I was following a tutorial about permissions instead CakePHP.
I don't understand how this model (query) works.
Can anybody explain me how this query works.. I can't find what this variable hasAndBelongsToMany exactly does.
<?php
class Group extends Appmodel {
var $name = 'Group';
var $useTable 'groups';
var $hasAndBelongsToMany = array(
'Permission' => array('className' => 'Permission',
'joinTable' => 'groups_permissions',
'foreignKey' => 'group_id',
'associationForeignKey' => 'permission_id',
'unique' => true
)
'User' => array('className' => 'User',
'joinTable' => 'groups_users',
'foreignKey' => 'group_id',
'associationForeignKey' => 'user_id',
'unique' => true
),
);
}
First of all it is not a query. it is a declaration of relation of the model to other models.
$hasAndBelongsToMany means that every record in your database is associated with many records of another table, and the many records from other table can be associated with the current record as well.
for example Book can have many authors, and an authors can have many books. so it can be related as hasAndBelongsToMany.
in your case Group has many users, and users have many groups. same for permissions.
Related
I have 2 Models that are joined but not thrue the id's but with another field.
class Post extends AppModel{
public $useDbConfig = 'test';
public $actsAs = array('Containable');
public $belongsTo= array(
'User' => array(
'className' => 'User',
'foreignKey' => false,
'type' => 'inner',
'conditions' => array('User.field = Post.field')
));
}
But the cakephp is not connecting the 2 models correctly. To every Post it just gives the the first user (User with id 1). When I check the SQL-Statements the User statement is following:
SELECT `User`.`id`, `User`.`group_id`... FROM `users` AS `User` WHERE 1 = 1
Any ideas why this is not working?
I also tried joining the models manually:
$this->paginate = array(
'limit' => '15',
'joins' => array(
'INNER JOIN users User ON (User.field = Post.field)'
)
);
$posts= $this->paginate('Post');
Any ideas?
EDIT
I totally forgot to mention that these 2 tables are in different databases. Maybe there is the problem. But I had no problem joining tables over different databases so far.
EDIT
I was wrong about the join so I changed it from "belongsTo" to "hasOne" since a post can only be written by one user. But still no changes.
You can use the foreignKey parameter to any field, not necessarily the id:
Post model:
public $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'some_user_field'
)
);
User model:
public $hasMany = array (
'Post' => array (
'className' => 'Post',
'foreignKey' => 'some_user_field',
'dependent' => true
)
);
According to the book:
It is not mandatory to follow CakePHP conventions. You can easily
override the use of any foreignKey in your associations definitions.
Nevertheless, sticking to conventions will make your code less
repetitive and easier to read and maintain.
Otherwise, make joins manually:
$this->paginate = array(
'limit' => '15',
'joins' => array(
array(
'table' => 'users',
'alias' => 'User',
'type' => 'inner',
'conditions' => array('User.field = Post.field')
)
)
);
I found a solution although I don't understand why the others won't work. I put
$this->Post->primaryKey = 'field';
right before
$posts= $this->paginate('Post');
and now it works. Can anyone tell me why the other ways won't work?
I want to delete all dependent rable record
My association
Branch Model
var $hasMany =array(
'Dealbranch' => array(
'className' => 'Dealbranch',
'foreignKey' => 'DLB_BR_ID',
'dependent' =>true
)
);
Dealbranch Model
var $belongsTo = array(
'Deal' => array(
'className' => 'Deal',
'foreignKey' => 'DL_ID',
'dependent' => true
),
'Branch' => array(
'className' => 'Branch',
'foreignKey' => 'DLB_BR_ID',
)
);
Deal Model
var $hasMany = array(
'Dealbranch' => array(
'className' => 'Dealbranch',
'foreignKey' => 'DLB_DL_ID',
)
);
In controller I have used
$this->Branch->delete($id,true);
Now here whem I am deleting branch , so dependent dealbranch deleted successfully but none of any deal record deleted
I want like : whem I am deleting branch , so all dependent dealbranch should be deleted and all dependent( depend on dealbranch) deal record should be deleted
here Deal is child of Dealbranch and Dealbranch is child of branch
Now, For one branch there are multiple record in Dealbranch, and for multiple Dealbranch there is one record in Deal
Please help me. I am using cakephp 2
All the model records that are associated with Branch can be deleted by using
$this->Branch->delete($id,true);
I think if you want to remove the deal records on deleting of branch records then your model Branch should be associated with Deal model.
Just try to add like this
Branch Model
var $hasMany =array(
'Dealbranch' => array(
'className' => 'Dealbranch',
'foreignKey' => 'DLB_BR_ID',
'dependent' =>true
),
'Deal' => array(
'className' => 'Deal',
'foreignKey' => 'your_foriegn_key',
'dependent' =>true
)
);
or you may try like this
Update:
According to your requirement here Deal is child of Dealbranch and Dealbranch is child of branch your model associations should be like this.
deal branch model should be like this.
DealBranch Model
var $belongsTo = array(
'Branch' => array(
'className' => 'Branch',
'foreignKey' => 'DLB_BR_ID',
)
);
var $hasMany = array(
'Deal' => array(
'className' => 'Deal',
'foreignKey' => 'DL_ID',
'dependent' => true
),
);
deal model should be like this.
Deal Model
var $belongsTo = array(
'Dealbranch' => array(
'className' => 'Dealbranch',
'foreignKey' => 'DLB_DL_ID',
)
);
While I know the people at cakephp do not use foreign keys in their databases and rely on the framework to take care of these details, in your case if the framework is giving you problems and you have control over the database update your foreign key constraints to CASCADE on DELETE DB operations.
The basic problem is in your data model. According to your model, any branch can be connected to zero or more deals and vice versa. Thus if you delete a branch, it does not make any sense to delete any deal, because the deal could be related to another branch. If the deal was deleted, the database integrity would be corrupted.
The setting you use is often used to model M:N relationship.1
The whole picture if your data model:
And what you really meant:
Branch model
var $hasMany =array(
'Deal' => array(
'className' => 'Deal',
'foreignKey' => <set_according_to_your_column_names>,
'dependent' =>true
)
);
Deal model
var $hasMany = array(
'Branch' => array(
'className' => 'Dealbranch',
'foreignKey' => <set_according_to_your_column_names>,
)
);
This way, you can in the controller call only:
$this->Branch->delete($id,true);
or even
$this->Branch->delete($id);
since the second parameter is true by default.
1 Example of M:N relationship is Person - Address. Anyone can use more than one address (e.g. home and work) and one address can be shared by more people (family, colleagues).
Consider the following HABTM relation in CakePHP 2.2.3:
class User extends AppModel
{
public $hasAndBelongsToMany = array(
'Role' => array(
'className' => 'Role',
'joinTable' => 'roles_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'role_id',
)
);
}
This works fine, but when using an alias like VeryUniqueAlias instead of Role and changing the UsersController accordingly, the m:n relation is not persisted in the database (the data passed to save() in the controller are equivalent).
This does not work:
class User extends AppModel
{
public $hasAndBelongsToMany = array(
'VeryUniqueAlias' => array(
'className' => 'Role',
'joinTable' => 'roles_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'role_id',
)
);
}
This is awkward, since the the CakePHP docs state that it should work.
Any idea why it's not working for me? Did I miss something?
Use the 'with' key to define the name of the model for the join table. In your case:
public $hasAndBelongsToMany = array(
'VeryUniqueAlias' => array(
'className' => 'Role',
'joinTable' => 'roles_users',
'with' => 'RolesUser', // first model pluralized
'foreignKey' => 'user_id',
'associationForeignKey' => 'role_id',
)
);
In my tennis application, my 'match' table has two players (obviously). I've used player1_id and player2_id as a way to track the user ids. I haven't included a user_id foreign key though.
There is also a 'user' table where I want to pull player's names from.
Because 'match' has more than one user and users have more than one model, I'm wondering if the following model configuration will work:
I've setup the user model like this:
var $name = 'User';
var $hasMany = array(
'Match' => array(
'className' => 'Match',
'foreignKey' => array( 'player1_id', 'player2_id'),
'dependent' => true,
)
and the match model like this:
var $name = 'Match';
var $belongsTo = array(
'User' => array(
'className' => 'User',
'foreignKey' => 'user_id',
'conditions' => '',
)
I need to display the user first/last name for each player where user_id = player1_id or player2_id. Will this work? Can a foreign key use an array? And can a model operation use an 'or' when searching?
Or is there a better way to structure a table (like a match, or could be a group meeting) with more than one user?
Cheers,
Paul
I don't think an array as a foreign key on the User > Match relationship would work, but then again I have never tried. The single Match > User relationship with user_id as the foreign won't work though, since, as you said, that foreign id does not exist.
Conceptually the cleanest way would be a proper hasAndBelongsToMany relationship. After all, a match has many players, and players have many matches. So you're really looking at a many-to-many relationship.
To fake it with a belongsTo/hasMany relationship, you would need to do this:
// user model
var $hasMany = array(
'MatchAsPlayer1' => array(
'className' => 'Match',
'foreignKey' => 'player1_id',
),
'MatchAsPlayer2' => array(
'className' => 'Match',
'foreignKey' => 'player2_id',
)
);
// match model
var $belongsTo = array(
'Player1' => array(
'className' => 'User',
'foreignKey' => 'player1_id'
),
'Player2' => array(
'className' => 'User',
'foreignKey' => 'player2_id'
)
);
The ugly part is in the User model, where you'd receive related matches split into ['MatchAsPlayer1'] and ['MatchAsPlayer2']. You could do some trickery in the afterFind callback to merge those, but it's not a nice solution overall. Just go for the hasAndBelongsToMany. :)
Is there a shortcut for creating Unary associations in Cake?
For example, a user is a friend of another user. I'm pretty sure it's going to violate cake's conventions if I try it the hard way and code the associations myself.
Cake has HABTM:
var $hasAndBelongsToMany = array(
'User' =>
array(
'className' => 'User',
'joinTable' => 'friends',
'foreignKey' => 'user_id',
'associationForeignKey' => 'friend_id',
'unique' => true
)
);
Will this work? A user model assoc to another user model.
Update:
How do I save the data now?
$this->data["Friend"] = $request["Requester"];
$this->data["Admirer"] = $request["Requestee"];
$this->Friend->create();
$this->Friend->save($this->data);
$request["Requester"] and $request["Requestee"] both hold objects of type User.
The HABTM rel is defined in the User model
var $hasAndBelongsToMany = array(
'Friend' => array(
'className' => 'Friend',
'joinTable' => 'friends',
'foreignKey' => 'user_id',
'associationForeignKey' => 'id'
),
'Admirer'=>array(
'className'=>'Friend',
'joinTable'=>'friends',
'foreignKey' => 'friend_id',
'associationForeignKey' => 'id',
)
);
All that happens is the $data->["Friend"]'s id is stored in the id column of the friends table
Here is a solution I use in an example application
Two tables are needed, users and followers. The important fields are User->id, Follower->user_id, Follower->friend_id.
I hope this snippet helps.
<?php
class User extends AppModel {
public $useTable='users';
public $hasAndBelongsToMany=array(
'Friend'=>array(
'className'=>'User',
'joinTable'=>'followers',
'foreignKey' => 'user_id',
'associationForeignKey' => 'friend_id',
),
'Admirer'=>array(
'className'=>'User',
'joinTable'=>'followers',
'associationForeignKey' => 'friend_id',
'foreignKey' => 'user_id',
),
);
}
-teh
Bjorn,
he is asking about User habtm User...
your join table should be users_users and the relation should look like this
var $hasAndBelongsToMany = array(
'Friend' =>
array(
'className' => 'UserUser',
'joinTable' => 'users_users',
'foreignKey' => 'user_id',
'associationForeignKey' => 'friend_id',
'unique' => true
)
);
i think that should do the trick
In CakePHP there are several variables in your model available to do that, like $hasMany, $belongsTo and $hasAndBelongsToMany. Please read the Cookbook for further explaination.. http://book.cakephp.org/view/78/Associations-Linking-Models-Together .
In your example, I think you need HABTM.