function let(UserContext $userContext, EntityManager $em, ClassMetadata $classMetadata, EventManager $eventManager, TreeListener $treeListener, Nested $strategy)
 {
     $classMetadata->name = 'category';
     $userContext->getCurrentLocaleCode()->willReturn('en_US');
     $em->getEventManager()->willReturn($eventManager);
     $eventManager->getListeners()->willReturn([[$treeListener]]);
     $treeListener->getStrategy(Argument::cetera())->willReturn($strategy);
     $treeListener->getConfiguration(Argument::cetera())->willReturn(['parent' => 'parent', 'left' => 'left']);
     $this->beConstructedWith($userContext, $em, $classMetadata);
 }
 public function testTreeMetadata()
 {
     $meta = $this->em->getClassMetadata('Mapping\\Fixture\\Xml\\ClosureTree');
     $config = $this->tree->getConfiguration($this->em, $meta->name);
     $this->assertArrayHasKey('strategy', $config);
     $this->assertEquals('closure', $config['strategy']);
     $this->assertArrayHasKey('closure', $config);
     $this->assertEquals('Mapping\\Fixture\\ClosureTreeClosure', $config['closure']);
     $this->assertArrayHasKey('parent', $config);
     $this->assertEquals('parent', $config['parent']);
 }
예제 #3
0
 public function getSubscribedEvents()
 {
     $events = parent::getSubscribedEvents();
     unset($events[array_search('loadClassMetadata', $events)]);
     $events[] = Events::loadClassMetadata;
     return $events;
 }
예제 #4
0
 /**
  * {@inheritDoc}
  */
 public function buildTreeArray(array $nodes)
 {
     $meta = $this->getClassMetadata();
     $config = $this->listener->getConfiguration($this->om, $meta->name);
     $nestedTree = array();
     $l = 0;
     if (count($nodes) > 0) {
         // Node Stack. Used to help building the hierarchy
         $stack = array();
         foreach ($nodes as $child) {
             $item = $child;
             $item[$this->childrenIndex] = array();
             // Number of stack items
             $l = count($stack);
             // Check if we're dealing with different levels
             while ($l > 0 && $stack[$l - 1][$config['level']] >= $item[$config['level']]) {
                 array_pop($stack);
                 $l--;
             }
             // Stack is empty (we are inspecting the root)
             if ($l == 0) {
                 // Assigning the root child
                 $i = count($nestedTree);
                 $nestedTree[$i] = $item;
                 $stack[] =& $nestedTree[$i];
             } else {
                 // Add child to parent
                 $i = count($stack[$l - 1][$this->childrenIndex]);
                 $stack[$l - 1][$this->childrenIndex][$i] = $item;
                 $stack[] =& $stack[$l - 1][$this->childrenIndex][$i];
             }
         }
     }
     return $nestedTree;
 }
 public function testTreeMetadata()
 {
     $meta = $this->em->getClassMetadata('Mapping\\Fixture\\Xml\\NestedTree');
     $config = $this->tree->getConfiguration($this->em, $meta->name);
     $this->assertArrayHasKey('strategy', $config);
     $this->assertEquals('nested', $config['strategy']);
     $this->assertArrayHasKey('left', $config);
     $this->assertEquals('left', $config['left']);
     $this->assertArrayHasKey('right', $config);
     $this->assertEquals('right', $config['right']);
     $this->assertArrayHasKey('level', $config);
     $this->assertEquals('level', $config['level']);
     $this->assertArrayHasKey('root', $config);
     $this->assertEquals('root', $config['root']);
     $this->assertArrayHasKey('parent', $config);
     $this->assertEquals('parent', $config['parent']);
 }
 function let(EntityManager $em, Connection $connection, Statement $statement, ClassMetadata $classMetadata, EventManager $eventManager, TreeListener $treeListener, Nested $strategy, \ReflectionProperty $property)
 {
     $connection->prepare(Argument::any())->willReturn($statement);
     $em->getClassMetadata(Argument::any())->willReturn($classMetadata);
     $classMetadata->name = 'channel';
     $classMetadata->getReflectionProperty(Argument::any())->willReturn($property);
     $em->getConnection()->willReturn($connection);
     $em->getEventManager()->willReturn($eventManager);
     $em->getClassMetadata()->willReturn($classMetadata);
     $strategy->getName()->willReturn(Strategy::NESTED);
     $strategy->setNodePosition(Argument::cetera())->willReturn(null);
     $treeListener->getStrategy(Argument::cetera())->willReturn($strategy);
     $configuration = ['parent' => 'parent', 'left' => 'left'];
     $treeListener->getConfiguration(Argument::cetera())->willReturn($configuration);
     $eventManager->getListeners()->willReturn([[$treeListener]]);
     $this->beConstructedWith($em, $classMetadata);
 }
