Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 53 additions & 4 deletions src/Opifer/Revisions/Model/Revision.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,57 @@

class Revision
{
public $className;
public $revisionId;
public $revisionType;
protected $className;
protected $revisionId;
protected $revisionType;
protected $entity;
protected $data;

}
/**
* @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);
}
}
82 changes: 54 additions & 28 deletions src/Opifer/Revisions/RevisionManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down Expand Up @@ -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'];
}

Expand All @@ -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'];
}

Expand All @@ -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) {
Expand All @@ -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;
}

/**
Expand Down Expand Up @@ -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;
}


Expand Down Expand Up @@ -242,4 +268,4 @@ protected function getClassMetadata($className)

return $class;
}
}
}