There are a few ways to implement a friendship association, because there are two directions in a friendship. You can say that user A is friends with user B, but also user B is friend with user A.
When a person creates a friendship in the database. You'll have to create two records in the join table to represent this friendship in both directions (assuming you want a dual direction).
That covers the concepts of direction.
You may be experiencing problems with records disappearing, because CakePHP by default will erase all join data rows for a record when it's updated. Take a look at the description for the 'unique' option on a HABTM.
unique: If true (default value) cake will first delete existing relationship records in the foreign keys table before inserting new ones, when updating a record. So existing associations need to be passed again when updating.
That means that you always have to include the HABTM data when updating the record. Otherwise those records will be erased, and updated with what was passed.
Now the most basic friendship setup you can create would involve two tables.
CREATE TABLE `users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`name` varchar(45) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
CREATE TABLE `users_users` (
`id` int(10) unsigned NOT NULL AUTO_INCREMENT,
`user_id` int(10) unsigned NOT NULL,
`friend_id` int(10) unsigned NOT NULL,
PRIMARY KEY (`id`),
KEY `user` (`user_id`),
KEY `friend` (`friend_id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
The first table 'users' will hold our user data, and the second 'users_users' is the HABTM join table. Note the name, that it's users_users because it's joining itself.
You will still need to create two models in CakePHP.
The first is the User.php which will describe a user in the system. We'll be using mostly the defaults in CakePHP to get this to work. So the HABTM is just one line 'Friend'.
class User extends AppModel
{
var $name = 'User';
var $hasAndBelongsToMany = array(
'Friend'
);
}
Now, CakePHP will complain that the table users_friends is missing. We need to create a Friend model, but point it at the users table instead.
class Friend extends AppModel
{
var $name = 'Friend';
var $useTable = 'users';
}
Now CakePHP will use users_users table as the join. The Friend model now describes a user who is a friend.
It's important to understand that you will have to create the friends in both directions. When you save data for user A says he/she is friends with user B, then you will also have to save user B and say he/she is friends with user A. Otherwise, only one user will have the friendship defined.
There is another answer here that defines the dual direction of the friendship using aliases, but I recommend not implementing that as it adds extra SQL query work for CakePHP that might not be needed by your application. When you read records for User A, then you only need to know who their friends are, but no the other way around.
You could create a Behavior that ensures the friendship go both ways when user records are updated. That would be more efficient.
NOTE: My code example is for CakePHP 1.3 which is what I'm currently using, but it should work in 2.x just fine.
$log = $this->User->getDataSource()->getLog(false, false); debug($log)to get the output - AngeloS$this->recursive = 0in your model before the actual Save call? If you are calling save from the controller, it will be$this->User->recursive=0before calling the save method. I will try to setup a test scenario tomorrow on my system if that does not work. --Cheers - abhi.gupta200297