Ver código fonte

[Tree] Closure: If level property is found, we avoid the use of a subquery when getting the nodes hierarchy

comfortablynumb 13 anos atrás
pai
commit
ba4db02854

+ 19 - 9
lib/Gedmo/Tree/Entity/Repository/ClosureTreeRepository.php

@@ -296,8 +296,9 @@ class ClosureTreeRepository extends AbstractTreeRepository
         $meta = $this->getClassMetadata();
         $config = $this->listener->getConfiguration($this->_em, $meta->name);
         $nestedTree = array();
-        $levelField = self::SUBQUERY_LEVEL;
         $idField = $meta->getSingleIdentifierFieldName();
+        $hasLevelProp = isset($config['level']) && $config['level'];
+        $levelProp = $hasLevelProp ? $config['level'] : self::SUBQUERY_LEVEL;
 
         if (count($nodes) > 0) {
             $l = 1;
@@ -306,7 +307,7 @@ class ClosureTreeRepository extends AbstractTreeRepository
             foreach ($nodes as $n) {
                 $node = $n[0]['descendant'];
                 $node['__children'] = array();
-                $level = $n[$levelField];
+                $level = $hasLevelProp ? $node[$levelProp] : $n[$levelProp];
 
                 if ($l < $level) {
                     $l = $level;
@@ -332,19 +333,25 @@ class ClosureTreeRepository extends AbstractTreeRepository
     /**
      * {@inheritdoc}
      */
-    public function getNodesHierarchy($node, $direct, array $config, array $options = array())
+    public function getNodesHierarchy($node, $direct, array $config, array $options = array(), $returnQueryBuilder = false)
     {
         $meta = $this->getClassMetadata();
         $idField = $meta->getSingleIdentifierFieldName();
-        $subQuery = '(SELECT MAX(c2.depth) + 1 FROM '.$config['closure'];
-        $subQuery .= ' c2 WHERE c2.descendant = c.descendant GROUP BY c2.descendant) AS '.self::SUBQUERY_LEVEL;
+        $subQuery = '';
+        $hasLevelProp = isset($config['level']) && $config['level'];
+
+        if (!$hasLevelProp) {
+            $subQuery = ', (SELECT MAX(c2.depth) + 1 FROM '.$config['closure'];
+            $subQuery .= ' c2 WHERE c2.descendant = c.descendant GROUP BY c2.descendant) AS '.self::SUBQUERY_LEVEL;
+        }
+
         $q = $this->_em->createQueryBuilder()
-            ->select('c, node, p.'.$idField.' AS parent_id, '.$subQuery)
+            ->select('c, node, p.'.$idField.' AS parent_id'.$subQuery)
             ->from($config['closure'], 'c')
             ->innerJoin('c.descendant', 'node')
             ->leftJoin('node.parent', 'p')
             ->where('c.ancestor = :node')
-            ->addOrderBy('level', 'asc');
+            ->addOrderBy(($hasLevelProp ? 'node.'.$config['level'] : self::SUBQUERY_LEVEL), 'asc');
 
         $defaultOptions = array();
         $options = array_merge($defaultOptions, $options);
@@ -357,10 +364,13 @@ class ClosureTreeRepository extends AbstractTreeRepository
             );
         }
 
-        $q = $q->getQuery();
         $q->setParameters(compact('node'));
 
-        return $q->getArrayResult();
+        if ($returnQueryBuilder) {
+            return $q;
+        }
+
+        return $q->getQuery()->getArrayResult();
     }
 
     /**

+ 35 - 1
tests/Gedmo/Tree/ClosureTreeRepositoryTest.php

@@ -24,12 +24,16 @@ class ClosureTreeRepositoryTest extends BaseTestCaseORM
     const CATEGORY_WITHOUT_LEVEL = "Tree\\Fixture\\Closure\\CategoryWithoutLevel";
     const CATEGORY_WITHOUT_LEVEL_CLOSURE = "Tree\\Fixture\\Closure\\CategoryWithoutLevelClosure";
 
+    protected $listener;
+
     protected function setUp()
     {
         parent::setUp();
 
+        $this->listener = new TreeListener;
+
         $evm = new EventManager;
-        $evm->addEventSubscriber(new TreeListener);
+        $evm->addEventSubscriber($this->listener);
 
         $this->getMockSqliteEntityManager($evm);
     }
@@ -150,6 +154,36 @@ class ClosureTreeRepositoryTest extends BaseTestCaseORM
         $this->buildTreeTests(self::CATEGORY_WITHOUT_LEVEL);
     }
 
+    public function testHavingLevelPropertyAvoidsSubqueryInSelectInGetNodesHierarchy()
+    {
+        $this->populate();
+
+        $repo = $this->em->getRepository(self::CATEGORY);
+        $roots = $repo->getRootNodes();
+        $meta = $this->em->getClassMetadata(self::CATEGORY);
+        $config = $this->listener->getConfiguration($this->em, $meta->name);
+        $qb = $repo->getNodesHierarchy($roots[0], false, $config, array(), true);
+
+        $this->assertFalse(strpos($qb->getQuery()->getDql(), '(SELECT MAX('));
+    }
+
+    public function testoNotHavingLevelPropertyUsesASubqueryInSelectInGetNodesHierarchy()
+    {
+        $this->populate(self::CATEGORY_WITHOUT_LEVEL);
+
+        $repo = $this->em->getRepository(self::CATEGORY_WITHOUT_LEVEL);
+        $roots = $repo->getRootNodes();
+        $meta = $this->em->getClassMetadata(self::CATEGORY_WITHOUT_LEVEL);
+        $config = $this->listener->getConfiguration($this->em, $meta->name);
+        $qb = $repo->getNodesHierarchy($roots[0], false, $config, array(), true);
+
+        $this->assertTrue(((bool) strpos($qb->getQuery()->getDql(), '(SELECT MAX(')));
+    }
+
+
+
+    // Utility Methods
+
     protected function buildTreeTests($class)
     {
         $repo = $this->em->getRepository($class);