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