Jelajahi Sumber

[Closure Table] Fixed some typos

Gustavo Adrian 14 tahun lalu
induk
melakukan
4ccf731b88

+ 63 - 0
lib/Gedmo/Tree/Entity/Repository/ClosureTreeRepository.php

@@ -0,0 +1,63 @@
+<?php
+
+namespace Gedmo\Tree\Entity\Repository;
+
+use Gedmo\Tree\AbstractTreeRepository,
+    Doctrine\ORM\Query,
+    Gedmo\Tree\Strategy,
+    Gedmo\Tree\Strategy\ORM\Closure,
+    Doctrine\ORM\Proxy\Proxy;
+
+/**
+ * The ClosureTreeRepository has some useful functions
+ * to interact with Closure tree. Repository uses
+ * the strategy used by listener
+ *
+ * @author Gustavo Adrian <comfortablynumb84@gmail.com> 
+ * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
+ * @package Gedmo.Tree.Entity.Repository
+ * @subpackage ClosureRepository
+ * @link http://www.gediminasm.org
+ * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
+ */
+class ClosureTreeRepository extends AbstractTreeRepository
+{
+    /**
+     * Counts the children of given TreeNode
+     * 
+     * @param object $node - if null counts all records in tree
+     * @param boolean $direct - true to count only direct children
+     * @return integer
+     */ 
+    public function childCount( $node = null, $direct = false )
+    {
+        $meta 			= $this->getClassMetadata();
+		$qb 			= $this->_em->createQueryBuilder();
+		$config 		= $this->listener->getConfiguration( $this->_em, $meta->name );
+		$closureMeta	= $this->_em->getClassMetadata( $config[ 'closure' ] );
+		$table			= $closureMeta->getTableName();
+		$nodeID 		= $meta->getSingleIdentifierFieldName();
+		$id				= $meta->getReflectionProperty( $nodeID )->getValue( $node );
+		
+		$qb->select( 'COUNT( c.id )' )
+			->from( $table, 'c' )
+			->where( 'c.ancestor = :node_id' );
+		
+		if ( $direct === true )
+		{
+			$qb->andWhere( 'c.depth = 1' );
+		}
+		
+		$qb->setParameter( 'node_id', $id );
+		
+        return $qb->getQuery()->getSingleScalarResult();
+    }
+	
+	/**
+     * {@inheritdoc}
+     */
+    protected function validates()
+    {
+        return $this->listener->getStrategy($this->_em, $this->getClassMetadata()->name)->getName() === Strategy::CLOSURE;
+    }
+}

+ 1 - 1
lib/Gedmo/Tree/Mapping/Driver/Annotation.php

