diff --git a/src/Opifer/Revisions/Model/Revision.php b/src/Opifer/Revisions/Model/Revision.php index fd92de0..67d8fd4 100644 --- a/src/Opifer/Revisions/Model/Revision.php +++ b/src/Opifer/Revisions/Model/Revision.php @@ -7,8 +7,57 @@ class Revision { - public $className; - public $revisionId; - public $revisionType; + protected $className; + protected $revisionId; + protected $revisionType; + protected $entity; + protected $data; -} \ No newline at end of file + /** + * @var \ReflectionClass + */ + protected $reflection; + + public function __construct($data, $entity) + { + $data = (array) $data; + $this->className = get_class($entity); + $this->entity = $entity; + $this->revisionId = $data['revision_id']; + $this->revisionType = $data['rev_type']; + $this->data = array_diff_key($data, ['revision_id', 'rev_type']); + $this->reflection = new \ReflectionClass($entity); + } + + public function getClassName() + { + return $this->className; + } + + public function getRevisionId() + { + return $this->revisionId; + } + + public function getRevisionType() + { + return $this->revisionType; + } + + public function __call($name, $arguments) + { + $property = lcfirst(substr($name, 3)); + if (strpos($name, 'get') === 0 && $this->reflection->hasMethod($name) && $this->reflection->hasProperty($property)) { + return isset($this->data[$property]) + ? $this->data[$property] + : call_user_func_array([$this->entity, $name], $arguments); + } + // Support twig. + elseif ($this->reflection->hasProperty($name)) { + return isset($this->data[$name]) + ? $this->data[$name] + : call_user_func_array([$this->entity, 'get' . ucfirst($name)], $arguments); + } + trigger_error('Call to undefined method '.__CLASS__.'::'.$name.'()', E_USER_ERROR); + } +} diff --git a/src/Opifer/Revisions/RevisionManager.php b/src/Opifer/Revisions/RevisionManager.php index d267e66..f13f227 100644 --- a/src/Opifer/Revisions/RevisionManager.php +++ b/src/Opifer/Revisions/RevisionManager.php @@ -2,12 +2,12 @@ namespace Opifer\Revisions; +use Doctrine\DBAL\Types\Type; use Doctrine\ORM\EntityManagerInterface; use Doctrine\ORM\Mapping\ClassMetadataInfo; -use Doctrine\DBAL\Types\Type; use Opifer\Revisions\Exception\DeletedException; use Opifer\Revisions\Mapping\AnnotationReader; -use Opifer\Revisions\Mapping\RevisionMetadata; +use Opifer\Revisions\Model\Revision; class RevisionManager { @@ -36,9 +36,10 @@ public function __construct(EntityManagerInterface $em, AnnotationReader $annota */ public function getLatestRevision($entity) { - $latest = $this->getRevisionData($entity, [], [], 1); + $result = $this->getRevisionData($entity, [], [], 1); - if ($latest) { + if ($result) { + $latest = reset($result); return $latest['revision_id']; } @@ -56,9 +57,10 @@ public function getCurrentRevision($entity) $criteria[] = '((r.updated_at <= e.updated_at AND r.deleted_at IS NULL) OR (e.created_at IS NULL AND e.created_at IS NOT NULL) OR (e.deleted_at IS NOT NULL AND r.deleted_at <= e.updated_at))'; } - $current = $this->getRevisionData($entity, $criteria, $params, 1); + $result = $this->getRevisionData($entity, $criteria, $params, 1); - if ($current) { + if ($result) { + $current = reset($result); return $current['revision_id']; } @@ -79,9 +81,25 @@ public function revert(&$entity, $revision) $meta = $this->getClassMetadata(get_class($entity)); $data = $this->getRevisionData($entity, ['revision_id = :revisionId'], ['revisionId' => $revision], 1); + if (!$data) { + throw new \InvalidArgumentException(sprintf('Revision with id %d not found for entity %s', $revision, get_class($entity))); + } + + $this->fillObject($entity, $meta, reset($data)); + + if ($meta->getReflectionClass()->hasMethod('getDeletedAt') && $entity->getDeletedAt() !== null) { + $exception = new DeletedException('Entity is deleted in this revision'); + $exception->setEntity($entity); + throw $exception; + } + + return $entity; + } + protected function fillObject(&$object, ClassMetadataInfo $meta, $data) + { /** @var \ReflectionProperty[] $revisedProperties */ - $revisedProperties = $this->annotationReader->getRevisedProperties($entity); + $revisedProperties = $this->annotationReader->getRevisedProperties($meta->getName()); $exception = null; foreach ($revisedProperties as $field => $property) { @@ -100,19 +118,8 @@ public function revert(&$entity, $revision) $value = $data[$columnName]; $property = $meta->getReflectionProperty($field); - $property->setValue($entity, $value); - - if ($field == 'deletedAt' && $value !== null) { - $exception = new DeletedException('Entity is deleted in this revision'); - } + $property->setValue($object, $value); } - - if ($exception) { - $exception->setEntity($entity); - throw $exception; - } - - return $entity; } /** @@ -170,20 +177,39 @@ protected function getRevisionData($entity, $criteria = array(), $params = array $sql .= ' LIMIT 0,' . $limit; } - $row = $this->em->getConnection()->fetchAssoc($sql, $params); + $rows = $this->em->getConnection()->fetchAll($sql, $params); - if (!$row) { + if (!$rows) { return false; } - foreach ($row as $column => &$value) { - try { - $this->mapValue($class, $class->getFieldForColumn($column), $value); - } catch (\Exception $e) { - continue; + foreach ($rows as &$row) { + $row = (array) $row; + foreach ($row as $column => &$value) { + try { + $this->mapValue($class, $class->getFieldForColumn($column), $value); + } catch (\Exception $e) { + continue; + } } } - return $row; + return $rows; + } + + public function getRevisions($entity, $criteria = array(), $params = array(), $limit = false) + { + $result = $this->getRevisionData($entity, $criteria, $params, $limit); + /** @var ClassMetadataInfo $meta */ + $meta = $this->getClassMetadata(get_class($entity)); + $revisions = array(); + foreach ($result as $row) { + $object = new \stdClass(); + $object->revision_id = $row['revision_id']; + $object->rev_type = $row['rev_type']; + $this->fillObject($object, $meta, $row); + $revisions[] = new Revision($object, $entity); + } + return $revisions; } @@ -242,4 +268,4 @@ protected function getClassMetadata($className) return $class; } -} \ No newline at end of file +}