예제 #7
0
파일: Nested.php 프로젝트: 7rin0/SF3
 /**
  * Shift range of right and left values on tree
  * depending on tree level difference also
  *
  * @param EntityManager  $em
  * @param string         $class
  * @param integer        $first
  * @param integer        $last
  * @param integer        $delta
  * @param integer|string $root
  * @param integer|string $destRoot
  * @param integer        $levelDelta
  */
 public function shiftRangeRL(EntityManager $em, $class, $first, $last, $delta, $root = null, $destRoot = null, $levelDelta = null)
 {
     $meta = $em->getClassMetadata($class);
     $config = $this->listener->getConfiguration($em, $class);
     $sign = $delta >= 0 ? ' + ' : ' - ';
     $absDelta = abs($delta);
     $levelSign = $levelDelta >= 0 ? ' + ' : ' - ';
     $absLevelDelta = abs($levelDelta);
     $qb = $em->createQueryBuilder();
     $qb->update($config['useObjectClass'], 'node')->set('node.' . $config['left'], "node.{$config['left']} {$sign} {$absDelta}")->set('node.' . $config['right'], "node.{$config['right']} {$sign} {$absDelta}")->where($qb->expr()->gte('node.' . $config['left'], $first))->andWhere($qb->expr()->lte('node.' . $config['right'], $last));
     if (isset($config['root'])) {
         $qb->set('node.' . $config['root'], ':drid');
         $qb->setParameter('drid', $destRoot);
         $qb->andWhere($qb->expr()->eq('node.' . $config['root'], ':rid'));
         $qb->setParameter('rid', $root);
     }
     if (isset($config['level'])) {
         $qb->set('node.' . $config['level'], "node.{$config['level']} {$levelSign} {$absLevelDelta}");
     }
     $qb->getQuery()->getSingleScalarResult();
     // update in memory nodes increases performance, saves some IO
     foreach ($em->getUnitOfWork()->getIdentityMap() as $className => $nodes) {
         // for inheritance mapped classes, only root is always in the identity map
         if ($className !== $meta->rootEntityName) {
             continue;
         }
         foreach ($nodes as $node) {
             if ($node instanceof Proxy && !$node->__isInitialized__) {
                 continue;
             }
             $nodeMeta = $em->getClassMetadata(get_class($node));
             if (!array_key_exists($config['left'], $nodeMeta->getReflectionProperties())) {
                 continue;
             }
             $left = $meta->getReflectionProperty($config['left'])->getValue($node);
             $right = $meta->getReflectionProperty($config['right'])->getValue($node);
             $currentRoot = isset($config['root']) ? $meta->getReflectionProperty($config['root'])->getValue($node) : null;
             if ($currentRoot === $root && $left >= $first && $right <= $last) {
                 $oid = spl_object_hash($node);
                 $uow = $em->getUnitOfWork();
                 $meta->getReflectionProperty($config['left'])->setValue($node, $left + $delta);
                 $uow->setOriginalEntityProperty($oid, $config['left'], $left + $delta);
                 $meta->getReflectionProperty($config['right'])->setValue($node, $right + $delta);
                 $uow->setOriginalEntityProperty($oid, $config['right'], $right + $delta);
                 if (isset($config['root'])) {
                     $meta->getReflectionProperty($config['root'])->setValue($node, $destRoot);
                     $uow->setOriginalEntityProperty($oid, $config['root'], $destRoot);
                 }
                 if (isset($config['level'])) {
                     $level = $meta->getReflectionProperty($config['level'])->getValue($node);
                     $meta->getReflectionProperty($config['level'])->setValue($node, $level + $levelDelta);
                     $uow->setOriginalEntityProperty($oid, $config['level'], $level + $levelDelta);
                 }
             }
         }
     }
 }
