/**
  * 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);
     //		}
 }