/**
  * Persists node in given position strategy
  */
 protected function persistAs($node, $child = null, $position = Nested::FIRST_CHILD)
 {
     $em = $this->getEntityManager();
     $wrapped = new EntityWrapper($node, $em);
     $meta = $this->getClassMetadata();
     $config = $this->listener->getConfiguration($em, $meta->name);
     $siblingInPosition = null;
     if ($child !== null) {
         switch ($position) {
             case Nested::PREV_SIBLING:
             case Nested::NEXT_SIBLING:
                 $sibling = new EntityWrapper($child, $em);
                 $newParent = $sibling->getPropertyValue($config['parent']);
                 if (null === $newParent && isset($config['root'])) {
                     throw new UnexpectedValueException("Cannot persist sibling for a root node, tree operation is not possible");
                 }
                 $siblingInPosition = $child;
                 $child = $newParent;
                 break;
         }
         $wrapped->setPropertyValue($config['parent'], $child);
     }
     $wrapped->setPropertyValue($config['left'], 0);
     // simulate changeset
     $oid = spl_object_hash($node);
     $this->listener->getStrategy($em, $meta->name)->setNodePosition($oid, $position, $siblingInPosition);
     $em->persist($node);
     return $this;
 }
 /**
  * Allows the following 'virtual' methods:
  * - persistAsFirstChild($node)
  * - persistAsFirstChildOf($node, $parent)
  * - persistAsLastChild($node)
  * - persistAsLastChildOf($node, $parent)
  * - persistAsNextSibling($node)
  * - persistAsNextSiblingOf($node, $sibling)
  * - persistAsPrevSibling($node)
  * - persistAsPrevSiblingOf($node, $sibling)
  * Inherited virtual methods:
  * - find*
  *
  * @see \Doctrine\ORM\EntityRepository
  * @throws InvalidArgumentException - If arguments are invalid
  * @throws BadMethodCallException - If the method called is an invalid find* or persistAs* method
  *      or no find* either persistAs* method at all and therefore an invalid method call.
  * @return mixed - TreeNestedRepository if persistAs* is called
  */
 public function __call($method, $args)
 {
     if (substr($method, 0, 9) === 'persistAs') {
         if (!isset($args[0])) {
             throw new \Gedmo\Exception\InvalidArgumentException('Node to persist must be available as first argument');
         }
         $node = $args[0];
         $wrapped = new EntityWrapper($node, $this->_em);
         $meta = $this->getClassMetadata();
         $config = $this->listener->getConfiguration($this->_em, $meta->name);
         $position = substr($method, 9);
         if (substr($method, -2) === 'Of') {
             if (!isset($args[1])) {
                 throw new \Gedmo\Exception\InvalidArgumentException('If "Of" is specified you must provide parent or sibling as the second argument');
             }
             $parent = $args[1];
             $wrapped->setPropertyValue($config['parent'], $parent);
             $position = substr($position, 0, -2);
         }
         $wrapped->setPropertyValue($config['left'], 0);
         // simulate changeset
         $oid = spl_object_hash($node);
         $this->listener->getStrategy($this->_em, $meta->name)->setNodePosition($oid, $position);
         $this->_em->persist($node);
         return $this;
     }
     return parent::__call($method, $args);
 }
 /**
  * @param ChangeSet $changeset
  * @return bool|object
  */
 public function applyChangeSet(ChangeSet $changeset)
 {
     $now = new \DateTime();
     if ($changeset->getChangeAt() == null || $changeset->getChangeAt()->diff($now)->invert) {
         return false;
     }
     if ($changeset->getAction() == LoggableListener::ACTION_CREATE && $changeset->getObjectId() != null) {
         throw new \Exception("changeSet invalid {$changeset->getId()}  create with object id");
     }
     if ($changeset->getAction() != LoggableListener::ACTION_CREATE && $changeset->getObjectId() == null) {
         throw new \Exception("changeSet invalid {$changeset->getId()}  no objectId found but no create Action");
     }
     $data = $changeset->getData();
     if ($changeset->getObjectId() == null) {
         //create a new one
         $r = new \ReflectionClass($changeset->getObjectClass());
         $entity = $r->newInstanceWithoutConstructor();
     } else {
         //edit
         $entity = $this->_em->find($changeset->getObjectClass(), $changeset->getObjectId());
     }
     if ($changeset->getAction() == LoggableListener::ACTION_REMOVE) {
         //very rudimental remove... dont care about sitdeffects
         $this->_em->remove($entity);
         $this->_em->remove($changeset);
         $this->_em->flush();
         return true;
     }
     $wrapped = new EntityWrapper($entity, $this->_em);
     $objectMeta = $wrapped->getMetadata();
     foreach ($data as $field => $value) {
         if ($objectMeta->isSingleValuedAssociation($field)) {
             $mapping = $objectMeta->getAssociationMapping($field);
             $value = $value ? $this->_em->getReference($mapping['targetEntity'], $value) : null;
         }
         if (property_exists($changeset->getObjectClass(), $field)) {
             $wrapped->setPropertyValue($field, $value);
         }
     }
     if ($changeset->getObjectId() == null) {
         //MANY_TO_ONE create new one
         foreach ($objectMeta->getAssociationMappings() as $associationMapping) {
             if ($associationMapping['type'] != \Doctrine\ORM\Mapping\ClassMetadata::MANY_TO_ONE) {
                 continue;
             }
             $one = $objectMeta->getReflectionProperty($associationMapping['fieldName'])->getValue($entity);
             if (array_key_exists('inversedBy', $associationMapping)) {
                 $field = $associationMapping['inversedBy'];
                 $associationMeta = $this->_em->getClassMetadata($associationMapping['targetEntity']);
                 $associationMeta->getReflectionProperty($field)->getValue($one)->add($entity);
             }
         }
     }
     $object = $wrapped->getObject();
     $object->removeScheduledChangeDate();
     $this->_em->persist($object);
     $this->_em->remove($changeset);
     $this->_em->flush();
     return $object;
 }
 public function testManaged()
 {
     $test = $this->em->find(self::ARTICLE, array('id' => 1));
     $this->assertInstanceOf(self::ARTICLE, $test);
     $wrapped = new EntityWrapper($test, $this->em);
     $this->assertEquals(1, $wrapped->getIdentifier());
     $this->assertEquals('test', $wrapped->getPropertyValue('title'));
     $wrapped->setPropertyValue('title', 'changed');
     $this->assertEquals('changed', $wrapped->getPropertyValue('title'));
     $this->assertTrue($wrapped->hasValidIdentifier());
 }
 /**
  * Reverts given $entity to $revision by
  * restoring all fields from that $revision.
  * After this operation you will need to
  * persist and flush the $entity.
  *
  * @param object $entity
  * @param integer $version
  * @throws \Gedmo\Exception\UnexpectedValueException
  * @return void
  */
 public function revert($entity, $version = 1)
 {
     $wrapped = new EntityWrapper($entity, $this->_em);
     $objectMeta = $wrapped->getMetadata();
     $objectClass = $objectMeta->name;
     //$objectMeta = $this->_em->getClassMetadata($objectClass);
     $meta = $this->getClassMetadata();
     $dql = "SELECT log FROM {$meta->name} log";
     $dql .= " WHERE log.objectId = :objectId";
     $dql .= " AND log.objectClass = :objectClass";
     $dql .= " AND log.version <= :version";
     $dql .= " ORDER BY log.version ASC";
     $objectId = $wrapped->getIdentifier();
     $q = $this->_em->createQuery($dql);
     $q->setParameters(compact('objectId', 'objectClass', 'version'));
     $logs = $q->getResult();
     if ($logs) {
         $config = $this->getLoggableListener()->getConfiguration($this->_em, $objectMeta->name);
         $fields = $config['versioned'];
         $filled = false;
         while (($log = array_pop($logs)) && !$filled) {
             if ($data = $log->getData()) {
                 foreach ($data as $field => $value) {
                     if (in_array($field, $fields)) {
                         if ($objectMeta->isSingleValuedAssociation($field)) {
                             $mapping = $objectMeta->getAssociationMapping($field);
                             $value = $value ? $this->_em->getReference($mapping['targetEntity'], $value) : null;
                         }
                         $wrapped->setPropertyValue($field, $value);
                         unset($fields[array_search($field, $fields)]);
                     }
                 }
             }
             $filled = count($fields) === 0;
         }
         /*if (count($fields)) {
               throw new \Gedmo\Exception\UnexpectedValueException('Could not fully revert the entity to version: '.$version);
           }*/
     } else {
         throw new \Gedmo\Exception\UnexpectedValueException('Could not find any log entries under version: ' . $version);
     }
 }
 /**
  * {@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;
 }
 /**
  * Revert a Entity identified by $objectId and $objectClass to a specific $version
  * @param               $objectId
  * @param               $objectClass
  * @param               $version
  * @param EntityWrapper $wrapped
  * @param null          $softDeleteDateFieldName
  * @param bool          $deleteHistory if true, the revert will also delete all log entries since the reverted one
  * @param bool          $logRevert if logRevert is true, the revert will be logged
  */
 public function revertBy($objectId, $objectClass, $version, EntityWrapper $wrapped, $softDeleteDateFieldName = null, $deleteHistory = true, $logRevert = false)
 {
     $logs = $this->findLogs($objectId, $objectClass, $version);
     if (!$logs) {
         throw new \Gedmo\Exception\UnexpectedValueException('Could not find any log entries under version: ' . $version);
     }
     if (!$logRevert) {
         $this->getLoggableListener()->setEnabled(false);
     }
     while ($log = array_pop($logs)) {
         $action = $log->getAction();
         if ($action === 'create') {
             if (!$softDeleteDateFieldName) {
                 throw new \Gedmo\Exception\UnexpectedValueException('Cant revert to create: you have to use softdeletable to use this feature');
             }
             $wrapped->setPropertyValue($softDeleteDateFieldName, new \DateTime());
         } else {
             if ($action === 'remove') {
                 if (!$softDeleteDateFieldName) {
                     throw new \Gedmo\Exception\UnexpectedValueException('Cant revert to create: you have to use softdeletable to use this feature');
                 }
                 $wrapped->setPropertyValue($softDeleteDateFieldName, null);
             } else {
                 $this->revertObjectBySingleLog($log, $wrapped);
             }
         }
         $this->_em->flush();
         if ($deleteHistory) {
             if ($logRevert) {
                 $this->getLoggableListener()->setEnabled(false);
             }
             $this->_em->remove($log);
             if ($logRevert) {
                 $this->getLoggableListener()->setEnabled(true);
             }
         }
     }
     if (!$logRevert) {
         $this->getLoggableListener()->setEnabled(true);
     }
 }