예제 #8
0
 /**
  * @param EventArgs $eventArgs
  * @return void
  */
 public function loadClassMetadata(EventArgs $eventArgs)
 {
     $meta = $eventArgs->getClassMetadata();
     $ea = $this->getEventAdapter($eventArgs);
     if (is_subclass_of($meta->getName(), $ea->getHierarchyClassName(), true)) {
         $ea->mapHierarchy($meta);
     }
     parent::loadClassMetadata($eventArgs);
 }
예제 #9
0
 /**
  * Update node and closures
  *
  * @param EntityManager $em
  * @param object        $node
  * @param object        $oldParent
  */
 public function updateNode(EntityManager $em, $node, $oldParent)
 {
     $wrapped = AbstractWrapper::wrap($node, $em);
     $meta = $wrapped->getMetadata();
     $config = $this->listener->getConfiguration($em, $meta->name);
     $closureMeta = $em->getClassMetadata($config['closure']);
     $nodeId = $wrapped->getIdentifier();
     $parent = $wrapped->getPropertyValue($config['parent']);
     $table = $closureMeta->getTableName();
     $conn = $em->getConnection();
     // ensure integrity
     if ($parent) {
         $dql = "SELECT COUNT(c) FROM {$closureMeta->name} c";
         $dql .= " WHERE c.ancestor = :node";
         $dql .= " AND c.descendant = :parent";
         $q = $em->createQuery($dql);
         $q->setParameters(compact('node', 'parent'));
         if ($q->getSingleScalarResult()) {
             throw new \Gedmo\Exception\UnexpectedValueException("Cannot set child as parent to node: {$nodeId}");
         }
     }
     if ($oldParent) {
         $subQuery = "SELECT c2.id FROM {$table} c1";
         $subQuery .= " JOIN {$table} c2 ON c1.descendant = c2.descendant";
         $subQuery .= " WHERE c1.ancestor = :nodeId AND c2.depth > c1.depth";
         $ids = $conn->fetchAll($subQuery, compact('nodeId'));
         if ($ids) {
             $ids = array_map(function ($el) {
                 return $el['id'];
             }, $ids);
         }
         // using subquery directly, sqlite acts unfriendly
         $query = "DELETE FROM {$table} WHERE id IN (" . implode(', ', $ids) . ")";
         if (!$conn->executeQuery($query)) {
             throw new RuntimeException('Failed to remove old closures');
         }
     }
     if ($parent) {
         $wrappedParent = AbstractWrapper::wrap($parent, $em);
         $parentId = $wrappedParent->getIdentifier();
         $query = "SELECT c1.ancestor, c2.descendant, (c1.depth + c2.depth + 1) AS depth";
         $query .= " FROM {$table} c1, {$table} c2";
         $query .= " WHERE c1.descendant = :parentId";
         $query .= " AND c2.ancestor = :nodeId";
         $closures = $conn->fetchAll($query, compact('nodeId', 'parentId'));
         foreach ($closures as $closure) {
             if (!$conn->insert($table, $closure)) {
                 throw new RuntimeException('Failed to insert new Closure record');
             }
         }
     }
     if (isset($config['level'])) {
         $this->pendingNodesLevelProcess[$nodeId] = $node;
     }
 }
 public function testTreeMetadata()
 {
     $meta = $this->em->getClassMetadata('Mapping\\Fixture\\Xml\\MaterializedPathTree');
     $config = $this->tree->getConfiguration($this->em, $meta->name);
     $this->assertArrayHasKey('strategy', $config);
     $this->assertEquals('materializedPath', $config['strategy']);
     $this->assertArrayHasKey('activate_locking', $config);
     $this->assertTrue($config['activate_locking']);
     $this->assertArrayHasKey('locking_timeout', $config);
     $this->assertEquals(10, $config['locking_timeout']);
     $this->assertArrayHasKey('level', $config);
     $this->assertEquals('level', $config['level']);
     $this->assertArrayHasKey('parent', $config);
     $this->assertEquals('parent', $config['parent']);
     $this->assertArrayHasKey('path_source', $config);
     $this->assertEquals('title', $config['path_source']);
     $this->assertArrayHasKey('path', $config);
     $this->assertEquals('path', $config['path']);
     $this->assertArrayHasKey('lock_time', $config);
     $this->assertEquals('lockTime', $config['lock_time']);
 }
