Symfony 5&Doctrine 2:选择仅包含N个标签的文章

问题描述 投票:1回答:2

我有两个实体,商品实体和标签实体。这两个实体之间存在ManyToMany关系(文章可以具有0-> N个标签,并且标签可以包含在0-> N个文章中)

我想在某些条件下搜索文章(我必须使用querybuilder,像findBy()这样的魔术方法还不够),在这些条件下的一种是选择恰好包含N个特定标记的文章

我尝试过几次以取得预期的结果,但没有成功。我想我误解了教义如何与联接表一起工作。我的最后尝试:

public function search($titles, $tags, $authors)
{

    $query = $this->createQueryBuilder('a') // a = article
        ->orderBy('a.createdAt', 'DESC')
        ->setMaxResults($limit)
        ->setFirstResult($offset);

    if($titles !== null){
        // ...
    }

    // tags is an array of string containing names of searched tags (ex : $tags = ['english', 'french', 'game', 'guide'] )
    if($tags !== null){
        // $query->innerJoin('a.tags', 't');
        // $tagsQuery = "";
        // foreach ($tags as $id => $tag){
        //     if($id > 0) $tagsQuery .= " AND ";
        //     $tagsQuery .= "t.name LIKE :tag_".$id;
        //     $query->setParameter("tag_".$id, '%'.$tag.'%');
        // }
        // $query
        //     ->andWhere($tagsQuery);

        $query->leftjoin ('a.tags','t');
        foreach ($tags as $id => $tag){
        // $query->andWhere("t.name LIKE :tag_".$id);
        // $query->setParameter("tag_".$id, '%'.$tag.'%');
            $query
                ->addSelect('t')
                ->andwhere("t.name LIKE :tag_".$id)
                ->setParameter("tag_".$id, '%'.$tag.'%');
        }
    }

    // ...

预期结果的一个例子:

有3篇文章:

- id 1 
- tags : 
    - guide
    - game

- id 2 
- tags : 
    - english

- id 3 
- tags : 
    - english
    - guide

方法search(null, ['guide','english'], null)必须仅返回ID为3的文章

php symfony doctrine
2个回答
1
投票

如果您希望所有的文章都具有至少一个指定的标签,那么您的代码应该是这样的:

    public function search($titles, $tags, $authors)
    {

        return $query = $this->createQueryBuilder('a') // a = article
            ->innerJoin('a.tags', 't') //on inner join is enough
            ->where('t.name in (:set)')
            ->setParameter('set', $tags)
            ->orderBy('a.createdAt', 'DESC')
            ->setMaxResults($limit)
            ->setFirstResult($offset)
            ->getQuery()   //retrieve
            ->getResult();
    }

此第一个SQL将进行联接。提示是使用“ in”运算符。

[如果您希望文章包含所有标签(实际上是所有标签),则应为每个标签添加一个内部联接。技巧是为每个联接添加一个别名,并为别名上的某物添加唯一的名称。


    public function search($titles, $tags, $authors)
    {

        $query = $this->createQueryBuilder('a') // a = article;

        foreach ($tags as $index => $tag) {
             $query->innerJoin('a.tags', "t$index")
               ->andWhere("t$index" + ".name in (:tag$index)")
               ->setParameter("tag$index", $tag)
        }

        return $query
            ->orderBy('a.createdAt', 'DESC')
            ->setMaxResults($limit)
            ->setFirstResult($offset)
            ->getQuery()   //retrieve
            ->getResult();

您的请求应该是这样的。我没有测试它们,但这是模板。


0
投票

感谢Alexandre的技巧,我得到了解决方案:)

如果有人遇到同样的问题,这里的代码:

     foreach ($tags as $id => $tag) {
            $query->innerJoin('a.tags', "t${id}")
                ->andWhere("t${id}.name in (:tag${id})")
                ->setParameter(":tag${id}", $tag);
     }
© www.soinside.com 2019 - 2024. All rights reserved.