代码之家  ›  专栏  ›  技术社区  ›  Teej

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

  •  4
  • Teej  · 技术社区  · 15 年前

    我最近有个问题 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
                    )
            )
    )
    

    问题是1个职位分为两类。我也想知道这些信息。

    3 回复  |  直到 15 年前
        1
  •  1
  •   Stephen    15 年前

    我留下了我的另一个答案,因为它包含了很多很好的信息给那些可能偶然发现它的人。能更优雅地解决你的问题吗?您需要翻转其头上的查找,并通过特殊连接从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
  •  3
  •   Stephen    15 年前

    关闭。试试这个:

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

    切线

    这样编写控制器代码有问题:

    1. 它会膨胀您的控制器方法,使您的控制器更不可读。
    2. 它防止您在不同的控制器之间重新使用业务逻辑。

    您可以通过将find调用移动到模型方法来满意地纠正这些问题:

    // 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 .

    正切α2

    在您学习了如何嵌套像我向您展示的那样的可包含模型之后,将来您可能会尝试这样做:

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

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

    可怕的消息? Cakephp不知道如何优化这种深层关联的查询。因此,随着数据库的增长,最终会得到几十个(如果不是数百个(如果不是数千个))的 SELECT 对数据库的查询,有效地使应用程序进入爬行状态(如果不是 停止 )

    设计cakephp的优秀人员正在为cakephp 2.0开发一个更好的可包含行为,但是您必须等到那时才能获得这一级别的精度。

        3
  •  0
  •   Teej    15 年前

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

    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;
        }
    

    我真的不知道这是否可以用一种更冷静的方式来实现:

    我返回如下内容:

    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
                                    )
    
                            )
    
                    )
    )