0

I'm trying to use Containable in CakePHP with a rather odd scenario.

  • Group hasAndBelongsToMany User
  • Group belongsTo User
  • User hasAndBelongsToMany Group

I'm uncertain, but either I've got something wrong in my query, or I'm thinking that perhaps Containable is having a difficult time automagically determining which "User" I'm attempting to refer to in my conditions. (A department has a Department Head, thus the Group belongsTo User. A department also HABTM employees, and vice versa, thus the two HABTM links.)

From the user controller (for the view), I'm trying to get the departments (groups), and ONLY the departments, that the user belongs to.

In the User Model:

public function findDepartments($id) {
    $user = $this->find('first', array(
        'conditions' => array(
            'User.id' => $id
        ),
        'contain' => array(
            'Group.logical_group = 0',
            'Group' => array(
                'User' => array('fields' => array(
                    'id',
                    'firstName',
                    'lastName',
                    'ext'
                ))
            )
        )
    ));
    return $user;
}

This gives me an array of data with all of the information that I need. However, since I want to keep the controller skinny and the model fat, I want to eliminate the returned values that I'm getting - wherein the user is returned in the data.

Data returned:

Array
(
    [User] => Array
        (
            [id] => 46
            [username] => ytruly
            [firstName] => Yours
            [nickname] => 
            [lastName] => Truly
            [active] => 1
            [created] => 2009-10-06 19:10:13
            [lastlogin] => 2013-10-03 12:47:52
            [deactivated] => 
            [name] => Truly, Yours
        )
    [Group] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [name] => Administration
                    [parent_id] => 
                    [logical_group] => 
                    [user_id] => 70
                    [GroupsUser] => Array
                        (
                            [id] => 225
                            [group_id] => 1
                            [user_id] => 46
                        )
                    [User] => Array
                        (
                            [id] => 70
                            [firstName] => Head
                            [lastName] => Honcho
                            [ext] => 201
                        )

                )
            [1] => Array
                (
                    [id] => 2
                    [name] => Computer Services
                    [parent_id] => 1
                    [logical_group] => 
                    [user_id] => 182
                    [GroupsUser] => Array
                        (
                            [id] => 226
                            [group_id] => 2
                            [user_id] => 46
                        )

                    [User] => Array
                        (
                            [id] => 182
                            [firstName] => Boss
                            [lastName] => Man
                            [ext] => 202
                        )
                )
        )
)

I've tried accessing a similarly named method in the Groups model, but without any luck:

 public function findDepartments($user_id){
        $groups = $this->find('all', array(
            'conditions' => array(
                'Group.logical_group = 0'
            ),
            'contain' => array('User.id = ' . $user_id)
        ));
        return $groups;
    }

This will remove the User array from the returned data, but it is returning every single department (group) whether the join table (groups_users) has a match or not, and simply returns an empty user array along with the data it's returning.

I know I can simply use this data from my User model's method and use the Set class to remove what I don't want, but that's rather inefficient. There's got to be a way to get the Group model to properly query what I'm looking for, right?

-- EDIT/UPDATE -- I have made some progress, but in doing so long some other benefits.

I am now calling findDepartment from the Group model:

public function findDepartments($user_id) {
    $this->recursive = -1;

    $options['joins'] = array(
        array(
            'table' => 'groups_users',
            'alias' => 'GroupsUser',
            'type'  => 'INNER',
            'conditions' => array(
                'Group.id = GroupsUser.group_id'                    
            )
        )
    );
    $options['conditions'] = array(
        'Group.logical_group = 0',
        'GroupsUser.user_id = '.$user_id
    );
    $depts = $this->find('all', $options);
    return $depts;
}

This gets me much closer to what I was looking to get in terms of data back:

Array
(
    [0] => Array
        (
            [Group] => Array
                (
                    [id] => 3
                    [name] => Adult Services
                    [parent_id] => 
                    [logical_group] => 
                    [user_id] => 38
                )
        )
    [1] => Array
        (
            [Group] => Array
                (
                    [id] => 9
                    [name] => Youth Services
                    [parent_id] => 
                    [logical_group] => 
                    [user_id] => 62
                )
        )
)

Unfortunately, I've lost the associated belongsTo User relationship here. I've tried adding a secondary LEFT join in the joins array to User, but it didn't seem to work. I'm not sure how Containable creates its joins for HABTM to create such a result...

BrendonKoz
  • 463
  • 1
  • 6
  • 18
  • Why does a Group belong to a User? Surely Group and User should both hasAndBelongsToMany of each other, as a user could be in multiple groups, and a group has have multiple users? – Martin Bean Oct 03 '13 at 17:35
  • This was described in the first paragraph after the bullet points. The "Group belongsTo User" relationship is due to each Group (Department) having a manager. There will only ever be one manager per group. However, each manager may still belong to multiple groups. I could have either set that setting in the groups_users table, or in the groups table. I chose to set it in the groups table as I felt it was more akin to Cake's conventions. I've gotten closer to the solution using Cake's $options['join'] syntax, but lost the ability to gather the manager of the group(s) in doing this. – BrendonKoz Oct 04 '13 at 19:59

0 Answers0