238 lines
8.3 KiB
PHP
238 lines
8.3 KiB
PHP
|
|
<?php
|
||
|
|
namespace DynCom\mysyde\common\classes;
|
||
|
|
use DynCom\mysyde\common\interfaces\CRUDObjectStorage;
|
||
|
|
use DynCom\mysyde\common\interfaces\Entity;
|
||
|
|
use DynCom\mysyde\common\interfaces\Observer;
|
||
|
|
use DynCom\mysyde\common\interfaces\UnitOfWorkInterface;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* Created by PhpStorm.
|
||
|
|
* User: Bauer
|
||
|
|
* Date: 08.07.2015
|
||
|
|
* Time: 13:59
|
||
|
|
*/
|
||
|
|
class GenericCRUDObjectStorageUnitOfWork implements UnitOfWorkInterface,Observer
|
||
|
|
{
|
||
|
|
|
||
|
|
const ENTITY_STATE_NEW = 'ENTITY_STATE_NEW';
|
||
|
|
const ENTITY_STATE_CLEAN = 'ENTITY_STATE_CLEAN';
|
||
|
|
const ENTITY_STATE_DIRTY = 'ENTITY_STATE_DIRTY';
|
||
|
|
const ENTITY_STATE_REMOVED = 'ENTITY_STATE_REMOVED';
|
||
|
|
|
||
|
|
const EVENT_SUBSTR_MODEL_CHANGED = '.changed';
|
||
|
|
|
||
|
|
protected $storage;
|
||
|
|
protected $newEntities;
|
||
|
|
protected $cleanEntities;
|
||
|
|
protected $cleanEntitiesInit;
|
||
|
|
protected $dirtyEntities;
|
||
|
|
protected $removedEntities;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* GenericCRUDObjectStorageUnitOfWork constructor.
|
||
|
|
* @param CRUDObjectStorage $storage
|
||
|
|
*/
|
||
|
|
public function __construct(CRUDObjectStorage $storage) {
|
||
|
|
$this->storage = $storage;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param $eventName
|
||
|
|
* @param $data
|
||
|
|
*/
|
||
|
|
public function notify($eventName, $data) {
|
||
|
|
$className = get_class($data);
|
||
|
|
if(!$className || !($data instanceof Entity)) return;
|
||
|
|
$id = $data->getID();
|
||
|
|
$this->checkEventForChangedClean($eventName,$className,$id);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param $eventName
|
||
|
|
* @param $className
|
||
|
|
* @param $id
|
||
|
|
*/
|
||
|
|
protected function checkEventForChangedClean($eventName, $className, $id) {
|
||
|
|
if(array_key_exists($className,$this->cleanEntities) && array_key_exists($id,$this->cleanEntities[$className]) && false !== stripos($eventName,self::EVENT_SUBSTR_MODEL_CHANGED)) {
|
||
|
|
if(isset($this->cleanEntities[$className][$id])) {
|
||
|
|
$entity = $this->cleanEntities[$className][$id];
|
||
|
|
$this->dirtyEntities[$className][$id] = $entity;
|
||
|
|
unset($this->cleanEntities[$className][$id]);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Entity $entity
|
||
|
|
*/
|
||
|
|
public function registerNew(Entity $entity) {
|
||
|
|
$className = get_class($entity);
|
||
|
|
$id = $entity->getID();
|
||
|
|
if((int)$id > 0) {
|
||
|
|
throw new \BadMethodCallException(
|
||
|
|
"Entity must not have an ID > 0 to be registered as new."
|
||
|
|
);
|
||
|
|
}
|
||
|
|
$objHash = spl_object_hash($entity);
|
||
|
|
$this->newEntities[$className][$objHash] = &$entity;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Entity $entity
|
||
|
|
*/
|
||
|
|
public function registerClean(Entity $entity) {
|
||
|
|
$className = get_class($entity);
|
||
|
|
$id = $entity->getID();
|
||
|
|
if(!(int)$id > 0) {
|
||
|
|
throw new \BadMethodCallException(
|
||
|
|
"Entity needs a not-null id to be registered as clean."
|
||
|
|
);
|
||
|
|
}
|
||
|
|
if(
|
||
|
|
(array_key_exists($className,$this->dirtyEntities) && array_key_exists($id,$this->dirtyEntities[$className]))
|
||
|
|
|| (array_key_exists($className,$this->removedEntities) && array_key_exists($id,$this->removedEntities[$className]))) {
|
||
|
|
|
||
|
|
throw new \BadMethodCallException(
|
||
|
|
"Entity must not already be registered as dirty or removed to be registered as Clean"
|
||
|
|
);
|
||
|
|
}
|
||
|
|
$this->cleanEntitiesInit[$className][$id] = clone $entity;
|
||
|
|
$this->cleanEntities[$className][$id] = &$entity;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Entity $entity
|
||
|
|
*/
|
||
|
|
public function registerDirty(Entity $entity) {
|
||
|
|
$className = get_class($entity);
|
||
|
|
$id = $entity->getID();
|
||
|
|
if(!(int)$id > 0) {
|
||
|
|
throw new \BadMethodCallException(
|
||
|
|
"Entity needs a not-null id to be registered as dirty."
|
||
|
|
);
|
||
|
|
}
|
||
|
|
unset($this->cleanEntities[$className][$id],$this->removedEntities[$className][$id]);
|
||
|
|
$this->dirtyEntities[$className][$id] = &$entity;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Entity $entity
|
||
|
|
*/
|
||
|
|
public function registerRemoved(Entity $entity) {
|
||
|
|
$className = get_class($entity);
|
||
|
|
$id = $entity->getID();
|
||
|
|
if(!(int)$id > 0) {
|
||
|
|
throw new \BadMethodCallException(
|
||
|
|
"Entity needs a not-null id to be registered as removed."
|
||
|
|
);
|
||
|
|
}
|
||
|
|
unset($this->cleanEntities[$className][$id],$this->dirtyEntities[$className][$id]);
|
||
|
|
$this->removedEntities[$className][$id] = &$entity;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Entity $entity
|
||
|
|
* @param $state
|
||
|
|
*/
|
||
|
|
public function registerEntity(Entity $entity, $state) {
|
||
|
|
switch($state) {
|
||
|
|
case self::ENTITY_STATE_NEW:
|
||
|
|
$this->registerNew($entity);
|
||
|
|
return;
|
||
|
|
case self::ENTITY_STATE_CLEAN:
|
||
|
|
$this->registerClean($entity);
|
||
|
|
return;
|
||
|
|
case self::ENTITY_STATE_DIRTY:
|
||
|
|
$this->registerDirty($entity);
|
||
|
|
return;
|
||
|
|
case self::ENTITY_STATE_REMOVED:
|
||
|
|
$this->registerRemoved($entity);
|
||
|
|
return;
|
||
|
|
default: break;
|
||
|
|
}
|
||
|
|
throw new \InvalidArgumentException(
|
||
|
|
"State must be one of ENTITY_STATE_NEW, ENTITY_STATE_CLEAN, ENTITY_STATE_DIRTY, ENTITY_STATE_REMOVED."
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* @param Entity $entity
|
||
|
|
*/
|
||
|
|
public function unregisterEntity(Entity $entity) {
|
||
|
|
$className = get_class($entity);
|
||
|
|
$id = $entity->getID();
|
||
|
|
$objHash = spl_object_hash($entity);
|
||
|
|
unset(
|
||
|
|
$this->newEntities[$className][$objHash],
|
||
|
|
$this->cleanEntities[$className][$id],
|
||
|
|
$this->dirtyEntities[$className][$id],
|
||
|
|
$this->removedEntities[$className][$id]
|
||
|
|
);
|
||
|
|
|
||
|
|
}
|
||
|
|
|
||
|
|
public function rollback() {
|
||
|
|
//Look for entities in dirty / removed that had initially
|
||
|
|
//been registered as clean and then moved to dirty / removed through changes.
|
||
|
|
//Reset such entities to their initial state cloned on registration
|
||
|
|
foreach($this->dirtyEntities as $className => &$entityArr) {
|
||
|
|
foreach($entityArr as $id => $obj) {
|
||
|
|
if(array_key_exists($id,$this->cleanEntitiesInit[$className])) {
|
||
|
|
$oldState = $this->cleanEntitiesInit[$className][$id];
|
||
|
|
//Initially stored by reference,
|
||
|
|
//So this resets the referenced entity to init state
|
||
|
|
//And then deletes the reference in the array
|
||
|
|
$obj = $entityArr[$id];
|
||
|
|
$obj = $oldState;
|
||
|
|
unset($entityArr[$id]);
|
||
|
|
$this->cleanEntities[$className][$id] = $obj;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
unset($entityArr);
|
||
|
|
|
||
|
|
foreach($this->removedEntities as $className => &$entityArr2) {
|
||
|
|
foreach($entityArr2 as $id => $obj) {
|
||
|
|
if(array_key_exists($id,$this->cleanEntitiesInit[$className])) {
|
||
|
|
$oldState = $this->cleanEntitiesInit[$className][$id];
|
||
|
|
//Initially stored by reference,
|
||
|
|
//So this resets the referenced entity to init state
|
||
|
|
//And then deletes the reference in the array
|
||
|
|
$obj = $entityArr2[$id];
|
||
|
|
$obj = $oldState;
|
||
|
|
unset($entityArr2[$id]);
|
||
|
|
$this->cleanEntities[$className][$id] = $obj;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
unset($entityArr2);
|
||
|
|
}
|
||
|
|
|
||
|
|
public function clear() {
|
||
|
|
$this->newEntities = [];
|
||
|
|
$this->cleanEntitiesInit = [];
|
||
|
|
$this->cleanEntities = [];
|
||
|
|
$this->dirtyEntities = [];
|
||
|
|
$this->removedEntities = [];
|
||
|
|
}
|
||
|
|
|
||
|
|
public function commit() {
|
||
|
|
foreach($this->newEntities as $className => $objArr) {
|
||
|
|
foreach($objArr as $entity) {
|
||
|
|
$this->storage->create($entity);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
foreach($this->dirtyEntities as $className => $objArr) {
|
||
|
|
foreach($objArr as $id => $entity) {
|
||
|
|
$this->storage->update($entity);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
foreach($this->removedEntities as $className => $objArr) {
|
||
|
|
foreach($objArr as $id => $entity) {
|
||
|
|
$this->storage->delete($entity);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
|
||
|
|
}
|