Php 在查询多个标记关系的原则时

Php 在查询多个标记关系的原则时,php,doctrine-orm,dql,Php,Doctrine Orm,Dql,一点背景: 我有办公室实体。 办公室可能有物品。 文章有标签。 办公室可以与其他办公室共享标签,从而共享文章。 现在,我正在尝试构建一个查询,该查询显示:获取属于我的办公室或具有与我的办公室共享的标记的所有文章 我在MySQL中尝试过这一点,以下查询按预期工作: SELECT * FROM `articles` `a` WHERE ( `office_id` = 2 OR `a`.`id` IN (

一点背景:

我有办公室实体。 办公室可能有物品。 文章有标签。 办公室可以与其他办公室共享标签,从而共享文章。 现在,我正在尝试构建一个查询,该查询显示:获取属于我的办公室或具有与我的办公室共享的标记的所有文章

我在MySQL中尝试过这一点,以下查询按预期工作:

SELECT 
    *  
FROM 
    `articles` `a` 
WHERE 
    (
        `office_id` = 2 
        OR 
        `a`.`id` IN (
            SELECT 
                `at`.`article_id` 
            FROM 
                `article_tags` `at` 
            WHERE 
                `at`.`article_id` = `a`.`id` 
            AND 
                `at`.`tag_id` IN 
                (
                    SELECT 
                        `st`.`tag_id` 
                    FROM 
                        `shared_tags` `st` 
                    WHERE 
                        `st`.`shared_with_id` = 2 
                    AND 
                        `st`.`article` = 1
                )
            )
    ) 
AND 
    `status` = 1
我的实体如下:

文章 标签 共享标签 那么,我如何在DQL或QueryBuilder中查询它呢?我尝试了几种方法,但似乎无法在WHERE in查询中使用relationship articles.tags中的标记id

提前谢谢你

编辑: 经过反复试验,感谢Jean的回答,我可以这样提问:

SELECT
  a
FROM
  Article a
LEFT JOIN a.tags t
LEFT JOIN a.office o
LEFT JOIN o.sharedTags st
WHERE
  (
    a.office = :office
    OR
    (
      t = st.tag
      AND
      st.sharedWith = :office
      AND
      st.article = 1
    )
  )
AND
  a.status.status = :status
AND
  a.template IS NULL
GROUP BY a.id

您应该使用联接,而不是子查询。这样,您可以获得更好的性能和更少复杂的DQL代码:

SELECT DISTINCT `a`
FROM `articles` `a` 
LEFT JOIN `a.tags` `t`
LEFT JOIN `t.shared_with_id` `o`
WHERE (`a`.`office_id` = 2 OR `o`.`id` = 2) 
AND `status` = 1

谢谢它走在正确的道路上,但是它仍然需要一些额外的限制。项目t中的标记需要与共享标记表中的标记匹配,并且该共享标记需要将布尔项目设置为1。所以我仍然需要找到一种方法来查询a.tags.id吗?对不起,我不明白。。。此查询已按共享标记进行筛选,因为o.id=2条件强制要求在id为2的办公室中使用该标记。。。你还需要什么?是的,你说得对!有一些条件,但经过一些调整,我找到了适合我的用例的条件,我已经用工作的DQL更新了我的问题。
class SharedTag extends Entity
{

    /**
     * @ORM\Id
     * @ORM\GeneratedValue
     * @ORM\Column(type="integer")
     * @var int
     */
    protected $id;

    /**
     * @ORM\ManyToOne(targetEntity="Office", inversedBy="sharedTags")
     * @ORM\JoinColumn(name="shared_with_id", referencedColumnName="id")
     * @var Office
     */
    protected $sharedWith;

    /**
     * @ORM\ManyToOne(targetEntity="Office", inversedBy="sharedTags")
     * @ORM\JoinColumn(name="shared_by_id", referencedColumnName="id")
     * @var Office
     */
    protected $sharedBy;

    /**
     * @ORM\ManyToOne(targetEntity="Tag", inversedBy="sharedTags")
     * @var Tag
     */
    protected $tag;

    /**
     * @ORM\Column(type="boolean", options={"default" = 0})
     * @var bool
     */
    protected $template = 0;

    /**
     * @ORM\Column(type="boolean", options={"default" = 0})
     * @var bool
     */
    protected $article = 0;

    /**
     * @ORM\Embedded(class = "\ValueObjects\CreatedAt", columnPrefix=false)
     * @var CreatedAt
     */
    protected $createdAt;

}
SELECT
  a
FROM
  Article a
LEFT JOIN a.tags t
LEFT JOIN a.office o
LEFT JOIN o.sharedTags st
WHERE
  (
    a.office = :office
    OR
    (
      t = st.tag
      AND
      st.sharedWith = :office
      AND
      st.article = 1
    )
  )
AND
  a.status.status = :status
AND
  a.template IS NULL
GROUP BY a.id
SELECT DISTINCT `a`
FROM `articles` `a` 
LEFT JOIN `a.tags` `t`
LEFT JOIN `t.shared_with_id` `o`
WHERE (`a`.`office_id` = 2 OR `o`.`id` = 2) 
AND `status` = 1