Как я могу найти все записи для модели, не выполняя длинный список условий «ИЛИ»? - PullRequest
4 голосов
/ 08 марта 2010

У меня проблемы с составлением CakePHP find (), которая возвращает записи, которые я ищу.

Мои ассоциации выглядят так:

Пользователь -> (имеет много) -> Друзья,
Пользователь -> (имеет много) -> Сообщений

Я пытаюсь отобразить список всех недавних постов друзей пользователя, другими словами, перечислять все посты, созданные другом текущего пользователя, вошедшего в систему.

Единственный способ, которым я могу думать об этом, - это поместить user_ids всех друзей пользователя в большой массив, а затем перебрать каждый из них так, чтобы вызов 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
                    )
                )           
            )
        ));

У меня сложилось впечатление, что это не лучший способ сделать что-то, как если бы этот пользователь пользовался популярностью, а это много условий ИЛИ. Кто-нибудь может предложить лучшую альтернативу?

Для пояснения, вот упрощенная версия моей базы данных:

Таблица «Пользователи»
ID
Имя пользователя
и т. д.

Стол «Друзья»
ID
user_id
friend_id
и т. д.

Таблица «Посты»
ID
user_id
и т. д.

Ответы [ 5 ]

2 голосов
/ 08 марта 2010

После просмотра того, что вы переписали, я думаю, что понимаю, что вы делаете. Ваша текущая структура не будет работать. Там нет ссылки в постах на друзей. Поэтому, основываясь на опубликованной вами схеме, друзья НЕ МОГУТ добавлять какие-либо посты. Я думаю, что вы пытаетесь сделать ссылку на друга как одного из других пользователей. Это означает, что FRIEND пользователей - это просто еще один пользователь USER в таблице USERS. Это самореферентные отношения HABTM. Итак, вот что я хотел бы предложить:

1- Сначала убедитесь, что в базе данных создана таблица HABTM:

- MySQL CREATE TABLE users_users (user_id char (36) NOT NULL,
friend_id char (36) NOT NULL);

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

http://test/users/get_user/USER_ID

6- Ваш вывод покажет все записи (рекурсивно), включая друзей и их сообщения в возвращенном дереве данных, когда вы pr ($ posts)

Я знаю, что это длинный пост, но я думаю, что он обеспечит лучшее решение для того, что вы пытаетесь сделать. Сила CakePHP невероятна. Это кривая обучения, которая убивает нас.

Счастливого кодирования!

0 голосов
/ 09 марта 2010

Если ваши модели правильно связаны, 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);
0 голосов
/ 09 марта 2010

Разве 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)",
));
0 голосов
/ 08 марта 2010

В зависимости от вашей настройки, может быть быстрее выполнить два запроса, чем пытаться связать их вместе с помощью Cake. Я бы порекомендовал добавить что-то вроде getFriendsPosts () в модель Users.

<?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') );

НТН, Travis

0 голосов
/ 08 марта 2010

Если 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) ..

...