I have a simple friends system built in CakePHP with two tables: Users and Friends
Users
id,
username,
password
Friends
id
user_id
friend_id
status
To list the friends for a user I do the following:
$user = $this->User->find('first', array( 'conditions' => array('User.username' => $username)));
// First get a list of friend ids
$friendsList = $this->Friend->find('list',
array(
'conditions'=>array(
'Friend.user_id'=>$user['User']['id'],
'Friend.status'=>1
),
'fields'=>array(
'Friend.friend_id'
)
)
);
// Then list users with matching ids
$friends = $this->User->find('all',
array(
'conditions'=>array(
'User.id'=>$friendsList
),
)
);
Now this works fine for listing friends that the user has friended as it’s pulling the list of friend ids that the user id matches in the friends table. The problem is if a friend has friended the user then the ids will be reversed in the columns and therefore it wont show the friendship when viewing one user but will the other… If that makes sense?
How do I fix this? I basically need to find all matching ids in both columns for the user and then pull out the friend id or user id that matches the row.
I’ve posted the models as well (although I don’t think they really matter for this question as the issue is with the query rather than the relationships which are working).
User Model:
public $hasAndBelongsToMany = array(
'User'=>array(
'className' => 'User',
'joinTable' => 'friends',
'with' => 'Friend',
'foreignKey' => 'user_id',
'associationForeignKey' => 'friend_id'
)
);
Friend model is virtualised!
Thanks
EDIT: Doing this fixes the problem:
// First get a list of friend ids
$friendsList1 = $this->Friend->find('list',
array(
'conditions'=>array(
'Friend.user_id'=>$user['User']['id'],
'Friend.status'=>1
),
'fields'=>array(
'Friend.friend_id'
)
)
);
$friendsList2 = $this->Friend->find('list',
array(
'conditions'=>array(
'Friend.friend_id'=>$user['User']['id'],
'Friend.status'=>1
),
'fields'=>array(
'Friend.user_id'
)
)
);
$friendsList = array_merge($friendsList1,$friendsList2);
// Then list users with matching ids
$friends = $this->User->find('all',
array(
'conditions'=>array(
'User.id'=>$friendsList
),
)
);
But the performance could be rather poor if I have a large DB of users I presume.
I think you want this to be a recursive table so that the model works correctly.
You essentially want User to habtm User. So your model should look more like this.
Then you can query the User model and get all the relations as they should be. like so:
Or if your original model works: