/** * Checks if the nested set fix is required * @param EntityManager $em * @param OutputInterface $output * @param string $entityName * @return boolean */ protected function isFixRequired(EntityManager $em, $output, $entityName) { $repository = $em->getRepository($entityName); if (!$repository instanceof RepositoryInterface) { $output->writeln('<error>The entity name isn\'t configured to be in nested set'); return false; } $nestedRepository = $repository->getNestedSetRepository(); $filter = $nestedRepository->createSearchCondition(); $order = $nestedRepository->createSelectOrderRule(); // Order by left index $order->byLeftAscending(); /* @var $nestedRepository DoctrineRepository */ $qb = $nestedRepository->createSearchQueryBuilder($filter, $order); $qb->select('e'); $query = $qb->getQuery(); $query->setHint(Query::HINT_FORCE_PARTIAL_LOAD, true); $query->setHydrationMode(Query::HYDRATE_SIMPLEOBJECT); $records = $query->getResult(); // Keeps pile of current parents $parents = array(); $arrayRepository = new ArrayRepository(); $nodes = array(); /* @var $nodes ValidationArrayNode[] */ foreach ($records as $record) { if (!$record instanceof EntityNodeInterface) { throw new \UnexpectedValueException(sprintf('Expecting DoctrineNode, [%s] received.', get_class($record))); } $level = $record->getLevel(); $node = new ValidationArrayNode($record); $nodes[] = $node; $arrayRepository->add($node); // Fixing strongly relies on the level if ($level > 0) { $parent = null; if (isset($parents[$level - 1])) { $parent = $parents[$level - 1]; } else { // Too fast level drop, takes the deepest parent $parent = end($parents); } if (!empty($parent)) { $parent->addChild($node); } } $newLevel = $node->getLevel(); // Removing historical parents deeper than the current node $parents = array_slice($parents, 0, $newLevel); $parents[$newLevel] = $node; } $fixRequired = false; foreach ($nodes as $node) { if (!$node->isOk()) { // Output index changes suggested $output->writeln("Node " . $node->getNodeTitle()); $dbEntity = $em->find($entityName, $node->getId()); /* @var $dbEntity EntityNodeInterface */ if (!$node->isLeaf() && $node->isOriginallyWithLeafInterface()) { $children = $node->getChildren(); foreach ($children as $child) { if (!$node->isOk()) { $child->moveAsNextSiblingOf($node); } else { $child->moveAsPrevSiblingOf($node); } } } else { // Overwrite the indices $dbEntity->setLeftValue($node->getLeftValue()); $dbEntity->setRightValue($node->getRightValue()); $dbEntity->setLevel($node->getLevel()); } $fixRequired = true; } } // Flushing, commit or rollback done later if ($fixRequired) { $em->flush(); } return $fixRequired; }
/** * Additionally it will refresh the nodes from the database because index * update has been made using DQL already * {@inheritdoc} */ protected function moveNode(Node\NodeInterface $item, $moveLeft, $moveRight, $moveLevel) { // $newLeft = $item->getLeftValue() + (int) $moveLeft; // $newRight = $item->getRightValue() + (int) $moveRight; // $newLevel = $item->getLevel() + (int) $moveLevel; // // Call original local move method for items not in the database yet parent::moveNode($item, $moveLeft, $moveRight, $moveLevel); // In case of entity update, make the new nested set values to be ignored $insert = $this->entityManager->getUnitOfWork()->isScheduledForInsert($item); if (!$insert) { $oid = spl_object_hash($item); $this->entityManager->getUnitOfWork()->setOriginalEntityProperty($oid, 'level', $item->getLevel()); $this->entityManager->getUnitOfWork()->setOriginalEntityProperty($oid, 'right', $item->getRightValue()); $this->entityManager->getUnitOfWork()->setOriginalEntityProperty($oid, 'left', $item->getLeftValue()); } // // if ($insert) { // // Call original local move method for items not in the database yet // parent::moveNode($item, $moveLeft, $moveRight, $moveLevel); // } else { // // Refresh so additional UPDATE-s are not executed on the server // $this->entityManager->refresh($item); // } // // Double check the values, should not happen // if ($item->getLeftValue() != $newLeft) { // $item->setLeftValue($newLeft); // } // if ($item->getRightValue() != $newRight) { // $item->setRightValue($newRight); // } // if ($item->getLevel() != $newLevel) { // $item->setLevel($newLevel); // } }