Akelos Framework v1 forum archive. This forum is no longer maintained. To report bugs please visit https://github.com/akelos/akelos/issues
    • CommentAuthorThijs
     

    Great to see a framework that translates the Rails philosophy to PHP! Cause I don’t speak Ruby and I have 1 big project that definitely could use some redesign from the ground up.

    It's a system that takes the energy meter readings of households which are organised into different neighbourhoods and calculates their savings. It's a Belgian campaign, but now they're going european and need the same thing, but for 9 countries in 8 languages.

    The current code (in one locale) is getting out of hand. The business logic, validation and different user permissions are everywhere. Bugs keep popping up. It's time for an MVC makeover, in Akelos hopefully.. And if that doesn't work out I have to learn Rails.. (well, the deadline is still two months away. It might work.)

    Okay, I just got started, and here's what I'm trying to do:

    There are different 'neighbourhoods' and 'users'. Every neighbourhood has different users, and every user can be member of different neighbourhoods. So the models look like this:

    class Neighbourhood extends ActiveRecord
    {
        var $has_and_belongs_to_many = 'users';
    }
    
    class User extends ActiveRecord
    {
        var $has_and_belongs_to_many = 'neighbourhoods';
    }
    

    and then there’s the automatically generated:

    class NeighbourhoodUser extends ActiveRecord {
        var $_avoidTableNameValidation = true;
        function NeighbourhoodUser()
        {
            $this->setModelName("NeighbourhoodUser");
            $attributes = (array)func_get_args();
            $this->setTableName('neighbourhoods_users', true, true);
            $this->init($attributes);
        }
    }
    

    I've got that working with some scaffolded pages. I can add and edit users and neighbourhoods. And even managed to edit Users which are member of a certain Neighbourhood on a 'user in neighbourhood' page using an extra 'route' (and view and controller method):

    -- in routes --
    $Map->connect('/neighbourhood/:id/user/:userid', array(
    'controller' => 'neighbourhood',
    'action' => 'edit_user'
    ));
    
    -- in neighbourhood_controller --
    function edit_user()
    {
        $this->Neighbourhood->user->load();
    
        if(!empty($this->params['user']) && !empty($this->params['userid'])){
            if($this->Request->isPost() && $this->user->update($this->params['userid'],$this->params['user'])){
                $this->flash['notice'] = $this->t('User was successfully updated.');
                $this->redirectTo(array('action' => 'show', 'id' => $this->Neighbourhood->getId()));
            }
        }   
    }
    
    -- for every column in the view: edit_user.tpl --
    <p>
        <label for="user_first_name">_{First name}</label><br />
        <?=$form_tag_helper->text_field_tag('user[first_name]',$Neighbourhood->users[$userid]->get('first_name'),array("class" => "input_user"))?>
    </p>
    

    .. well. I've got it more are less working. I seem to be getting extra records in the Users tabel for every user I tried to update this was.. But that's probably a bit of code tweaking.

    But now: here's the problem I'm facing: There are more columns in the neighbourhoods_users table then the mandatory foreign keys. And I need to be able to access and update them on the 'user in neighbourhood' view. Here's an abstract from the installer:

    $this->createTable('neighbourhoods_users',
    'id,
     neighbourhood_id,
     user_id,
     is_enabled bool default 1,
     year smallint(6),
     code,
     measures_taken,
     housetype bool default 1,
     insulation bool default 1,
     .. etcetera..
     ');
    

    Is that possible in an habtm association? I was looking in the Rails api pages for an answer, and found this under the 'Cardinality and associations' > 'Many-to-many' header:

    Choosing which way to build a many-to-many relationship is not always simple. If you need to work with the relationship model as its own entity, use has_many :through. Use has_and_belongs_to_many when working with legacy schemas or when you never work directly with the relationship itself.

    But is it possible to use 'through' when defining a 'has many' association in Akelos?

    Thanks in advance for any help.

    • CommentAuthorKaste
     

    we don't have has_many :through, so you have do to this manually.

    users has_many: neighbourhoods_users. // neighbourhoods_user belongs_to (a): neighbourhood. (and vice-versa)

    Since neighbourhoods_users is a rich model, I would suggest renaming the model to something more appropriate.

    • CommentAuthorThijs
     

    okay, thanks. Doing some searches manually will also give me more control over them (I noticed direct SQL queries are possible, will need them)

    But.. I'm stuck again: How do I search the details of each user which is a member of a neighbourhood? And where do I search: in the controller (preferably I suppose) or in the view?

    This is the situation:

    class Hood extends ActiveRecord
    {
        var $has_many = 'hoodmemberships';
    }
    
    class Hoodmembership extends ActiveRecord
    {
        var $belongs_to = array('user','hood');
    }
    
    class User extends ActiveRecord
    {
        var $has_many = 'hoodmemberships';
        var $belongs_to = 'hood';  // this is because some users also administer a neighbourhood, add other users etc...
    }
    

    I can show the ID's of the different users which are member of a hood in view/hood/show.tpl

    {loop hood.hoodmemberships}
        {hoodmembership.user_id}<br />
    {end}
    

    But how do I show the details of the users? I’ve tried to put the code below in that loop and the right SQL query showed up in the log. But I don't know how to access the values of the found columns.

    <?php $User->find($hoodmembership->user_id);
       echo $User->first_name;
    ?>
    

    In the hood controller I have one of these: (both have the same result, but the generated SQL query is more detailed with the second)

    $this->hood->hoodmembership->load();
    $this->hood = $this->hood->find(@$this->params['id'], array('include' => 'hoodmembership'));
    

    Is it possible to do a find in the controller that will also generate the associated objects for the users?

    Which I could then show in the view using, f.i. :

    {hood.hoodmembership-0.first_name}
    

    or something similar?

    • CommentAuthorKaste
     

    so you have : Hood -> Hoodmemberships -> User

    now you can load the user for each Hoodmembership via Hoodmembership->user->load();

    class Hood ...
    
    function loadUserForEachHoodmembership()
    {
        foreach ($this->hoodmemberships as &$Hoodmembership){
            $Hoodmembership->user->load();
        }
    }
    

    and maybe a convenient finder

    class Hood ...
    
    function findHoodWithHoodmembershipsAndBelongingUsers(id)
    {
        $Hood = $this->find(id,array('include'=>'Hoodmemebership'));
        $Hood->loadUserForE....();
        return $Hood;
    }
    

    something like this.

    • CommentAuthorKaste
     

    class User extends ActiveRecord { var $has_many = 'hoodmemberships'; var $belongs_to = 'hood'; // this is because some users also administer a neighbourhood, add other users >etc... }

    this sounds like User administers a(one?) Hood. And a Hood is 'administered' by a User.

    -> (a) User has_one Hood AND (a) Hood belongs_to (one) User
    

    Or: Each Hood must have a supervisor, but not each User is actually a supervisor for a Hood.

    • CommentAuthorThijs
     

    Excellent! Works great, thanks.

    Now I can access them in the view using, f.i. :

    {loop hood.hoodmemberships}
       {hoodmembership.user.first_name} {hoodmembership.user.last_name}<br />
    {end}
    

    this sounds like User administers a(one?) Hood. And a Hood is 'administered' by a User.

    Well, it's a bit more complicated: every hood must have 1 supervisor, but can have up to three. Plus an optional 4th supervisor at a higher level. And each of those supervisors can have several Hoods (and also have a Hoodmembership in one)

    So I better stick to the User belongs_to Hood.