Let’s say you have a User model, and you want to paginate the Friends of a certain User. Your table definition looks like:
create table users (
id int(11) not null auto_increment,
username varchar(32) not null,
primary key (id)
);
create table users_friends (
id int(11) not null auto_increment,
user_id int(11) not null,
friend_id int(11) not null,
primary key (id)
);
We can then add some test data to the tables:
insert into users (id, username) values (1, 'kevin');
insert into users (id, username) values (2, 'stephanie');
insert into users (id, username) values (3, 'michael');
insert into users (id, username) values (4, 'jennifer');
insert into users_friends (user_id, friend_id) values (1, 2);
insert into users_friends (user_id, friend_id) values (1, 3);
insert into users_friends (user_id, friend_id) values (2, 1);
insert into users_friends (user_id, friend_id) values (2, 4);
insert into users_friends (user_id, friend_id) values (3, 1);
insert into users_friends (user_id, friend_id) values (3, 4);
insert into users_friends (user_id, friend_id) values (4, 2);
insert into users_friends (user_id, friend_id) values (4, 3);
And make a self-referential join in your User model:
class User extends AppModel {
var $name = 'User';
var $hasAndBelongsToMany = array(
'Friend' => array(
'className' => 'User',
'joinTable' => 'users_friends',
'foreignKey' => 'user_id',
'associationForeignKey' => 'friend_id',
'unique' => true,
)
);
}
Now we want to paginate all friends in the user “kevin”. By following the tutorial "Quick Tip - Doing Ad-hoc Joins in Model::find()", we’ll create a controller:
// app/controllers/friends_controller.php
class FriendsController extends AppController {
function index() {
$this->paginate = array(
'Friend' => array(
'limit' => 2,
'joins' => array(
array(
'table' => 'users_friends',
'alias' => 'UsersFriend',
'type' => 'inner',
'conditions'=> array(
'UsersFriend.friend_id = Friend.id',
),
),
array(
'table' => 'users',
'alias' => 'User',
'type' => 'inner',
'conditions'=> array(
'User.id = UsersFriend.user_id',
'User.id' => 1
)
)
)
)
);
$data = $this->paginate('Friend');
debug($data);
exit;
}
}
The debug output should now look like:
Array
(
[0] => Array
(
[Friend] => Array
(
[id] => 2
[username] => stephanie
[0] => Array
(
[id] => 1
[username] => kevin
[UsersFriend] => Array
(
[id] => 3
[user_id] => 2
[friend_id] => 1
)
)
[1] => Array
(
[id] => 4
[username] => jennifer
[UsersFriend] => Array
(
[id] => 4
[user_id] => 2
[friend_id] => 4
)
)
)
)
[1] => Array
(
[Friend] => Array
(
[id] => 3
[username] => michael
[0] => Array
(
[id] => 1
[username] => kevin
[UsersFriend] => Array
(
[id] => 5
[user_id] => 3
[friend_id] => 1
)
)
[1] => Array
(
[id] => 4
[username] => jennifer
[UsersFriend] => Array
(
[id] => 6
[user_id] => 3
[friend_id] => 4
)
)
)
)
)
Hi Kyo,
ReplyDeleteDo you have a friends table on this? Or is the friend taken from the user table?
Thanks
@Nu Order Webs
ReplyDeleteNo, there's no need to create a friend table. You only need 2 tables, users and users_friends. It's retrieving data as Friend from the users table.
Hi,
ReplyDeleteThanks a lot for the example.
How would you structure it so that you would not just get the User's friends, but also the people to whom the User is a friend. With your data set, this is irrelevant, because all relationships are reciprocal.
More importantly, how would you structure it so that you would get back only a list of people to whom the user is a friend?
I have been playing around with the joins and haven't figured it out yet.
Thanks a lot for your helpful tutorial.
Josh
My question is similar to Josh's. How do you find your User's friend's content? i.e. How can I see all the posts that my friends have posted?
ReplyDeleteGreat tutorial!
thanks man for this ....
ReplyDeletegod bless you
I know this is an old article but have the same question as the others. This association seems to go one way. Meaning, there's no readily apparent way to see who had you as a friend. Ideally, this relationship could be completely reciprocal; meaning if Tom is friends with Sue, Sue should be friend with Tom.
ReplyDelete