@@ -228,7 +228,7 @@ class Annotation implements Driver
     private function validateClosureTreeMetadata(ClassMetadata $meta, array $config)
     {
         if (is_array($meta->identifier) && count($meta->identifier) > 1) {
-            throw new InvalidMappingException("Tree does not support composite indentifiers in class - {$meta->name}");
+            throw new InvalidMappingException("Tree does not support composite identifiers in class - {$meta->name}");
         }
         
         $missingFields = array();

+ 26 - 41
lib/Gedmo/Tree/Strategy/ORM/Closure.php

@@ -9,17 +9,15 @@ use Gedmo\Tree\Strategy,
 
 /**
  * This strategy makes tree act like
- * nested set.
- * 
- * This behavior can inpact the performance of your application
- * since nested set trees are slow on inserts and updates.
+ * a closure table.
  * 
  * Some Tree logic is copied from -
  * CakePHP: Rapid Development Framework (http://cakephp.org)
  * 
+ * @author Gustavo Adrian <comfortablynumb84@gmail.com>
  * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  * @package Gedmo.Tree.Strategy.ORM
- * @subpackage Nested
+ * @subpackage Closure
  * @link http://www.gediminasm.org
  * @license MIT License (http://www.opensource.org/licenses/mit-license.php)
  */
@@ -75,18 +73,14 @@ class Closure implements Strategy
     /**
      * {@inheritdoc}
      */
-    public function processPostPersist($em, $entity)
+    public function processPostPersist( $em, $entity )
     {        
-        if (count($this->pendingChildNodeInserts)) {
-            while ($entity = array_shift($this->pendingChildNodeInserts)) {
-                $this->insertNode($em, $entity);
+        if ( count( $this->pendingChildNodeInserts ) ) 
+		{
+            while ( $entity = array_shift( $this->pendingChildNodeInserts ) ) 
+			{
+                $this->insertNode( $em, $entity );
             }
-            
-            //$meta = $em->getClassMetadata(get_class($entity));
-            //$config = $this->listener->getConfiguration($em, $meta->name);
-            //$closureMeta = $em->getClassMetadata($config['closure']);
-            
-            
         }
     }
     
@@ -99,19 +93,20 @@ class Closure implements Strategy
         $closureMeta = $em->getClassMetadata($config['closure']);
         $entries = array();
 		
-		// If node has children it means it already has a self referencing row, so we skip the insert of it
+		// If node has children it means it already has a self referencing row, so we skip its insertion
 		if ( $addNodeChildrenToAncestors === false )
 		{
 			$entries[] = array(
-				'ancestor' => $id,
-				'descendant' => $id,
-				'depth' => 0
+				'ancestor'		=> $id,
+				'descendant' 	=> $id,
+				'depth' 		=> 0
 			);
 		}
 		
-        $parent = $meta->getReflectionProperty($config['parent'])->getValue($entity);
+        $parent = $meta->getReflectionProperty( $config[ 'parent' ] )->getValue( $entity );
 		
-        if ($parent) {
+        if ( $parent ) 
+		{
             $parentId = $meta->getReflectionProperty($identifier)->getValue($parent);
             $dql = "SELECT c.ancestor, c.depth FROM {$closureMeta->name} c";
             $dql .= " WHERE c.descendant = {$parentId}";
@@ -168,15 +163,15 @@ class Closure implements Strategy
     
     public function updateNode(EntityManager $em, $entity, array $change)
     {
-        $meta = $em->getClassMetadata(get_class($entity));
-        $config = $this->listener->getConfiguration($em, $meta->name);
-        $closureMeta = $em->getClassMetadata($config['closure']);
-        $oldParent = $change[0];
-        $nodeId = $this->extractIdentifier($em, $entity);
-        //$oldParentId = $this->extractIdentifier($em, $oldParent);
-        
-        $table = $closureMeta->getTableName();
-        if ($oldParent) {
+        $meta 			= $em->getClassMetadata(get_class($entity));
+        $config 		= $this->listener->getConfiguration($em, $meta->name);
+        $closureMeta 	= $em->getClassMetadata($config['closure']);
+        $oldParent 		= $change[ 0 ];
+        $nodeId 		= $this->extractIdentifier($em, $entity);
+        $table 			= $closureMeta->getTableName();
+		
+        if ( $oldParent ) 
+		{
             $this->removeClosurePathsOfNodeID( $em, $table, $nodeId );
 			
 			$this->insertNode( $em, $entity, true );
@@ -189,21 +184,11 @@ class Closure implements Strategy
 	/**
      * {@inheritdoc}
      */
-    public function processScheduledDelete($em, $entity)
+    public function processScheduledDelete( $em, $entity )
     {
 		$this->removeNode( $em, $entity );
 	}
 	
-	public function postRemove( EventArgs $args )
-	{
-		$em = $this->getObjectManager($args);
-		
-		foreach ( $this->pendingNodesForRemove as $node )
-		{
-			$this->removeNode( $em, $node );
-		}
-	}
-	
 	public function removeNode( EntityManager $em, $entity, $maintainSelfReferencingRow = false, $maintainSelfReferencingRowOfChildren = false )
 	{
 		$meta 			= $em->getClassMetadata( get_class( $entity ) );

+ 121 - 0
tests/Gedmo/Tree/ClosureTreeRepositoryTest.php

@@ -0,0 +1,121 @@
+<?php
+
+namespace Gedmo\Tree;
+
+use Doctrine\Common\Util\Debug;
+use Tree\Fixture\Closure\Category;
+use Tool\Logging\DBAL\QueryAnalyzer;
+
+/**
+ * These are tests for Tree behavior
+ * 
+ * @author Gustavo Adrian <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 ClosureTreeRepositoryTest extends \PHPUnit_Framework_TestCase
+{
+    const TEST_ENTITY_CLASS = "Tree\Fixture\Closure\Category";
+    const TEST_CLOSURE_CLASS = "Tree\Fixture\Closure\CategoryClosure";
+    const TEST_BASE_CLOSURE_CLASS = "Gedmo\Tree\Entity\AbstractClosure";
+    private $em;
+
+    public function setUp()
+    {        
+        $config = new \Doctrine\ORM\Configuration();
+        $config->setMetadataCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
+        $config->setQueryCacheImpl(new \Doctrine\Common\Cache\ArrayCache);
+        $config->setProxyDir(__DIR__ . '/Proxy');
+        $config->setProxyNamespace('Gedmo\Tree\Proxies');
+        $config->setMetadataDriverImpl($config->newDefaultAnnotationDriver());
+
+        /*$conn = array(
+            'driver' => 'pdo_sqlite',
+            'memory' => true,
+        );*/
+        
+        $conn = array(
+            'driver' => 'pdo_mysql',
+            'host' => '127.0.0.1',
+            'dbname' => 'closure',
+            'user' => 'root',
+            'password' => 'B9jt12h0'
+        );
+        
+        $evm = new \Doctrine\Common\EventManager();
+        $treeListener = new TreeListener(TreeListener::TYPE_CLOSURE);
+        $evm->addEventSubscriber($treeListener);
+        $this->em = \Doctrine\ORM\EntityManager::create($conn, $config, $evm);
+        
+		$schema	= array(
+            $this->em->getClassMetadata(self::TEST_BASE_CLOSURE_CLASS),
+            $this->em->getClassMetadata(self::TEST_CLOSURE_CLASS),
+            $this->em->getClassMetadata(self::TEST_ENTITY_CLASS),
+        );
+        $schemaTool = new \Doctrine\ORM\Tools\SchemaTool($this->em);
+        $schemaTool->dropSchema( $schema );
+        $schemaTool->createSchema( $schema );
+        
+        $this->analyzer = new QueryAnalyzer(
+            $this->em->getConnection()->getDatabasePlatform()
+        );
+        $config->setSQLLogger($this->analyzer);
+		
+		$this->populate();
+    }
+    
+    public function test_childCount_returnsNumberOfChilds()
+    {        
+        $repo 		= $this->em->getRepository( self::TEST_ENTITY_CLASS );
+        $food 		= $repo->findOneByTitle( 'Food' );
+        die( var_dump( get_class( $repo ) ) );
+        $childCount = $repo->childCount( $food );
+		
+		$this->assertEquals( $childCount, 4 );
+    }
+    
+    
+    
+    private function populate()
+    {
+        $root = new Category();
+        $root->setTitle("Food");
+		$this->food = $root;
+        
+        $root2 = new Category();
+        $root2->setTitle("Sports");
+		$this->sports = $root2;
+        
+        $child = new Category();
+        $child->setTitle("Fruits");
+        $child->setParent($root);
+		$this->fruits = $child;
+        
+        $child2 = new Category();
+        $child2->setTitle("Vegitables");
+        $child2->setParent($root);
+		$this->vegitables = $child2;
+        
+        $childsChild = new Category();
+        $childsChild->setTitle("Carrots");
+        $childsChild->setParent($child2);
+		$this->carrots = $childsChild;
+        
+        $potatoes = new Category();
+        $potatoes->setTitle("Potatoes");
+        $potatoes->setParent($child2);
+		$this->potatoes = $potatoes;
+        
+        $this->em->persist($this->food);
+        $this->em->persist($this->sports);
+        $this->em->persist($this->fruits);
+        $this->em->persist($this->vegitables);
+        $this->em->persist($this->carrots);
+        $this->em->persist($this->potatoes);
+		
+        $this->em->flush();
+		$this->em->clear();
+    }
+}

+ 2 - 1
tests/Gedmo/Tree/ClosureTreeTest.php

@@ -8,7 +8,8 @@ use Tool\Logging\DBAL\QueryAnalyzer;
 
 /**
  * These are tests for Tree behavior
- * 
+ *
+ * @author Gustavo Adrian <comfortablynumb84@gmail.com> 
  * @author Gediminas Morkevicius <gediminas.morkevicius@gmail.com>
  * @package Gedmo.Tree
  * @link http://www.gediminasm.org

+ 1 - 1
tests/Gedmo/Tree/Fixture/Closure/CategoryClosure.php

@@ -10,4 +10,4 @@ use Gedmo\Tree\Entity\AbstractClosure;
 class CategoryClosure extends AbstractClosure
 {
     
-}
+}