如何在CakePHP中的包含模型中查找类别

时间:2010-11-29 18:47:54

标签: cakephp

我最近有一个关于Finding records via conditions in 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
                )
        )
)

问题是其中一个帖子分为两类。我想也可以获得这些信息。

3 个答案:

答案 0 :(得分:3)

关闭。试试这个:

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

正切

编写这样的控制器代码存在问题:

  1. 它会使你的控制器方法变得臃肿,使你的控制器的可读性降低。
  2. 它可以防止您在不同的控制器中重复使用业务逻辑。
  3. 您可以通过将查找调用移至模型方法来令人满意地纠正这些问题:

    // 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'))
        ));
    }
    

    这使您的代码更加精彩

    1. 控制器很好,Skinny,超级可读。
    2. 现在,您可以从任何关联的模型调用相同的方法。例如,在您的PostsController中,您可以致电:$this->Post->Category->get_posts_with_cats($uri);。您的代码现在是DRY
    3. 切线#2

      在您学习如何嵌套像我向您展示过的可容纳的模型之后,您可能会在未来尝试做类似的事情:

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

      好消息?您将从上述方法中获得所需的模型数据(只要您已定义所有这些关系)。

      可怕的消息? CakePHP不知道如何针对这样的深层关联优化查询。因此,随着数据库的增长,您将最终向数据库发送数十个(如果不是数千个)SELECT个{{1}}个查询,从而有效地使您的应用程序进行爬网(如果不是停止) 。)

      设计CakePHP的好人正在为CakePHP 2.0开发更好的可容纳行为,但是你必须等到那时才能获得这种精确度。

答案 1 :(得分:1)

我正在离开我的另一个答案,因为它包含了许多可能偶然发现它的人的好信息。至于更优雅地解决你的问题?您需要翻转它的头部并使用ad-hoc连接从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')
));

返回的数组的格式有点不同,但它应该包含您要查找的所有数据。

答案 2 :(得分:0)

我实际上这样做是为了得到我想要的东西:

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-y方式完成:

我返回的内容如下:

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
                                )

                        )

                )
)