问题
I have 3 models (User
, Message
and Tag
) with the following relations:
User
hasManyMessage
Message
belongstoUser
Message
HABTMTag
Tag
HABTMMessage
If a User is logged in he might want to see all Message
tagged with something.
$messages = $this->Message->find('all', array(
'conditions' => array("Message.user_id" => $this->uid),
'contain' => array(
'Tag' => array(
'conditions' => array(
'Tag.id' => $activetag['Tag']['id']
)
)
));
However, this find will return ALL messages of that user. (Containable behaviour is included in both models)
回答1:
Containable on child (tag) does not perform filter on the parent (message), that's why all the messages are returned. The containable only place condition on the tag itself, in your case, messages not matching $activeTag would still get returned but with empty tag array attached, while messages matching would return with an array containing only one tag, the $activeTag, but all messages would get returned.
For your purpose CakepHP recommend using join function for filtering with HABTM, it joins hasOne or belongsTo for you automatically but when it comes to HABTM you may need to perform the join yourself if needed.
assuming tables are named conventionally:
$this->Message->recursive = -1;
$options['joins'] = array(
array('table' => 'messages_tags',
'alias' => 'MessageTag',
'type' => 'INNER',
'conditions' => array(
'Message.id = MessageTag.message_id',
)
) );
$options['conditions'] = array(
'MessageTag.tag_id' => $activetag['Tag']['id'],
'Message.user_id' => $this->uid );
$message = $this->Message->find('all', $options);
more info here: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html#joining-tables
回答2:
In your Model Message add
**
* @see Model::$actsAs
*/
public $actsAs = array(
'Containable',
);
/**
* @see Model::$belongsTo
*/
public $belongsTo = array(
'Message' => array(
'className' => 'Message',
'foreignKey' => 'message_id',
),
'Tags' => array(
'className' => 'Tag',
'foreignKey' => 'tag_id',
),
);
in your controller :
// $tagsId = tags ids
$message = $this->MessageTag->find('all', array('conditions' => array('MessageTag.tag_id' => $tagsId),'contain' => array('Message')));
also is better follow cake naming convention, if you have tags(plural), message_tags(first singular second plural),messages(plural) tables you must have Tag,MessageTag,Message Models.
来源:https://stackoverflow.com/questions/14946311/cakephp-find-habtm