2011-05-13 90 views
1

我为可怕的标题道歉,我想不出如何解释我的问题。CakePHP条件查询与控制器hasAndBelongsToMany'

在我的数据库中,我有以下表格,articles,tagsarticles_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标签返回的文章?

回答

2

试试这个

// 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 
      )); 
0

不可能直接。

最简单的方法是通过标签控制器

2

使查询这样你可以使用LinkableBehavior条件。它是专为确切的你想要的结果。如果你不想使用它,你必须做的标签控制器上的查询:

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

重新评论你留在我的答案。我使用了与分页相似的东西。但我无法验证,因为我没有访问我的蛋糕机。当我回家时,我会看看,谢谢你的抬头。 – JohnP 2011-05-13 08:03:07

+0

如果我从标签控制器执行查询,我遇到了几乎相同的问题。这是因为文章有一个状态字段,我需要检查状态是否处于活动状态。 – Paramount 2011-05-13 13:20:02

+0

@派拉蒙,所以狮子座的解决方案是要走的路 – kaklon 2011-05-13 14:31:07

0

我更新这个问题有答案CakePHP的3 。X。

对于给定的tag,您可以使用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);

我敢肯定,这个信息已经在网络上,但这个问题是谷歌的结果页的顶部。所以也许这会帮助其他人。