Как я могу найти все записи для модели, не выполняя длинный список условий “ИЛИ”?

StackOverflow https://stackoverflow.com/questions/2402059

Вопрос

У меня возникли проблемы с составлением 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- Теперь вы можете запросить пользовательскую таблицу с помощью рекурсивного извлечения записей с помощью следующей команды:

http://test/users/get_user/USER_ID

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);
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top