CakePHP найти HABTM

У меня 3 модели (User, Message а также Tag) со следующими отношениями:

  • User имеет много Message
  • Message принадлежит User
  • Message HABTM Tag
  • Tag HABTM Message

Если пользователь вошел в систему, он может захотеть увидеть все Message помечен чем-то.

$messages = $this->Message->find('all', array(
    'conditions' => array("Message.user_id" => $this->uid),
    'contain' => array(
        'Tag' => array(
            'conditions' => array(
                'Tag.id' => $activetag['Tag']['id']
            )
         )
    ));

Однако эта находка вернет ВСЕ сообщения этого пользователя. (Контейнерное поведение включено в обе модели)

2 ответа

Содержимое на дочернем элементе (тег) не выполняет фильтрацию на родительском элементе (сообщение), поэтому все сообщения возвращаются. Содержимое только помещает условие на сам тег, в вашем случае сообщения, не соответствующие $activeTag, будут по-прежнему возвращаться, но с прикрепленным пустым массивом тегов, в то время как сопоставление сообщений будет возвращаться с массивом, содержащим только один тег, $activeTag, но все сообщения вернется.

Для вашей цели CakepHP рекомендует использовать функцию соединения для фильтрации с HABTM, он автоматически присоединяет вас к hasOne или ownTo, но когда дело доходит до HABTM, вам может понадобиться выполнить соединение самостоятельно, если это необходимо.

при условии, что таблицы названы условно:

$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);

дополнительная информация здесь: http://book.cakephp.org/2.0/en/models/associations-linking-models-together.html

В вашем модельном сообщении добавьте

**
 * @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',
        ),
    );

в вашем контроллере:

// $tagsId = tags ids
    $message = $this->MessageTag->find('all', array('conditions' => array('MessageTag.tag_id' => $tagsId),'contain' => array('Message')));

также лучше следовать соглашению об именах тортов, если у вас есть теги (множественное число), message_tags(первое единственное число, второе множественное число), таблицы сообщений (множественное число), у вас должны быть Tag,MessageTag,Message Models.

Другие вопросы по тегам