Cameron
Cameron

Reputation: 28783

Multiple relations to one table in CakePHP

In my app a user can be friends with another user. So they have a many to many relationship between two tables. In this fashion: Users > Friends < Users

The tables look like:

Users:
id
username
password

Friends:
id
user_id_from
user_id_to

and I have set the Models up like so:

class User extends AppModel
{
    public $name = 'User';

    public $hasOne = 'Profile';

    public $hasMany = array(
        'Post',
        'Answer',
    'Friend'
    );

    public $actsAs = array('Containable');
}

class Friend extends AppModel
{
    var $name = 'Friend';

    var $belongsTo = array(
        'Sender' => array(
            'className' => 'User',
            'foreignKey' => 'user_id_from'
        ),
        'Recipient' => array(
            'className' => 'User',
            'foreignKey' => 'user_id_to'
        )
    );

    public $actsAs = array('Containable');
}

However it doesn't seem to link them properly?

I use this code inside the User Model:

public function getFriends($username)
    {
        return $this->find('all', array('conditions' => array('User.username' => $username, 'Friend.status'=>1)

        ));
    }

and then when visiting a url like /users/USERNAME/friends it should list the friends for that person. The method that calls it is:

public function index( $username )
{   
    $friends = $this->User->getFriends($username);

    $this->set('friends', $this->paginate());
}

What's the problem?

Upvotes: 1

Views: 1941

Answers (1)

jeremyharris
jeremyharris

Reputation: 7882

For a friend relationship, you should use HABTM instead of hasMany.

class User extends AppModel
{
    public $name = 'User';

    public $hasOne = 'Profile';

    public $hasMany = array(
        'Post',
        'Answer',
    );

    public $hasAndBelongsToMany = array(
      'Friend' => array(
        'className' => 'User',
        'joinTable' => 'friends',
        'foreignKey' => 'user_id_to',
        'associationForeignKey' => 'user_id_from',
      )
    );

    public $actsAs = array('Containable');
}

Remove your current Friend model as it is not needed and will possibly confuse Cake.

Your getFriends() method will look like this:

public function getFriends($username) {
   return $this->find('all', array(
     'conditions' => array(
       'User.username' => $username, 
       'User.status'=>1
      ),
      'contain' => array(
        'Friend'
      )
   ));
}

Here, we search on the User model and include all that user's Friend records. Cake will automatically get the join table data and include the User data. $this->User->getFriends('Jeremy'); will return data that looks like this:

Array
(
    [User] => Array
        (
            [id] => 1
            [username] => Jeremy
        )
    [Friend] => Array
        (
           [0] => Array
                (
                    [id] => 2
                    [username] => Cameron
                )
           [1] => Array
                (
                    [id] => 3
                    [name] => Mark
                )
           [2] => Array
                (
                    [id] => 4
                    [name] => Bob
                )
        )
)

Each Friend key here is actually a User model result.

You can read more about HABTM here: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#hasandbelongstomany-habtm

Upvotes: 2

Related Questions