From ac62e4d9bb3cab75553f08a1c4b2b77a6f01e830 Mon Sep 17 00:00:00 2001 From: beberlei Date: Sun, 21 Feb 2010 21:55:39 +0000 Subject: [PATCH] [2.0] DDC-358 - Refactored UnitOfWork Event triggering capabilities --- lib/Doctrine/DBAL/Types/ArrayType.php | 2 +- lib/Doctrine/ORM/Event/LifecycleEventArgs.php | 50 ++++++++- lib/Doctrine/ORM/UnitOfWork.php | 106 +++++++++--------- 3 files changed, 100 insertions(+), 58 deletions(-) diff --git a/lib/Doctrine/DBAL/Types/ArrayType.php b/lib/Doctrine/DBAL/Types/ArrayType.php index c0a27a017..b0cc8941b 100644 --- a/lib/Doctrine/DBAL/Types/ArrayType.php +++ b/lib/Doctrine/DBAL/Types/ArrayType.php @@ -11,7 +11,7 @@ class ArrayType extends Type { public function getSqlDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) { - return $platform->getClobDeclarationSql($fieldDeclaration); + return $platform->getClobTypeDeclarationSql($fieldDeclaration); } public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) diff --git a/lib/Doctrine/ORM/Event/LifecycleEventArgs.php b/lib/Doctrine/ORM/Event/LifecycleEventArgs.php index c97b7a7e5..57b2273d1 100644 --- a/lib/Doctrine/ORM/Event/LifecycleEventArgs.php +++ b/lib/Doctrine/ORM/Event/LifecycleEventArgs.php @@ -1,26 +1,66 @@ . +*/ namespace Doctrine\ORM\Event; +use Doctrine\ORM\EntityManager; + +/** + * Lifecycle Events are triggered by the UnitOfWork + * + * @license http://www.opensource.org/licenses/lgpl-license.php LGPL + * @link www.doctrine-project.com + * @since 1.0 + * @version $Revision$ + * @author Roman Borschel + * @author Benjamin Eberlei + */ class LifecycleEventArgs extends \Doctrine\Common\EventArgs { - //private $_em; + /** + * @var EntityManager + */ + private $_em; + + /** + * @var object + */ private $_entity; - public function __construct($entity) + public function __construct($entity, EntityManager $em) { $this->_entity = $entity; + $this->_em = $em; } public function getEntity() { return $this->_entity; } - - /* + + /** + * @return EntityManager + */ public function getEntityManager() { return $this->_em; } - */ } \ No newline at end of file diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 0e68b419b..2f16ddba2 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -365,6 +365,29 @@ class UnitOfWork implements PropertyChangedListener return array(); } + /** + * Method can be used to compute the change-set of any entity. + * + * @Internal + * + * @Todo inline _computeChangeSet to here? + * + * @param ClassMetadata $class + * @param object $entity + * @return void + */ + public function computeChangeSet($class, $entity) + { + $this->_computeEntityChanges($class, $entity); + // Look for changes in associations of the entity + foreach ($class->associationMappings as $assoc) { + $val = $class->reflFields[$assoc->sourceFieldName]->getValue($entity); + if ($val !== null) { + $this->_computeAssociationChanges($assoc, $val); + } + } + } + /** * Computes all the changes that have been done to entities and collections * since the last commit and stores these changes in the _entityChangeSet map @@ -375,14 +398,7 @@ class UnitOfWork implements PropertyChangedListener // Compute changes for INSERTed entities first. This must always happen. foreach ($this->_entityInsertions as $entity) { $class = $this->_em->getClassMetadata(get_class($entity)); - $this->_computeEntityChanges($class, $entity); - // Look for changes in associations of the entity - foreach ($class->associationMappings as $assoc) { - $val = $class->reflFields[$assoc->sourceFieldName]->getValue($entity); - if ($val !== null) { - $this->_computeAssociationChanges($assoc, $val); - } - } + $this->computeChangeSet($class, $entity); } // Compute changes for other MANAGED entities. Change tracking policies take effect here. @@ -406,14 +422,7 @@ class UnitOfWork implements PropertyChangedListener // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here. $oid = spl_object_hash($entity); if ( ! isset($this->_entityInsertions[$oid]) && isset($this->_entityStates[$oid])) { - $this->_computeEntityChanges($class, $entity); - // Look for changes in associations of the entity - foreach ($class->associationMappings as $assoc) { - $val = $class->reflFields[$assoc->sourceFieldName]->getValue($entity); - if ($val !== null) { - $this->_computeAssociationChanges($assoc, $val); - } - } + $this->computeChangeSet($class, $entity); } } } @@ -528,11 +537,26 @@ class UnitOfWork implements PropertyChangedListener } } if ($changeSet) { - if ($entityIsDirty) { - $this->_entityUpdates[$oid] = $entity; - } $this->_entityChangeSets[$oid] = $changeSet; $this->_originalEntityData[$oid] = $actualData; + + if ($entityIsDirty) { + $hasPreUpdateListeners = $this->_evm->hasListeners(Events::preUpdate); + if (isset($class->lifecycleCallbacks[Events::preUpdate])) { + $class->invokeLifecycleCallbacks(Events::preUpdate, $entity); + if ( ! $hasPreUpdateListeners) { + // Need to recompute entity changeset to detect changes made in the callback. + $this->recomputeSingleEntityChangeSet($class, $entity); + } + } + if ($hasPreUpdateListeners) { + $this->_evm->dispatchEvent(Events::preUpdate, new LifecycleEventArgs($entity, $this->_em)); + // Need to recompute entity changeset to detect changes made in the listener. + $this->recomputeSingleEntityChangeSet($class, $entity); + } + + $this->_entityUpdates[$oid] = $entity; + } } } } @@ -576,7 +600,7 @@ class UnitOfWork implements PropertyChangedListener $targetClass->invokeLifecycleCallbacks(Events::prePersist, $entry); } if ($this->_evm->hasListeners(Events::prePersist)) { - $this->_evm->dispatchEvent(Events::prePersist, new LifecycleEventArgs($entry)); + $this->_evm->dispatchEvent(Events::prePersist, new LifecycleEventArgs($entry, $this->_em)); } // Get identifier, if possible (not post-insert) @@ -595,15 +619,8 @@ class UnitOfWork implements PropertyChangedListener // NEW entities are INSERTed within the current unit of work. $this->_entityInsertions[$oid] = $entry; - - $this->_computeEntityChanges($targetClass, $entry); - // Look for changes in associations of the entity - foreach ($targetClass->associationMappings as $assoc2) { - $val = $targetClass->reflFields[$assoc2->sourceFieldName]->getValue($entry); - if ($val !== null) { - $this->_computeAssociationChanges($assoc2, $val); - } - } + + $this->computeChangeSet($targetClass, $entry); } else if ($state == self::STATE_REMOVED) { throw ORMException::removedEntityInCollectionDetected($entity, $assoc); @@ -627,7 +644,7 @@ class UnitOfWork implements PropertyChangedListener * @param object $entity The entity for which to (re)calculate the change set. * @throws InvalidArgumentException If the passed entity is not MANAGED. */ - public function computeSingleEntityChangeSet($class, $entity) + public function recomputeSingleEntityChangeSet($class, $entity) { $oid = spl_object_hash($entity); @@ -718,7 +735,7 @@ class UnitOfWork implements PropertyChangedListener $class->invokeLifecycleCallbacks(Events::postPersist, $entity); } if ($hasListeners) { - $this->_evm->dispatchEvent(Events::postPersist, new LifecycleEventArgs($entity)); + $this->_evm->dispatchEvent(Events::postPersist, new LifecycleEventArgs($entity, $this->_em)); } } } @@ -734,26 +751,11 @@ class UnitOfWork implements PropertyChangedListener $className = $class->name; $persister = $this->getEntityPersister($className); - $hasPreUpdateLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::preUpdate]); - $hasPreUpdateListeners = $this->_evm->hasListeners(Events::preUpdate); $hasPostUpdateLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::postUpdate]); $hasPostUpdateListeners = $this->_evm->hasListeners(Events::postUpdate); foreach ($this->_entityUpdates as $oid => $entity) { - if (get_class($entity) == $className || $entity instanceof Proxy && $entity instanceof $className) { - if ($hasPreUpdateLifecycleCallbacks) { - $class->invokeLifecycleCallbacks(Events::preUpdate, $entity); - if ( ! $hasPreUpdateListeners) { - // Need to recompute entity changeset to detect changes made in the callback. - $this->computeSingleEntityChangeSet($class, $entity); - } - } - if ($hasPreUpdateListeners) { - $this->_evm->dispatchEvent(Events::preUpdate, new LifecycleEventArgs($entity)); - // Need to recompute entity changeset to detect changes made in the listener. - $this->computeSingleEntityChangeSet($class, $entity); - } - + if (get_class($entity) == $className || $entity instanceof Proxy && $entity instanceof $className) { $persister->update($entity); unset($this->_entityUpdates[$oid]); @@ -761,7 +763,7 @@ class UnitOfWork implements PropertyChangedListener $class->invokeLifecycleCallbacks(Events::postUpdate, $entity); } if ($hasPostUpdateListeners) { - $this->_evm->dispatchEvent(Events::postUpdate, new LifecycleEventArgs($entity)); + $this->_evm->dispatchEvent(Events::postUpdate, new LifecycleEventArgs($entity, $this->_em)); } } } @@ -796,7 +798,7 @@ class UnitOfWork implements PropertyChangedListener $class->invokeLifecycleCallbacks(Events::postRemove, $entity); } if ($hasListeners) { - $this->_evm->dispatchEvent(Events::postRemove, new LifecycleEventArgs($entity)); + $this->_evm->dispatchEvent(Events::postRemove, new LifecycleEventArgs($entity, $this->_em)); } } } @@ -1198,7 +1200,7 @@ class UnitOfWork implements PropertyChangedListener $class->invokeLifecycleCallbacks(Events::prePersist, $entity); } if ($this->_evm->hasListeners(Events::prePersist)) { - $this->_evm->dispatchEvent(Events::prePersist, new LifecycleEventArgs($entity)); + $this->_evm->dispatchEvent(Events::prePersist, new LifecycleEventArgs($entity, $this->_em)); } $idGen = $class->idGenerator; @@ -1276,7 +1278,7 @@ class UnitOfWork implements PropertyChangedListener $class->invokeLifecycleCallbacks(Events::preRemove, $entity); } if ($this->_evm->hasListeners(Events::preRemove)) { - $this->_evm->dispatchEvent(Events::preRemove, new LifecycleEventArgs($entity)); + $this->_evm->dispatchEvent(Events::preRemove, new LifecycleEventArgs($entity, $this->_em)); } $this->scheduleForDelete($entity); break; @@ -1835,7 +1837,7 @@ class UnitOfWork implements PropertyChangedListener $class->invokeLifecycleCallbacks(Events::postLoad, $entity); } if ($this->_evm->hasListeners(Events::postLoad)) { - $this->_evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity)); + $this->_evm->dispatchEvent(Events::postLoad, new LifecycleEventArgs($entity, $this->_em)); } return $entity;