【问题标题】:Doctrine ORM: filter articles by 2 categoriesDoctrine ORM:按 2 个类别过滤文章
【发布时间】:2018-06-20 12:35:58
【问题描述】:

在我们的在线商店中,我们销售工业计算机系统的备件。因此,我们有 2 个主要类别:备件和计算机系统。用户可以通过备件类别或通过计算机系统搜索所需的备件。如果用户在主页上选择了他的计算机系统,他应该会得到一个与他的计算机系统匹配的备件类别列表。

因此我需要查询所有备件类别并按所有文章过滤它们,这些文章也在预选的计算机系统的类别中。否则用户可能会看到一个空类别。

我有 2 个学说实体:文章和类别 - 它们中的每一个都与另一个多对多相关:

类别实体

/**
 * @ORM\Table(name="categories")
 * @ORM\Entity(repositoryClass="Repository")
 */
class Category extends ModelEntity
{

    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Models\Article\Article")
     * @ORM\JoinTable(name="articles_categories",
     *      joinColumns={
     *          @ORM\JoinColumn(name="categoryID", referencedColumnName="id")
     *      },
     *      inverseJoinColumns={
     *          @ORM\JoinColumn(name="articleID", referencedColumnName="id")
     *      }
     * )
     */
    private $articles;

文章实体:

/**
 * @ORM\Entity(repositoryClass="Repository")
 * @ORM\Table(name="articles")
 */
class Article extends ModelEntity
{

    /**
     * @var ArrayCollection
     *
     * @ORM\ManyToMany(targetEntity="Models\Category\Category")
     * @ORM\JoinTable(name="articles_categories",
     *      joinColumns={
     *          @ORM\JoinColumn(name="articleID", referencedColumnName="id")
     *      },
     *      inverseJoinColumns={
     *          @ORM\JoinColumn(name="categoryID", referencedColumnName="id")
     *      }
     * )
     */
    protected $categories;

我正在尝试使用 2 个类别的文章查询所有类别。例如:获取所有类别,在“this”类别中有文章,但仅在相同文章也在“that”类别中。

不幸的是,我不知道该怎么做。谁能帮帮我?

【问题讨论】:

  • 那么在任何 2 个类别中,还是在您选择的 2 个类别中?
  • 在 2 个选定的类别中 - 例如:仅获取本身有文章的类别 AND 类别 2。

标签: php doctrine-orm orm


【解决方案1】:

要查找属于给定文章列表的类别(每个类别必须与给定列表中的每篇文章有关联),那么您可以使用一些聚合

$articleIds = [1,2,3,4,5];
$qb = $this->createQueryBuilder('c');
        $qb->addSelect('COUNT(DISTINCT  a.id) AS HIDDEN total_articles')
           ->innerJoin('c.articles', 'a')
           ->add('where', $qb->expr()->in('a', $articleIds))
           ->groupBy('c.id')
           ->having('total_articles = '.count($articleIds))
           ->getQuery()
           ->getResult(); 

【讨论】:

  • 感谢您的帮助 - 它确实让我大开眼界。虽然,您的查询获取所有类别,其中包含特定文章。我需要一个查询,它获取所有类别,其文章也被分配到另一个特定类别。比如:$qb->select('c, COUNT(DISTINCT a.id) AS total_articles') ->from('Models\Category\Category', 'c') ->innerJoin('c.articles', 'a') ->innerJoin('a.categories', 'c2') ->add('where', $qb->expr()->in('c2', 42636)) ->groupBy('c.id') ->having('total_articles = 2');
  • @chris.ribal 您能否为类别和文章添加示例数据,并在此基础上在您的问题中包含您的预期输出,这将非常有助于理解您的问题
  • @M Khalid Junaid 我更新了问题并包含了我想要实现的目标的基本描述。我也在我的案例中找到了解决方案并将其作为单独的答案发布。谢谢你让我走上正轨!
【解决方案2】:

感谢 M Khalid Junaid,我终于弄明白了。 这是我的最终查询:

// select all active root categories from the online shop
$builder = Shopware()->Models()->createQueryBuilder();
$builder->from('Models\Category\Category', 'c')
        ->select('c as category')
        ->andWhere('c.active = 1')
        ->andWhere('c.parentId = 0');

// if the user already selected his computer system,
// only get articles, that are in both categories: the
// category of this particular computer system and the
// category of spare parts
if ($this->computerSystemCategoryId) {

    $builder->addSelect('COUNT(DISTINCT a2.id) AS total_system_articles')
            ->leftJoin('c.articles', 'a2')
            ->leftJoin('a2.categories', 'c2')
            ->groupBy('c.id')
            ->having('total_system_articles > 0')
            ->andWhere($builder->expr()->in('c2', [$this->computerSystemCategoryId]));

}

$query = $builder->getQuery();
$categories = $query->getResult();

通过此查询,我只能获取与特定备件类别相关联的备件,还可以获取与特定计算机系统类别 ID 相关联的备件。

【讨论】:

  • 很高兴你找到它
猜你喜欢
  • 2020-01-23
  • 2017-08-06
  • 2015-06-08
  • 2014-11-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-06-28
  • 1970-01-01
相关资源
最近更新 更多