Комплексный возврат и объединение данных CakePHP - PullRequest
3 голосов
/ 04 сентября 2011

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

Получите все истории от людей, на которых я подписан, и отформатируйте их следующим образом:

[Username] has posted [StoryName] - View story

Получите все истории, которые пользователи, к которым я подключен, оставили комментарии к

[Username] has posted a comment on [StoryName] - View story

Я не уверен, как получить оба массива, отобразить их в желаемом формате, но упорядочить их по дате публикации (так же, как это делают люди вроде Facebook)

Как лучше всего это сделать?

Обратите внимание: ответ должен быть легко расширяемым. Я рассматриваю следующую модель WordPress и создаю таблицу сообщений с полем «Тип сообщения».

Ответы [ 4 ]

4 голосов
/ 10 сентября 2011

То, что вы пытаетесь сделать, в значительной степени встроено в CakePHP.Главное, чтобы ваши модели были правильно связаны.Как только это будет выполнено, Cake выполнит большую часть тяжелой работы за вас.

Для вашей ситуации используйте 3 связанные модели:

class Story extends AppModel{
    var $belongsTo = 'Author';
    var $hasMany = 'Comment';
}

class Author extends AppModel{
    var $hasMany = array( 'Story', 'Comment' );
    var $hasAndBelongsToMany = 'User';
}

class Comment extends AppModel{
    var $belongsTo = array( 'Author', 'Story' );
}

Настройте ваши столы в соответствии с Cakeконвенций.Затем небольшое волшебство CakePHP в вашем контроллере:

$this->Story->Author->bindModel( array( 'hasOne' => array( 'AuthorsUsers' ) ) );
$myAuthors = $this->Story->Author->find( 'list', array(
    'fields' => array( 'id' ),
    'conditions' => array( 'AuthorsUsers.user_id' => $userId ),
    'recursive' => false 
    ) );

$stories = $this->Story->find( 'all', array(
    'fields' => array( 'Story.id', 'Story.title', 'Author.id', 'Author.name' ),
    'order' => 'published_date DESC',
    'conditions' => array( 'Author.id' => $myAuthors ),
    'recursive' => 2
    ) );

Краткое объяснение происходящего:

  • bindModel() позволяет Cake знать, что вы хотитеиспользуйте ассоциацию HABTM для поиска авторов по связанному идентификатору пользователя.(Соглашение Cake заключается в том, что для присоединения к ассоциации Author-> User HABTM имеется таблица с именем «author_users».)
  • Если вы отладите переменную $myAuthors, вы увидите, что она получает простой массив идентификаторов.
  • 'conditions' => array( 'field' => array() ) будет обработан как "ГДЕ поле IN (...)".В этом примере мы получаем все модели WHERE 'Author.id' IN $myAuthors.
  • Короткий вызов $this->Story->find() - это красота Cake.Он автоматически найдет все модели Story, соответствующие указанным условиям, и , а также найдет другие модели, связанные с каждой найденной Story.(Вы можете запретить поиск связанных моделей, отключив Recursive или используя Containable поведение.)
  • Отладка переменной $stories покажет вам структуру, подобнуюследующее:
Array
(
    [0] => Array
        (
            [Story] => Array
                (
                    [id] => 1
                    [title] => 'Common Sense'
                    [published_date] => 1776-01-10 
                )
            [Author] => Array
                (
                    [id] => 1
                    [name] => 'Thomas Paine'
                )
            [Comment] => Array
                (
                    [0] => Array
                        (
                            [id] => 1
                            [text] => 'Revolutionary!'
                            [Author] => Array
                                (
                                    [id] => 3
                                    [name] => 'Silence Dogood'
                                )
                        )
                    [1...n] => ...
                )
        )
    [1...n] => ...
)

Затем вы можете использовать эту структуру в своем представлении для отображения данных по вашему желанию.

У меня такое чувство, что должен быть способ сделать это столько 1 запрос, но этот способ работает и не требует от вас выполнения каких-либо подзапросов или вставки пользовательского SQL в ваш вызов Cake find().

0 голосов
/ 09 сентября 2011

Ну, я бы сделал что-то вроде этого

Создайте следующие отношения

Пользователь hasMany StoryName

Пользователь hasMany Комментарии

StoryName hasMany Комментарии

Комментарии принадлежит Пользователь

Комментарии принадлежит StoryName

Таким способом было бы действительно легко получить всю необходимую информацию, поскольку вы могли бы извлечь все необходимые данные, хотя модель User и что-то вроде

$this->User->recursive = 2;

$this->User->find('all', $params) *// on $params you could use the conditions that the user retrieved should be friends to the current user*

Надеюсь, это даст мне массив, заполненный следующей структурой

[USER] [сообщения] [комментарии]

И нужно было просто передать его представлению и использовать foreach в представлении для создания HTML

.
0 голосов
/ 09 сентября 2011

Я не знаю, есть ли у вас уже настроенные другие модели (Пользователь, История и т. Д.).Но чтобы сохранить ответ на этот вопрос, я просто сосредоточусь на модели деятельности (таблица действий): Вы можете использовать эту таблицу как таблицу журнала.

Простая таблица: id, user_id, story_id, made (datetime), action_type (например, 0 для пост-истории, 1 для комментария к истории).Тогда нужно просто запросить эту таблицу, чтобы найти действия.

Или более общий, расширяемый: id, subject_id, subject_type (пользователь или что-либо еще действующее), verb_type, object_id, object_type, создан.На самом деле вам не нужно связывать эту модель с любой другой моделью (хотя вы можете использовать «условия», когда вы указываете отношения) или bindModel на лету.

0 голосов
/ 05 сентября 2011

Гэри, трудно ответить на это, не зная ваших моделей. Предполагая, что у вас есть правильно определенные схема и модели, это должно быть относительно просто.

Для ваших запросов поиска упорядочите по дате DESC и получите последние 10 строк. (это даст вам 20 последних результатов, например)

Объединить наборы результатов в один и снова отсортировать по дате DESC. Тогда это простая логика рендеринга для рендеринга строк так, как вам нужно.

...