CakePHP 条件查询与控制器“hasAndBelongsToMany”

发布于 2024-11-07 02:50:40 字数 1290 浏览 1 评论 0原文

我对这个可怕的标题表示歉意,我不知道如何解释我的问题。

在我的数据库中,我有以下表格:articlestagsarticles_tags。一篇文章可以有多个标签。

目前,我可以获取所有带有所有标签的文章,但我希望能够根据其标签查找文章。

我的选择很简单:

$articles = $this->Article->find('all', array(
    // extra condition to check for tag, maybe?
    'conditions'    => array('Article.status' => 'active'), 
    'limit'         => $this->articles_per_page,
    'offset'        => ($page_num-1)*$this->articles_per_page
));

我从数据库的返回如下:

Array
(
[0] => Array
    (
        [Article] => Array
            (
                [id] => 1
            )

        [Tag] => Array
            (
                [0] => Array
                    (
                        [id] => 1
                        [name] => Ruby
                        [slug] => ruby
                        [uses] => 1
                        [ArticlesTag] => Array
                            (
                                [id] => 1
                                [article_id] => 1
                                [tag_id] => 1
                            )

                    )

            )

    )

如果我只想返回带有 Ruby 标签的文章,该怎么办?

I apologize for the horrible title, I couldn't think of how to explain my problem.

In my database I have the following tables, articles, tags, and articles_tags. An article can have many tags.

Currently I am able to grab all the articles, with all the tags, but I want to be able to find articles based upon it's tags.

My select is simple:

$articles = $this->Article->find('all', array(
    // extra condition to check for tag, maybe?
    'conditions'    => array('Article.status' => 'active'), 
    'limit'         => $this->articles_per_page,
    'offset'        => ($page_num-1)*$this->articles_per_page
));

My return from the database is as follows:

Array
(
[0] => Array
    (
        [Article] => Array
            (
                [id] => 1
            )

        [Tag] => Array
            (
                [0] => Array
                    (
                        [id] => 1
                        [name] => Ruby
                        [slug] => ruby
                        [uses] => 1
                        [ArticlesTag] => Array
                            (
                                [id] => 1
                                [article_id] => 1
                                [tag_id] => 1
                            )

                    )

            )

    )

What do I do if I only want to return the articles with a Ruby tag?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

_失温 2024-11-14 02:50:40

试试这个

// In your Article model
function getArticleByTagSql($tag)
{       
        $dbo = $this->getDataSource();
        $subQuery = $dbo->buildStatement(
        array(
                    'fields' => array('DISTINCT(ArticlesTag.article_id)'),
                    'table' => "articles_tags",                                    
                    'joins' => array(
                                array('table' => 'tags',
                                    'alias' => 'Tag',
                                    'type' => 'INNER',
                                    'conditions' => array('ArticlesTag.tag_id = Tag.id')
                                    )
                                ),
                    'alias'=>"ArticlesTag",                                         
                    'conditions' => array("Tag.name"=>Sanitize::clean($tag_words)),
                    'order' => null,
                    'group' => "ArticlesTag.article_id"
                    ),
                    $this
                    );
                    $subQuery = ' Article.id  IN (' . $subQuery . ')';
                    return $dbo->expression($subQuery);

}

// In your Articles Controller

$this->paginate['conditions'][] = $this->Article->getArticleByTagSql($tag_name);
$this->paginate['conditions'][] = array('Article.status' => 'active');
$this->paginate['limit'] = $this->articles_per_page;



// or as per your example
$articles = $this->Article->find('all', array(
                // extra condition to check for tag, maybe?
                'conditions'    => array('Article.status' => 'active',$this->Article->getArticleByTagSql($tag_name)), 
                'limit'         => $this->articles_per_page,
                'offset'        => ($page_num-1)*$this->articles_per_page
            ));

Try this

// In your Article model
function getArticleByTagSql($tag)
{       
        $dbo = $this->getDataSource();
        $subQuery = $dbo->buildStatement(
        array(
                    'fields' => array('DISTINCT(ArticlesTag.article_id)'),
                    'table' => "articles_tags",                                    
                    'joins' => array(
                                array('table' => 'tags',
                                    'alias' => 'Tag',
                                    'type' => 'INNER',
                                    'conditions' => array('ArticlesTag.tag_id = Tag.id')
                                    )
                                ),
                    'alias'=>"ArticlesTag",                                         
                    'conditions' => array("Tag.name"=>Sanitize::clean($tag_words)),
                    'order' => null,
                    'group' => "ArticlesTag.article_id"
                    ),
                    $this
                    );
                    $subQuery = ' Article.id  IN (' . $subQuery . ')';
                    return $dbo->expression($subQuery);

}

// In your Articles Controller

$this->paginate['conditions'][] = $this->Article->getArticleByTagSql($tag_name);
$this->paginate['conditions'][] = array('Article.status' => 'active');
$this->paginate['limit'] = $this->articles_per_page;



// or as per your example
$articles = $this->Article->find('all', array(
                // extra condition to check for tag, maybe?
                'conditions'    => array('Article.status' => 'active',$this->Article->getArticleByTagSql($tag_name)), 
                'limit'         => $this->articles_per_page,
                'offset'        => ($page_num-1)*$this->articles_per_page
            ));
走过海棠暮 2024-11-14 02:50:40

对于这样的情况,您可以使用 LinkableBehavior。它专为您想要的结果而设计。如果您不想使用它,则必须在标签控制器上进行查询:

$this->Tag->find('all', array('conditions' => array('Tag.name' => 'ruby')));

For conditions like this you can use the LinkableBehavior. It's designed for exact your wanted result. In case you don't want to use it, you have to do a query on the tag controller:

$this->Tag->find('all', array('conditions' => array('Tag.name' => 'ruby')));
淡水深流 2024-11-14 02:50:40

直接不可能。

最简单的方法是通过标签控制器进行查询

Not possible directly.

The easiest way is to make the query through the tag controller

剧终人散尽 2024-11-14 02:50:40

我正在用 CakePHP 3.x 的答案更新这个问题。

您可以使用 INNER JOIN 查找给定标签的所有文章。此联接的好处是它将 articles 保留为查询中的主表。当您通过 HABTM 联接对结果进行分页时,这将成为一个简单的解决方案。

$tag_id = 3; // the ID of the tag

$query = $this->Articles->find('all')
                 ->innerJoin('articles_tags', [
                      'Articles.id = articles_tags.article_id',
                      'articles_tags.tag_id' => $tag_id
                 ]);

第一个连接条件必须是数组键。如果您使用=>数组赋值,那么CakePHP会将articles_tags.article_id作为字符串参数传递给连接条件。这是行不通的。

您还可以针对多个 HABTM 条件堆叠 innerJoin。例如;查找标签以及类别的所有文章。您还可以使用 in 查询表达式来匹配多个标签

您还可以在分页中使用上述内容,如下所示 $articles = $this->paginate($query);

我确信此信息已在网络上发布,但这个问题是最重要的谷歌的结果。所以也许这会帮助其他人。

I'm updating this question with an answer for CakePHP 3.x.

You can find all articles for a given tag using an INNER JOIN. The benefit of this join is that it keeps articles as the primary table in the query. Making this an easy solution when you're paginating results by a HABTM join.

$tag_id = 3; // the ID of the tag

$query = $this->Articles->find('all')
                 ->innerJoin('articles_tags', [
                      'Articles.id = articles_tags.article_id',
                      'articles_tags.tag_id' => $tag_id
                 ]);

The first join condition has to be the array key. If you use a => array assignment then CakePHP will pass the articles_tags.article_id as a string argument to the join condition. Which won't work.

You can also stack innerJoin for multiple HABTM conditions. For example; find all articles for a tag and also for a category. You can also use the in query expression to match multiple tags.

You can also use the above in pagination like this $articles = $this->paginate($query);

I'm sure this information is out on the web, but this question was the top of google's results. So maybe this will help others.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文