예제 #11
0
 public function testYamlMaterializedPathMapping()
 {
     $meta = $this->em->getClassMetadata(self::YAML_MATERIALIZED_PATH_CATEGORY);
     $config = $this->listener->getConfiguration($this->em, $meta->name);
     $this->assertArrayHasKey('strategy', $config);
     $this->assertEquals('materializedPath', $config['strategy']);
     $this->assertArrayHasKey('parent', $config);
     $this->assertEquals('parent', $config['parent']);
     $this->assertArrayHasKey('activate_locking', $config);
     $this->assertTrue($config['activate_locking']);
     $this->assertArrayHasKey('locking_timeout', $config);
     $this->assertEquals(3, $config['locking_timeout']);
     $this->assertArrayHasKey('level', $config);
     $this->assertEquals('level', $config['level']);
     $this->assertArrayHasKey('path', $config);
     $this->assertEquals('path', $config['path']);
     $this->assertArrayHasKey('path_separator', $config);
     $this->assertEquals(',', $config['path_separator']);
 }
예제 #12
0
 /**
  * {@inheritdoc}
  */
 public function persistAsNextSiblingOf(MenuItemInterface $node, MenuItemInterface $sibling)
 {
     $wrapped = new EntityWrapper($node, $this->_em);
     $meta = $this->getClassMetadata();
     $config = $this->treeListener->getConfiguration($this->_em, $meta->name);
     $wrappedSibling = new EntityWrapper($sibling, $this->_em);
     $newParent = $wrappedSibling->getPropertyValue($config['parent']);
     if (null === $newParent && isset($config['root'])) {
         throw new UnexpectedValueException('Cannot persist sibling for a root node, tree operation is not possible');
     }
     $node->sibling = $sibling;
     $sibling = $newParent;
     $wrapped->setPropertyValue($config['parent'], $sibling);
     $wrapped->setPropertyValue($config['left'], 0);
     $oid = spl_object_hash($node);
     $this->treeListener->getStrategy($this->_em, $meta->name)->setNodePosition($oid, 'NextSibling');
     $this->_em->persist($node);
     return $this;
 }
예제 #13
0
 public function testYamlMaterializedPathMapping()
 {
     if (!extension_loaded('apc') || !ini_get('apc.enable_cli')) {
         $this->markTestSkipped('APC extension is not loaded.');
     }
     $meta = $this->em->getClassMetadata(self::YAML_MATERIALIZED_PATH_CATEGORY);
     $config = $this->listener->getConfiguration($this->em, $meta->name);
     $this->assertArrayHasKey('strategy', $config);
     $this->assertEquals('materializedPath', $config['strategy']);
     $this->assertArrayHasKey('parent', $config);
     $this->assertEquals('parent', $config['parent']);
     $this->assertArrayHasKey('activate_locking', $config);
     $this->assertTrue($config['activate_locking']);
     $this->assertArrayHasKey('locking_timeout', $config);
     $this->assertEquals(3, $config['locking_timeout']);
     $this->assertArrayHasKey('level', $config);
     $this->assertEquals('level', $config['level']);
     $this->assertArrayHasKey('path', $config);
     $this->assertEquals('path', $config['path']);
     $this->assertArrayHasKey('path_separator', $config);
     $this->assertEquals(',', $config['path_separator']);
 }
예제 #14
0
 /**
  * @param EventManager           $manager
  * @param EntityManagerInterface $em
  * @param Reader                 $reader
  */
 public function addSubscribers(EventManager $manager, EntityManagerInterface $em, Reader $reader)
 {
     $subscriber = new TreeListener();
     $subscriber->setAnnotationReader($reader);
     $manager->addEventSubscriber($subscriber);
 }
