|
@@ -5,7 +5,6 @@ namespace PhpDevCommunity\PaperORM\Persistence;
|
|
|
use PhpDevCommunity\PaperORM\Entity\EntityInterface;
|
|
use PhpDevCommunity\PaperORM\Entity\EntityInterface;
|
|
|
use PhpDevCommunity\PaperORM\Event\PreCreateEvent;
|
|
use PhpDevCommunity\PaperORM\Event\PreCreateEvent;
|
|
|
use PhpDevCommunity\PaperORM\Event\PreUpdateEvent;
|
|
use PhpDevCommunity\PaperORM\Event\PreUpdateEvent;
|
|
|
-use PhpDevCommunity\PaperORM\Hydrator\EntityHydrator;
|
|
|
|
|
use PhpDevCommunity\PaperORM\Hydrator\ReadOnlyEntityHydrator;
|
|
use PhpDevCommunity\PaperORM\Hydrator\ReadOnlyEntityHydrator;
|
|
|
use PhpDevCommunity\PaperORM\Mapper\ColumnMapper;
|
|
use PhpDevCommunity\PaperORM\Mapper\ColumnMapper;
|
|
|
use PhpDevCommunity\PaperORM\Mapper\EntityMapper;
|
|
use PhpDevCommunity\PaperORM\Mapper\EntityMapper;
|
|
@@ -18,12 +17,14 @@ use Psr\EventDispatcher\EventDispatcherInterface;
|
|
|
class EntityPersistence
|
|
class EntityPersistence
|
|
|
{
|
|
{
|
|
|
private PlatformInterface $platform;
|
|
private PlatformInterface $platform;
|
|
|
|
|
+ private \SplObjectStorage $managed;
|
|
|
|
|
|
|
|
private ?EventDispatcherInterface $dispatcher;
|
|
private ?EventDispatcherInterface $dispatcher;
|
|
|
public function __construct(PlatformInterface $platform, EventDispatcherInterface $dispatcher = null)
|
|
public function __construct(PlatformInterface $platform, EventDispatcherInterface $dispatcher = null)
|
|
|
{
|
|
{
|
|
|
$this->platform = $platform;
|
|
$this->platform = $platform;
|
|
|
$this->dispatcher = $dispatcher;
|
|
$this->dispatcher = $dispatcher;
|
|
|
|
|
+ $this->managed = new \SplObjectStorage();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
public function insert(object $entity): int
|
|
public function insert(object $entity): int
|
|
@@ -32,8 +33,12 @@ class EntityPersistence
|
|
|
* @var EntityInterface $entity
|
|
* @var EntityInterface $entity
|
|
|
*/
|
|
*/
|
|
|
$this->checkEntity($entity);
|
|
$this->checkEntity($entity);
|
|
|
- if ($entity->getPrimaryKeyValue() !== null) {
|
|
|
|
|
- throw new \LogicException(static::class . sprintf(' Cannot insert an entity %s with a primary key ', get_class($entity)));
|
|
|
|
|
|
|
+ if ($entity->getPrimaryKeyValue() !== null || $this->managed->contains($entity)) {
|
|
|
|
|
+ throw new \LogicException(sprintf(
|
|
|
|
|
+ '%s cannot insert entity of type "%s": entity already managed (has primary key, is a proxy, or is attached).',
|
|
|
|
|
+ static::class,
|
|
|
|
|
+ get_class($entity)
|
|
|
|
|
+ ));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if ($this->dispatcher) {
|
|
if ($this->dispatcher) {
|
|
@@ -54,6 +59,7 @@ class EntityPersistence
|
|
|
if ($rows > 0) {
|
|
if ($rows > 0) {
|
|
|
$primaryKeyColumn = ColumnMapper::getPrimaryKeyColumnName($entity);
|
|
$primaryKeyColumn = ColumnMapper::getPrimaryKeyColumnName($entity);
|
|
|
(new ReadOnlyEntityHydrator())->hydrate($entity, [$primaryKeyColumn => $lastInsertId]);
|
|
(new ReadOnlyEntityHydrator())->hydrate($entity, [$primaryKeyColumn => $lastInsertId]);
|
|
|
|
|
+ $this->managed->attach($entity);
|
|
|
}
|
|
}
|
|
|
return $rows;
|
|
return $rows;
|
|
|
}
|
|
}
|
|
@@ -68,13 +74,22 @@ class EntityPersistence
|
|
|
throw new \LogicException(static::class . sprintf(' Cannot update an entity %s without a primary key ', get_class($entity)));
|
|
throw new \LogicException(static::class . sprintf(' Cannot update an entity %s without a primary key ', get_class($entity)));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (!$entity->__wasModified()) {
|
|
|
|
|
- return 0;
|
|
|
|
|
|
|
+ if ($entity instanceof ProxyInterface) {
|
|
|
|
|
+ if (!$entity->__wasModified()) {
|
|
|
|
|
+ return 0;
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
if ($this->dispatcher) {
|
|
if ($this->dispatcher) {
|
|
|
$this->dispatcher->dispatch(new PreUpdateEvent($entity));
|
|
$this->dispatcher->dispatch(new PreUpdateEvent($entity));
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ if ($entity instanceof ProxyInterface) {
|
|
|
|
|
+ $propertiesModified = $entity->__getPropertiesModified();
|
|
|
|
|
+ } else {
|
|
|
|
|
+ $propertiesModified = [];
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
$tableName = EntityMapper::getTable($entity);
|
|
$tableName = EntityMapper::getTable($entity);
|
|
|
$schema = $this->platform->getSchema();
|
|
$schema = $this->platform->getSchema();
|
|
|
$qb = QueryBuilder::update($schema->quote($tableName))
|
|
$qb = QueryBuilder::update($schema->quote($tableName))
|
|
@@ -84,14 +99,15 @@ class EntityPersistence
|
|
|
$entity->getPrimaryKeyValue()
|
|
$entity->getPrimaryKeyValue()
|
|
|
)
|
|
)
|
|
|
);
|
|
);
|
|
|
|
|
+
|
|
|
$values = [];
|
|
$values = [];
|
|
|
- foreach ((new SerializerToDb($entity))->serialize($entity->__getPropertiesModified()) as $key => $value) {
|
|
|
|
|
|
|
+ foreach ((new SerializerToDb($entity))->serialize($propertiesModified) as $key => $value) {
|
|
|
$qb->set($schema->quote($key), ":$key");
|
|
$qb->set($schema->quote($key), ":$key");
|
|
|
$values[$key] = $value;
|
|
$values[$key] = $value;
|
|
|
}
|
|
}
|
|
|
$conn = $this->platform->getConnection();
|
|
$conn = $this->platform->getConnection();
|
|
|
$rows = $conn->executeStatement($qb, $values);
|
|
$rows = $conn->executeStatement($qb, $values);
|
|
|
- if ($rows > 0) {
|
|
|
|
|
|
|
+ if ($rows > 0 && $entity instanceof ProxyInterface) {
|
|
|
$entity->__reset();
|
|
$entity->__reset();
|
|
|
}
|
|
}
|
|
|
return $rows;
|
|
return $rows;
|
|
@@ -110,22 +126,24 @@ class EntityPersistence
|
|
|
$tableName = EntityMapper::getTable($entity);
|
|
$tableName = EntityMapper::getTable($entity);
|
|
|
$schema = $this->platform->getSchema();
|
|
$schema = $this->platform->getSchema();
|
|
|
$qb = QueryBuilder::delete($schema->quote($tableName))
|
|
$qb = QueryBuilder::delete($schema->quote($tableName))
|
|
|
- ->where(
|
|
|
|
|
- sprintf('%s = %s',
|
|
|
|
|
- $schema->quote(ColumnMapper::getPrimaryKeyColumnName($entity)),
|
|
|
|
|
- $entity->getPrimaryKeyValue()
|
|
|
|
|
- )
|
|
|
|
|
- );
|
|
|
|
|
|
|
+ ->where(sprintf('%s = :id', $schema->quote(ColumnMapper::getPrimaryKeyColumnName($entity))));
|
|
|
|
|
|
|
|
$conn = $this->platform->getConnection();
|
|
$conn = $this->platform->getConnection();
|
|
|
- $rows = $conn->executeStatement($qb);
|
|
|
|
|
|
|
+ $rows = $conn->executeStatement($qb, [
|
|
|
|
|
+ 'id' => $entity->getPrimaryKeyValue(),
|
|
|
|
|
+ ]);
|
|
|
if ($rows > 0) {
|
|
if ($rows > 0) {
|
|
|
- $entity->__destroy();
|
|
|
|
|
|
|
+ if ($entity instanceof ProxyInterface) {
|
|
|
|
|
+ $entity->__destroy();
|
|
|
|
|
+ }
|
|
|
|
|
+ if ($this->managed->contains($entity)) {
|
|
|
|
|
+ $this->managed->detach($entity);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
return $rows;
|
|
return $rows;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- private function checkEntity(object $entity, bool $proxy = false): void
|
|
|
|
|
|
|
+ private function checkEntity(object $entity, bool $requireManaged = false): void
|
|
|
{
|
|
{
|
|
|
if (!$entity instanceof EntityInterface) {
|
|
if (!$entity instanceof EntityInterface) {
|
|
|
throw new \LogicException(sprintf(
|
|
throw new \LogicException(sprintf(
|
|
@@ -135,14 +153,16 @@ class EntityPersistence
|
|
|
));
|
|
));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if ($proxy && (!$entity instanceof ProxyInterface || !$entity->__isInitialized())) {
|
|
|
|
|
- throw new \LogicException(sprintf(
|
|
|
|
|
- 'Entity of type "%s" is not a valid initialized proxy (expected instance of "%s").',
|
|
|
|
|
- get_class($entity),
|
|
|
|
|
- ProxyInterface::class
|
|
|
|
|
- ));
|
|
|
|
|
|
|
+ if ($requireManaged) {
|
|
|
|
|
+ $isManaged = $this->managed->contains($entity);
|
|
|
|
|
+ $isProxy = $entity instanceof ProxyInterface && $entity->__isInitialized();
|
|
|
|
|
+ if (!$isManaged && !$isProxy) {
|
|
|
|
|
+ throw new \LogicException(sprintf(
|
|
|
|
|
+ 'Entity of type "%s" is not managed by ORM',
|
|
|
|
|
+ get_class($entity)
|
|
|
|
|
+ ));
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-
|
|
|
|
|
}
|
|
}
|