Как мне найти категории в содержании модели в CakePHP - PullRequest
4 голосов
/ 29 ноября 2010

У меня недавно возник вопрос по поводу Поиск записей по условиям в habtm .Теперь я могу искать сообщения в категории, которую искал.

Теперь у меня вопрос, как мне получить категории каждого сообщения.Иногда сообщение имеет одну или несколько категорий в этом запросе:

$this->set('posts', $this->Category->find(
    'first',
    array(
        'conditions' => array(
            'Category.uri' => $uri
        ),
        'contain' => array('Post')
    )
));

Я мог бы представить что-то вроде этого:

$this->set('posts', $this->Category->find(
    'first',
    array(
        'conditions' => array(
            'Category.uri' => $uri
        ),
        'contain' => array('Post' => array(
            'contain' => 'Category'
        ))
    )
));

Вот как выглядят мои модели.

// Category Model
class Category extends AppModel {
    var $name = 'Category';
    var $hasAndBelongsToMany = array(
        'Post' => array(
            'className' => 'Post'
        )
    );
    var $actsAs = array('Containable');
}

// Post Model
    class Post extends AppModel {
        var $name = 'Post';
        var $hasAndBelongsToMany = array(
            'Category' => array(
                'className' => 'Category'
            )
        );
        var $actsAs = array('Containable');
        var $virtualFields = array(
            'date_posted' => 'DATE_SUB(Post.created, INTERVAL 7 DAY)'
        );
    }

Пример данных будет выглядеть следующим образом:

categories
id name
1  holidays
2  destinations

posts
id title
1  I am a post
2  I am another post

categories_posts
post_id category_id
1       1
2       2
2       1

Я получаю сообщения из праздников.

Array
(
    [Category] => Array
        (
            [id] => 3
            [name] => holidays
            [uri] => holidays
            [created] => 2010-11-25 20:43:03
            [modified] => 2010-11-25 20:43:03
        )

    [Post] => Array
        (
            [0] => Array
                (
                    [id] => 1
                    [title] => I am a post
                ),
            [1] => Array
                (
                    [id] => 2
                    [title] => I am a another post
                )
        )
)

Проблема состоит в том, что 1 из сообщений относится к двум категориям.Я хотел бы, чтобы эта информация также была доступна.

Ответы [ 3 ]

3 голосов
/ 29 ноября 2010

Закрыть.Попробуйте это:

$this->set('posts', $this->Category->find(
    'first',
    array(
        'conditions' => array(
            'Category.uri' => $uri
        ),
        'contain' => array('Post' => array('Category'))
    )
));

Касательная

При написании кода контроллера, подобного этому, возникают проблемы:

  1. Это раздувает ваши методы контроллера и сделает ваши контроллеры менее читаемыми.1009 *
  2. Он не позволяет вам повторно использовать бизнес-логику между различными контроллерами.

Вы можете удовлетворительно исправить эти проблемы, переместив вызов поиска в метод модели:

// Categories Controller
$this->set('posts', $this->Category->get_posts_with_cats($uri));

// Category Model
function get_posts_with_cats($uri) {
    $this->find('first', array(
        'conditions' => array('Category.uri' => $uri),
        'contain' => array('Post' => array('Category'))
    ));
}

Это делает ваш код Подробнее Awesome :

  1. Контроллер хорош и Тощий , и супер читабелен.
  2. Теперь выМожно вызвать тот же метод из любой связанной модели.Так, например, в вашем PostsController вы можете позвонить: $this->Post->Category->get_posts_with_cats($uri);.Ваш код теперь DRY .

Tangent # 2

После того, как вы научитесь вкладывать вмещаемые модели, как я вам показал, вы можете испытать искушение вбудущее, чтобы сделать что-то вроде этого:

$this->find('first', array(
        'conditions' => array('Category.uri' => $uri),
        'contain' => array(
            'Post' => array(
                'Category' => array(
                    'Tag' => array('Author')
                )
            )
        )
    ));

Хорошая новость? Вы получите требуемые данные модели из вышеуказанного метода (если вы определили все эти отношения).

Ужасные новости? CakePHP не знает, как оптимизировать запросы для глубоких ассоциаций, подобных этой.Таким образом, по мере роста вашей базы данных вы получите десятки (если не сотни (если не тысячи)) SELECT запросов к базе данных, что приведет к полному обходу приложения (если не останов * 1046).*.)

Хорошие люди, которые проектируют CakePHP, работают над улучшением сдерживаемого поведения для CakePHP 2.0, но вам придется подождать до тех пор, чтобы получить этот уровень точности.

1 голос
/ 30 ноября 2010

Я оставляю свой другой ответ как есть, потому что он содержит много полезной информации для тех, кто может наткнуться на него.Насколько решение вашей проблемы более элегантно?Вам нужно будет перевернуть поиск по его голове и выполнить поиск по модели Post с помощью специального соединения, например:

// From the CategoriesController
$this->Category->Post->find('all', array(
    'joins' => array(
        array(
            'table' => 'categories_posts',
            'alias' => 'CategoryFilter',
            'type' => 'inner',
            'conditions' => array(
                'CategoryFilter.post_id = Post.id'
            )
        ),
        array(
            'table' => 'categories',
            'alias' => 'CategoryUriFilter',
            'type' => 'inner',
            'conditions' => array(
                'CategoryUriFilter.id = CategoryFilter.category_id'
            )
        )
    ),
    'conditions' => array(
        'CategoryUriFilter.uri' => $uri
    ),
    'contain' => array('Category')
));

Возвращенный массив будет отформатирован немного по-другому, но он должен содержатьвсе данные, которые вы искали.

0 голосов
/ 30 ноября 2010

Я действительно сделал это, чтобы получить то, что я хочу:

function getPostsFromCategory($uri) {
        return $this->populatePosts($this->find(
            'first',
            array(
                'conditions' => array(
                    'Category.uri' => $uri
                ),
                'contain' => array('Post' => array('Category'))
            )
        ));
    }

    function populatePosts($categoryPosts) {
        $posts = $categoryPosts['Post'];
        $count = count($categoryPosts['Post']);

        for ($i = 0; $i < $count; $i++) {
            $categories = $this->Post->find('first', array('conditions' => array('Post.id' => $categoryPosts['Post'][$i]['id']),
            'contains' => array('Category')));

            // unset($categories['Post']);
            foreach ($categories['Category'] as $cat) {
                $categoryPosts['Post'][$i]['Categories'][] = $cat;
            }
            unset($categories);
        }
        return $categoryPosts;
    }

Я действительно не знаю, можно ли это сделать более CakePHP-у, хотя:

Я возвращаюськак то так:

Array
(
    [Category] => Array
        (
            [id] => 3
            [name] => festivals
            [uri] => festivals
            [created] => 2010-11-25 20:43:03
            [modified] => 2010-11-25 20:43:03
        )

    [Post] => Array
        (
            [0] => Array
                (
                    [id] => 28
                    [title] => A Post
                    [Categories] => Array
                        (
                            [0] => Array
                                (
                                    [id] => 3
                                    [name] => festivals
                                    [uri] => festivals
                                    [created] => 2010-11-25 20:43:03
                                    [modified] => 2010-11-25 20:43:03
                                )

                            [1] => Array
                                (
                                    [id] => 4
                                    [name] => destinations
                                    [uri] => destinations
                                    [created] => 2010-11-28 13:04:52
                                    [modified] => 2010-11-28 13:04:52
                                )

                        )

                )
)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...