0

架构:

类别 [ id , parent, children, left, right, level, root, products ]

产品 [ id , category, marketSegments ]

市场细分 [ id ]

此外,每个实体都有 , 之类的字段 name 这些与我的问题无关。description slug

示例数据

传奇:

c- 类别,p- 产品

标有 * 的产品标有“出口到美国”的细分市场

Food                                [c, id: 1, level: 0]
---> Vegetables                       [c, id: 2, level: 1]
--------------> Potato                  [p, id: 1]
--------------> Carrot                  [p, id: 2]
---> Fruits                           [c, id: 3, level: 1]
--------------> Berries                 [c, id: 5, level: 2]
---------------------------> Grapes       [p, id: 3]
--------------> Hesperidiums            [c, id: 6, level: 2]
---------------------------> Orange*      [p, id: 4]
---> Meat                             [c, id: 4, level: 1]
--------------> Beef*                   [p, id: 5]

预期查询结果:

对于给定的数据和$category = Food$marketSegment = Export to USA的预期结果将是:

$filteredCategories = [Fruits, Meat]

为什么?

  • Meat因为它包含Beef标有出口到美国的产品
  • FruitsHesperidiums因为它包含包含标记产品的类别。

包含标记产品的类别在嵌套树中的深度无关紧要。

这个:

Sports [c]
-----> Individual [c]
----------------> Fight [c]
----------------------> MMA [c]
--------------------------> Boxing gloves* [p]

对于$category = Sports应返回:[ Individual]。

对于$category = Fight应该返回:[ MMA]。


我的(不工作的)DQL 方法:

SELECT DISTINCT cat FROM Avocode\CatalogBundle\Entity\Category cat 
WHERE cat.parent = :parent_id 
AND (EXISTS(
        SELECT sub FROM Avocode\CatalogBundle\Entity\Category sub 
        LEFT JOIN sub.products prod 
        LEFT JOIN prod.marketSegments seg 
        WHERE sub.left > cat.left 
        AND sub.right < cat.right 
        AND seg.id = :segment_id
)) 
ORDER BY cat.root, cat.left ASC
4

2 回答 2

3

NestedTreeRepositoryGedmo NestedSet 行为扩展附带的有一个方法getChildrenQueryBuilder(),允许您查询给定父节点的子节点,并有一个参数用于查询层次结构中深几层的节点。您应该调查随附的方法和选项,NestedTreeRepository以便不需要手动构建 DQL。

我不完全确定您的所有代码是如何设置的,因此我无法提供确切的解决方案,但我认为您可以弄清楚:)

NestedSet 文档:http ://www.gediminasm.org/article/tree-nestedset-behavior-extension-for-doctrine-2

于 2012-11-28T00:00:58.123 回答
1

谢谢约翰!使用 NestedTreeRepository 我想出了解决方案:

我为扩展 NestedTreeRepository 的 Category 类创建了自己的 Repository 并创建了一个自定义方法

公共函数 findSubcategoriesFilteredByMarketSegment (Category $parentNode, MarketSegment $segment)

{

   // get DIRECT CHILDREN for $parentNode
   $qb = $this->getChildrenQueryBuilder($parentNode, true);
   $qb->leftJoin($qb->getRootAlias().'.products', 'prod')
      ->leftJoin('prod.marketSegments', 'seg');    

   // subquery -> get all children (direct and indirect) 
   // for DIRECT CHILD from main query
   $sqb = $this->_em->getRepository('AvocodeCatalogBundle:Category')->createQueryBuilder('sub');

   // join products and market segments
   $sqb->leftJoin($sqb->getRootAlias().'.products', 'sub_prod')
       ->leftJoin('sub_prod.marketSegments', 'sub_seg');

   // to match children of main query's DIRECT CHILD
   // they need to have left and right values between DIRECT CHILD's left and right
   $sqb->where(
            $sqb->expr()->andX(
               $sqb->expr()->gt('sub.lft', $qb->getRootAlias().'.lft'),
               $sqb->expr()->lt('sub.rgt', $qb->getRootAlias().'.rgt'),
               $sqb->expr()->eq('sub.root', $qb->getRootAlias().'.root')
        ));

   // match only children with products related to $segment
   $sqb->andWhere($sqb->expr()->eq('sub_seg.id', ':segment_id'));

   // BACK TO MAIN QUERY
   // select only parentNode children THAT
   $qb->andWhere(
         $qb->expr()->orX(
             // contain product with related segment
             $qb->expr()->eq('seg.id', ':segment_id'),
             // or 
             // have a child (direct or indirect) that does contain such product
             $qb->expr()->exists($sqb->getDQL())       
     ))
     ->setParameter('segment_id', $segment->getId());

   return $qb->getQuery()->getResult();

}

于 2012-11-29T12:45:58.227 回答