Jelajahi Sumber

[Tree] Materialized Path - ORM: Added repository methods and tests

comfortablynumb 13 tahun lalu
induk
melakukan
5c4911a896

+ 130 - 3
lib/Gedmo/Tree/Entity/Repository/MaterializedPathRepository.php

@@ -1,10 +1,11 @@
 <?php
 
-namespace Gedmo\Tree\Document\MongoDB\Repository;
+namespace Gedmo\Tree\Entity\Repository;
 
 use Gedmo\Exception\InvalidArgumentException,
     Gedmo\Tree\Strategy,
-    Gedmo\Tree\Strategy\ORM\MaterializedPath;
+    Gedmo\Tree\Strategy\ORM\MaterializedPath,
+    Gedmo\Tool\Wrapper\EntityWrapper;
 
 /**
  * The MaterializedPathRepository has some useful functions
@@ -20,11 +21,137 @@ use Gedmo\Exception\InvalidArgumentException,
  */
 class MaterializedPathRepository extends AbstractTreeRepository
 {
+    /**
+     * Get tree query builder
+     *
+     * @return Doctrine\ORM\QueryBuilder
+     */
+    public function getTreeQueryBuilder()
+    {
+        return $this->getChildrenQueryBuilder();
+    }
+
+    /**
+     * Get tree query
+     *
+     * @return Doctrine\ORM\Query
+     */
+    public function getTreeQuery()
+    {
+        return $this->getTreeQueryBuilder()->getQuery();
+    }
+
+    /**
+     * Get tree
+     *
+     * @return array
+     */
+    public function getTree()
+    {
+        return $this->getTreeQuery()->execute();
+    }
+
+    /**
+     * Get all root nodes query builder
+     *
+     * @return Doctrine\ORM\QueryBuilder
+     */
+    public function getRootNodesQueryBuilder($sortByField = null, $direction = 'asc')
+    {
+        return $this->getChildrenQueryBuilder(null, true, $sortByField, $direction);
+    }
+
+    /**
+     * Get all root nodes query
+     *
+     * @return Doctrine\ORM\Query
+     */
+    public function getRootNodesQuery($sortByField = null, $direction = 'asc')
+    {
+        return $this->getRootNodesQueryBuilder($sortByField, $direction)->getQuery();
+    }
+
+    /**
+     * Get all root nodes
+     *
+     * @return array
+     */
+    public function getRootNodes($sortByField = null, $direction = 'asc')
+    {
+        return $this->getRootNodesQuery($sortByField, $direction)->execute();
+    }
+
+    /**
+     * Get children from node
+     *
+     * @return Doctrine\ORM\QueryBuilder
+     */
+    public function getChildrenQueryBuilder($node = null, $direct = false, $sortByField = null, $direction = 'asc')
+    {
+        $meta = $this->getClassMetadata();
+        $config = $this->listener->getConfiguration($this->_em, $meta->name);
+        $separator = addcslashes($config['path_separator'], '%');
+        $alias = 'materialized_path_entity';
+        $path = $config['path'];
+        $qb = $this->_em->createQueryBuilder($meta->name)
+            ->select($alias)
+            ->from($meta->name, $alias);
+
+        if (is_object($node) && $node instanceof $meta->name) {
+            $node = new EntityWrapper($node, $this->_em);
+            $nodePath = $node->getPropertyValue($path);
+            $expr = $qb->expr()->andx()->add(
+                $qb->expr()->like($alias.'.'.$path, $qb->expr()->literal($nodePath.'%'))
+            );
+            $expr->add($qb->expr()->neq($alias.'.'.$path, $qb->expr()->literal($nodePath)));
+
+            if ($direct) {
+                $expr->add(
+                    $qb->expr()->not(
+                        $qb->expr()->like($alias.'.'.$path, $qb->expr()->literal($nodePath.'%'.$separator.'%'.$separator))
+                ));
+            }
+
+            $qb->where('('.$expr.')');
+        } else if ($direct) {
+            $expr = $qb->expr()->not(
+                $qb->expr()->like($alias.'.'.$path, $qb->expr()->literal('%'.$separator.'%'.$separator.'%'))
+            );
+            $qb->where('('.$expr.')');
+        }
+
+        $orderByField = is_null($sortByField) ? $alias.'.'.$config['path'] : $alias.'.'.$sortByField;
+        $orderByDir = $direction === 'asc' ? 'asc' : 'desc';
+        $qb->orderBy($orderByField, $orderByDir);
+
+        return $qb;
+    }
+
+    /**
+     * Get children query
+     *
+     * @return Doctrine\ORM\Query
+     */
+    public function getChildrenQuery($node = null, $direct = false, $sortByField = null, $direction = 'asc')
+    {
+        return $this->getChildrenQueryBuilder($node, $direct, $sortByField, $direction)->getQuery();
+    }
+
+    /**
+     * Get children
+     *
+     * @return array
+     */
+    public function getChildren($node = null, $direct = false, $sortByField = null, $direction = 'asc')
+    {
+        return $this->getChildrenQuery($node, $direct, $sortByField, $direction)->execute();
+    }
+
     /**
      * {@inheritdoc}
      */
     protected function validate()
     {
-        return $this->listener->getStrategy($this->dm, $this->getClassMetadata()->name)->getName() === Strategy::MATERIALIZED_PATH;
+        return $this->listener->getStrategy($this->_em, $this->getClassMetadata()->name)->getName() === Strategy::MATERIALIZED_PATH;
     }
 }