예제 #15
0
 /**
  *
  * @return EntityManager
  */
 public function getEntityManager()
 {
     $cache = new DoctrineCache\ArrayCache();
     $annotationReader = new AnnotationReader();
     $cachedAnnotationReader = new CachedReader($annotationReader, $cache);
     // create a driver chain for metadata reading
     $driverChain = new MappingDriverChain();
     // load superclass metadata mapping only, into driver chain
     // also registers Gedmo annotations.NOTE: you can personalize it
     Gedmo\DoctrineExtensions::registerAbstractMappingIntoDriverChainORM($driverChain, $cachedAnnotationReader);
     // now we want to register our application entities,
     // for that we need another metadata driver used for Entity namespace
     $annotationDriver = new AnnotationDriver($cachedAnnotationReader, $this->paths);
     $driverChain->addDriver($annotationDriver, $this->namespace);
     // general ORM configuration
     $isDevMode = $this->env != "production";
     $config = DoctrineSetup::createAnnotationMetadataConfiguration($this->paths, $isDevMode);
     $config->setMetadataCacheImpl($cache);
     $config->setQueryCacheImpl($cache);
     $config->setMetadataDriverImpl($driverChain);
     $config->setProxyDir($this->proxy_path);
     $config->setProxyNamespace($this->namespace . '\\Proxy');
     $config->setAutoGenerateProxyClasses($isDevMode);
     // Third, create event manager and hook prefered extension listeners
     $evm = new EventManager();
     // gedmo extension listeners
     // sluggable
     $sluggableListener = new Gedmo\Sluggable\SluggableListener();
     // you should set the used annotation reader to listener, to avoid creating new one for mapping drivers
     $sluggableListener->setAnnotationReader($cachedAnnotationReader);
     $evm->addEventSubscriber($sluggableListener);
     // tree
     $treeListener = new Gedmo\Tree\TreeListener();
     $treeListener->setAnnotationReader($cachedAnnotationReader);
     $evm->addEventSubscriber($treeListener);
     // loggable, not used in example
     $loggableListener = new Gedmo\Loggable\LoggableListener();
     $loggableListener->setAnnotationReader($cachedAnnotationReader);
     $loggableListener->setUsername('unknown');
     $evm->addEventSubscriber($loggableListener);
     // timestampable
     $timestampableListener = new Gedmo\Timestampable\TimestampableListener();
     $timestampableListener->setAnnotationReader($cachedAnnotationReader);
     $evm->addEventSubscriber($timestampableListener);
     // blameable
     $blameableListener = new Gedmo\Blameable\BlameableListener();
     $blameableListener->setAnnotationReader($cachedAnnotationReader);
     $blameableListener->setUserValue('unknown');
     // determine from your environment
     $evm->addEventSubscriber($blameableListener);
     // translatable - buggy !!!
     /*
     $translatableListener = new Gedmo\Translatable\TranslatableListener();
     // current translation locale should be set from session or hook later into the listener
     // most important, before entity manager is flushed
     $translatableListener->setTranslatableLocale('en');
     $translatableListener->setDefaultLocale('en');
     $translatableListener->setAnnotationReader($cachedAnnotationReader);
     $evm->addEventSubscriber($translatableListener);
     */
     // sortable, not used in example
     $sortableListener = new Gedmo\Sortable\SortableListener();
     $sortableListener->setAnnotationReader($cachedAnnotationReader);
     $evm->addEventSubscriber($sortableListener);
     // mysql set names UTF-8 if required
     $evm->addEventSubscriber(new \Doctrine\DBAL\Event\Listeners\MysqlSessionInit());
     // Finally, create entity manager
     return EntityManager::create($this->dbParams, $config, $evm);
 }
예제 #16
0
 /**
  * @param ObjectManager $om
  * @param TreeListener $listener
  * @param string $class
  * @return Strategy
  */
 private function getClassStrategy(ObjectManager $om, TreeListener $listener, $class)
 {
     if (array_key_exists($class, $this->classStrategies)) {
         return $this->classStrategies[$class];
     }
     $this->classStrategies[$class] = null;
     $classParents = array_merge(array($class), class_parents($class));
     foreach ($classParents as $parent) {
         try {
             $this->classStrategies[$class] = $listener->getStrategy($om, $parent);
             break;
         } catch (\Exception $e) {
             // we don't like to throw exception because there might be a strategy for class parents
         }
     }
     return $this->classStrategies[$class];
 }