Как я могу найти все записи для модели, не выполняя длинный список условий “ИЛИ”?
-
18-09-2019 - |
Вопрос
У меня возникли проблемы с составлением CakePHP find(), которая возвращает записи, которые я ищу.
Мои ассоциации выглядят примерно так:
Пользователь -> (имеет много)-> Друзья ,
Пользователь -> (имеет много)-> Сообщений
Я пытаюсь отобразить список всех недавних сообщений друзей пользователя, другими словами, перечислить каждое сообщение, созданное другом текущего пользователя, вошедшего в систему.
Единственный способ, который я могу придумать для этого, - поместить идентификаторы пользователей всех друзей пользователя в большой массив, а затем выполнить цикл по каждому из них, чтобы вызов find() выглядел примерно так:
$posts = $this->Post->find('all',array(
'conditions' => array(
'Post.user_id' => array(
'OR' => array(
$user_id_array[0],$user_id_array[1],$user_id_array[2] # .. etc
)
)
)
));
У меня складывается впечатление, что это не лучший способ делать что-то так, как будто этот пользователь популярен, для чего требуется множество условий OR.Кто-нибудь может предложить лучшую альтернативу?
Чтобы внести ясность, вот упрощенная версия моей базы данных:
Таблица "Пользователи"
ID
Имя пользователя
и т.д.
Таблица "Друзья"
ID
идентификатор пользователя
идентификатор друга
и т.д.
Таблица "Сообщения"
ID
идентификатор пользователя
и т.д.
Решение
Просмотрев то, что вы переписали, я думаю, что понимаю, что вы делаете.Ваша нынешняя структура не будет работать.В ПОСТАХ нет ссылок на друзей.Таким образом, основываясь на схеме, которую вы опубликовали, друзья НЕ МОГУТ добавлять какие-либо ПУБЛИКАЦИИ.Я думаю, что то, что вы пытаетесь сделать, это сослаться на друга как на одного из других пользователей.Это означает, что ДРУГ пользователя на самом деле является просто другим ПОЛЬЗОВАТЕЛЕМ в таблице USERS.Это самореферентное отношение HABTM.Итак, вот что я хотел бы предложить:
1- Во-первых, убедитесь, что у вас есть таблица HABTM, созданная в базе данных:
-- MySQL СОЗДАЕТ ТАБЛИЦУ
users_users
(user_id
символ (36) НЕ РАВЕН НУЛЮ,
friend_id
символ (36) НЕ РАВЕН НУЛЮ );
2- Установите взаимосвязи в пользовательской модели.
var $hasAndBelongsToMany = array( 'friend' => array('className' => 'User', 'joinTable' => 'users_users', 'foreignKey' => 'user_id', 'associationForeignKey' => 'friend_id', 'unique' => true, ), ); var $hasMany = array( 'Post' => array( 'className' => 'Post', 'foreignKey' => 'user_id' ), );
3- используйте строительные леса, чтобы вставить несколько записей, связать друзей и добавить публикации.4- Добавьте функцию просмотра записи в пользовательский контроллер:
function get_user($id) { $posts = $this->User->find('first', array( 'conditions' => array('User.id' => $id), 'recursive' => '2' )); pr($posts); }
5- Теперь вы можете запросить пользовательскую таблицу с помощью рекурсивного извлечения записей с помощью следующей команды:
6- Ваши выходные данные будут отображать все записи (рекурсивно), включая друзей и их публикации, в возвращаемом дереве данных при pr ($ posts)
Я знаю, что это длинный пост, но я думаю, что он обеспечит лучшее решение для того, что вы пытаетесь сделать.Мощь CakePHP невероятна.Это кривая обучения, которая убивает нас.
Счастливого Кодирования!
Другие советы
Если Post.user_id
указывает на Friend.id
(что не последовало бы за конвенция кстати) тогда это было бы
$posts = $this->Post->find('all',array(
'conditions' => array(
'Post.user_id' => $user_id_array
)
);
что привело бы к .. WHERE Post.user_id IN (1, 2, 3) ..
В зависимости от ваших настроек может оказаться быстрее выполнить два запроса, чем пытаться объединить их вместе с помощью Cake stuff.Я бы рекомендовал добавить что-то вроде getFriendsPosts() в модель пользователей.
<?php
class UserModel extends AppModel {
// ... stuff
function getFriendsPosts( $user_id )
{
$friends = $this->find( ... parameters to get user IDs of all friends );
// flatten the array or tweak your params so they fit the conditions parameter. Check out the Set class in CakePHP
$posts = $this->find( 'all', array( 'conditions' => array( 'User.id' => $friends ) ) );
return $posts;
}
}
?>
Затем, чтобы вызвать его, в контроллере просто выполните
$friends = $this->User->getFriendsPosts( $this->Auth->User('id') );
Привет, Трэвис
Разве CakePHP уже не генерирует эффективный код:
SELECT * from Posts WHERE user_id IN (id1, id2 ...)
если нет, вы можете сделать
$conditions='NULL';
foreach($user_id_array as $id) $conditions.=", $id";
$posts = $this->Posts->find('all', array(
'conditions' => "Post.user_id IN ($conditions)",
));
Если ваши модели правильно связаны, Cake автоматически извлекет связанные записи модели.Таким образом, когда вы выполняете поиск по конкретному пользователю, Cake автоматически извлекает связанных друзей и связанные публикации этих друзей.Все, что вам нужно сделать, это установить достаточно высокий уровень рекурсии.
$user = $this->User->find('first', array('conditions' => array('User.id' => $id), 'recursive' => 2));
debug($user);
// gives something like:
array(
User => array()
Friend => array(
0 => array(
...
Post => array()
),
1 => array(
...
Post => array()
)
)
)
Все, что вам нужно сделать, это извлечь сообщения из друзей пользователя, что так же просто, как:
$postsOfFriends = Set::extract('/Friend/Post/.', $user);