+ 2 - 1
lib/Gedmo/Tree/Strategy/ORM/MaterializedPath.php

@@ -26,7 +26,7 @@ class MaterializedPath extends AbstractMaterializedPath
         $uow = $om->getUnitOfWork();
         $pathProp = $meta->getReflectionProperty($config['path']);
         $pathProp->setAccessible(true);
-        $path = $pathProp->getValue($node);
+        $path = addcslashes($pathProp->getValue($node), '%');
 
         // Remove node's children
         $qb = $om->createQueryBuilder();
@@ -46,6 +46,7 @@ class MaterializedPath extends AbstractMaterializedPath
      */
     public function getChildren($om, $meta, $config, $path)
     {
+        $path = addcslashes($path, '%');
         $qb = $om->createQueryBuilder($meta->name);
         $qb->select('e')
             ->from($meta->name, 'e')

+ 1 - 1
tests/Gedmo/Tree/Fixture/MPCategory.php

@@ -7,7 +7,7 @@ use Gedmo\Mapping\Annotation as Gedmo;
 use Doctrine\ORM\Mapping as ORM;
 
 /**
- * @ORM\Entity
+ * @ORM\Entity(repositoryClass="Gedmo\Tree\Entity\Repository\MaterializedPathRepository")
  * @Gedmo\Tree(type="materializedPath")
  */
 class MPCategory

+ 149 - 0
tests/Gedmo/Tree/MaterializedPathORMRepositoryTest.php

@@ -0,0 +1,149 @@
+<?php
+
+namespace Gedmo\Tree;
+
+use Doctrine\Common\EventManager;
+use Tool\BaseTestCaseORM;
+use Tree\Fixture\RootCategory;
+
+/**
+ * These are tests for Tree behavior
+ *
+ * @author Gustavo Falco <comfortablynumb84@gmail.com>
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Tree
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class MaterializedPathORMRepositoryTest extends BaseTestCaseORM
+{
+    const CATEGORY = "Tree\\Fixture\\MPCategory";
+
+    protected function setUp()
+    {
+        parent::setUp();
+
+        $this->listener = new TreeListener;
+
+        $evm = new EventManager;
+        $evm->addEventSubscriber($this->listener);
+
+        $this->getMockSqliteEntityManager($evm);
+
+        $meta = $this->em->getClassMetadata(self::CATEGORY);
+        $this->config = $this->listener->getConfiguration($this->em, $meta->name);
+        $this->populate();
+    }
+
+    /**
+     * @test
+     */
+    function getRootNodes()
+    {
+        $repo = $this->em->getRepository(self::CATEGORY);
+        $result = $repo->getRootNodes('title');
+        
+        $this->assertEquals(2, count($result));
+        $this->assertEquals('Food', $result[0]->getTitle());
+        $this->assertEquals('Sports', $result[1]->getTitle());
+    }
+
+    /**
+     * @test
+     */
+    function getChildren()
+    {
+        $repo = $this->em->getRepository(self::CATEGORY);
+        $root = $repo->findOneByTitle('Food');
+
+        // Get all children from the root
+        $result = $repo->getChildren($root, false, 'title');
+
+        $this->assertEquals(4, count($result));
+        $this->assertEquals('Carrots', $result[0]->getTitle());
+        $this->assertEquals('Fruits', $result[1]->getTitle());
+        $this->assertEquals('Potatoes', $result[2]->getTitle());
+        $this->assertEquals('Vegitables', $result[3]->getTitle());
+
+        // Get direct children from the root
+        $result = $repo->getChildren($root, true, 'title');
+
+        $this->assertEquals(2, count($result));
+        $this->assertEquals('Fruits', $result[0]->getTitle());
+        $this->assertEquals('Vegitables', $result[1]->getTitle());
+
+        // Get ALL nodes
+        $result = $repo->getChildren(null, false, 'title');
+
+        $this->assertEquals(6, count($result));
+        $this->assertEquals('Carrots', $result[0]->getTitle());
+        $this->assertEquals('Food', $result[1]->getTitle());
+        $this->assertEquals('Fruits', $result[2]->getTitle());
+        $this->assertEquals('Potatoes', $result[3]->getTitle());
+        $this->assertEquals('Sports', $result[4]->getTitle());
+        $this->assertEquals('Vegitables', $result[5]->getTitle());
+    }
+
+    /**
+     * @test
+     */
+    function getTree()
+    {
+        $repo = $this->em->getRepository(self::CATEGORY);
+        $tree = $repo->getTree();
+
+        $this->assertEquals(6, count($tree));
+        $this->assertEquals('Food', $tree[0]->getTitle());
+        $this->assertEquals('Fruits', $tree[1]->getTitle());
+        $this->assertEquals('Vegitables', $tree[2]->getTitle());
+        $this->assertEquals('Carrots', $tree[3]->getTitle());
+        $this->assertEquals('Potatoes', $tree[4]->getTitle());
+        $this->assertEquals('Sports', $tree[5]->getTitle());
+    }
+
+    protected function getUsedEntityFixtures()
+    {
+        return array(
+            self::CATEGORY
+        );
+    }
+
+    public function createCategory()
+    {
+        $class = self::CATEGORY;
+        return new $class;
+    }
+
+    private function populate()
+    {
+        $root = $this->createCategory();
+        $root->setTitle("Food");
+
+        $root2 = $this->createCategory();
+        $root2->setTitle("Sports");
+
+        $child = $this->createCategory();
+        $child->setTitle("Fruits");
+        $child->setParent($root);
+
+        $child2 = $this->createCategory();
+        $child2->setTitle("Vegitables");
+        $child2->setParent($root);
+
+        $childsChild = $this->createCategory();
+        $childsChild->setTitle("Carrots");
+        $childsChild->setParent($child2);
+
+        $potatoes = $this->createCategory();
+        $potatoes->setTitle("Potatoes");
+        $potatoes->setParent($child2);
+
+        $this->em->persist($root);
+        $this->em->persist($root2);
+        $this->em->persist($child);
+        $this->em->persist($child2);
+        $this->em->persist($childsChild);
+        $this->em->persist($potatoes);
+        $this->em->flush();
+    }
+}