Commit ac62e4d9 authored by beberlei's avatar beberlei

[2.0] DDC-358 - Refactored UnitOfWork Event triggering capabilities

parent 30712c6c
...@@ -11,7 +11,7 @@ class ArrayType extends Type ...@@ -11,7 +11,7 @@ class ArrayType extends Type
{ {
public function getSqlDeclaration(array $fieldDeclaration, \Doctrine\DBAL\Platforms\AbstractPlatform $platform) 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) public function convertToDatabaseValue($value, \Doctrine\DBAL\Platforms\AbstractPlatform $platform)
......
<?php <?php
/*
* $Id$
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* This software consists of voluntary contributions made by many individuals
* and is licensed under the LGPL. For more information, see
* <http://www.doctrine-project.org>.
*/
namespace Doctrine\ORM\Event; 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 <roman@code-factory.de>
* @author Benjamin Eberlei <kontakt@beberlei.de>
*/
class LifecycleEventArgs extends \Doctrine\Common\EventArgs class LifecycleEventArgs extends \Doctrine\Common\EventArgs
{ {
//private $_em; /**
* @var EntityManager
*/
private $_em;
/**
* @var object
*/
private $_entity; private $_entity;
public function __construct($entity) public function __construct($entity, EntityManager $em)
{ {
$this->_entity = $entity; $this->_entity = $entity;
$this->_em = $em;
} }
public function getEntity() public function getEntity()
...@@ -17,10 +56,11 @@ class LifecycleEventArgs extends \Doctrine\Common\EventArgs ...@@ -17,10 +56,11 @@ class LifecycleEventArgs extends \Doctrine\Common\EventArgs
return $this->_entity; return $this->_entity;
} }
/* /**
* @return EntityManager
*/
public function getEntityManager() public function getEntityManager()
{ {
return $this->_em; return $this->_em;
} }
*/
} }
\ No newline at end of file
...@@ -366,15 +366,18 @@ class UnitOfWork implements PropertyChangedListener ...@@ -366,15 +366,18 @@ class UnitOfWork implements PropertyChangedListener
} }
/** /**
* Computes all the changes that have been done to entities and collections * Method can be used to compute the change-set of any entity.
* since the last commit and stores these changes in the _entityChangeSet map *
* temporarily for access by the persisters, until the UoW commit is finished. * @Internal
*
* @Todo inline _computeChangeSet to here?
*
* @param ClassMetadata $class
* @param object $entity
* @return void
*/ */
public function computeChangeSets() public function computeChangeSet($class, $entity)
{ {
// 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); $this->_computeEntityChanges($class, $entity);
// Look for changes in associations of the entity // Look for changes in associations of the entity
foreach ($class->associationMappings as $assoc) { foreach ($class->associationMappings as $assoc) {
...@@ -385,6 +388,19 @@ class UnitOfWork implements PropertyChangedListener ...@@ -385,6 +388,19 @@ class UnitOfWork implements PropertyChangedListener
} }
} }
/**
* Computes all the changes that have been done to entities and collections
* since the last commit and stores these changes in the _entityChangeSet map
* temporarily for access by the persisters, until the UoW commit is finished.
*/
public function computeChangeSets()
{
// Compute changes for INSERTed entities first. This must always happen.
foreach ($this->_entityInsertions as $entity) {
$class = $this->_em->getClassMetadata(get_class($entity));
$this->computeChangeSet($class, $entity);
}
// Compute changes for other MANAGED entities. Change tracking policies take effect here. // Compute changes for other MANAGED entities. Change tracking policies take effect here.
foreach ($this->_identityMap as $className => $entities) { foreach ($this->_identityMap as $className => $entities) {
$class = $this->_em->getClassMetadata($className); $class = $this->_em->getClassMetadata($className);
...@@ -406,14 +422,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -406,14 +422,7 @@ class UnitOfWork implements PropertyChangedListener
// Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here. // Only MANAGED entities that are NOT SCHEDULED FOR INSERTION are processed here.
$oid = spl_object_hash($entity); $oid = spl_object_hash($entity);
if ( ! isset($this->_entityInsertions[$oid]) && isset($this->_entityStates[$oid])) { if ( ! isset($this->_entityInsertions[$oid]) && isset($this->_entityStates[$oid])) {
$this->_computeEntityChanges($class, $entity); $this->computeChangeSet($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);
}
}
} }
} }
} }
...@@ -528,11 +537,26 @@ class UnitOfWork implements PropertyChangedListener ...@@ -528,11 +537,26 @@ class UnitOfWork implements PropertyChangedListener
} }
} }
if ($changeSet) { if ($changeSet) {
$this->_entityChangeSets[$oid] = $changeSet;
$this->_originalEntityData[$oid] = $actualData;
if ($entityIsDirty) { 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; $this->_entityUpdates[$oid] = $entity;
} }
$this->_entityChangeSets[$oid] = $changeSet;
$this->_originalEntityData[$oid] = $actualData;
} }
} }
} }
...@@ -576,7 +600,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -576,7 +600,7 @@ class UnitOfWork implements PropertyChangedListener
$targetClass->invokeLifecycleCallbacks(Events::prePersist, $entry); $targetClass->invokeLifecycleCallbacks(Events::prePersist, $entry);
} }
if ($this->_evm->hasListeners(Events::prePersist)) { 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) // Get identifier, if possible (not post-insert)
...@@ -596,14 +620,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -596,14 +620,7 @@ class UnitOfWork implements PropertyChangedListener
// NEW entities are INSERTed within the current unit of work. // NEW entities are INSERTed within the current unit of work.
$this->_entityInsertions[$oid] = $entry; $this->_entityInsertions[$oid] = $entry;
$this->_computeEntityChanges($targetClass, $entry); $this->computeChangeSet($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);
}
}
} else if ($state == self::STATE_REMOVED) { } else if ($state == self::STATE_REMOVED) {
throw ORMException::removedEntityInCollectionDetected($entity, $assoc); throw ORMException::removedEntityInCollectionDetected($entity, $assoc);
...@@ -627,7 +644,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -627,7 +644,7 @@ class UnitOfWork implements PropertyChangedListener
* @param object $entity The entity for which to (re)calculate the change set. * @param object $entity The entity for which to (re)calculate the change set.
* @throws InvalidArgumentException If the passed entity is not MANAGED. * @throws InvalidArgumentException If the passed entity is not MANAGED.
*/ */
public function computeSingleEntityChangeSet($class, $entity) public function recomputeSingleEntityChangeSet($class, $entity)
{ {
$oid = spl_object_hash($entity); $oid = spl_object_hash($entity);
...@@ -718,7 +735,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -718,7 +735,7 @@ class UnitOfWork implements PropertyChangedListener
$class->invokeLifecycleCallbacks(Events::postPersist, $entity); $class->invokeLifecycleCallbacks(Events::postPersist, $entity);
} }
if ($hasListeners) { 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 ...@@ -734,26 +751,11 @@ class UnitOfWork implements PropertyChangedListener
$className = $class->name; $className = $class->name;
$persister = $this->getEntityPersister($className); $persister = $this->getEntityPersister($className);
$hasPreUpdateLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::preUpdate]);
$hasPreUpdateListeners = $this->_evm->hasListeners(Events::preUpdate);
$hasPostUpdateLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::postUpdate]); $hasPostUpdateLifecycleCallbacks = isset($class->lifecycleCallbacks[Events::postUpdate]);
$hasPostUpdateListeners = $this->_evm->hasListeners(Events::postUpdate); $hasPostUpdateListeners = $this->_evm->hasListeners(Events::postUpdate);
foreach ($this->_entityUpdates as $oid => $entity) { foreach ($this->_entityUpdates as $oid => $entity) {
if (get_class($entity) == $className || $entity instanceof Proxy && $entity instanceof $className) { 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);
}
$persister->update($entity); $persister->update($entity);
unset($this->_entityUpdates[$oid]); unset($this->_entityUpdates[$oid]);
...@@ -761,7 +763,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -761,7 +763,7 @@ class UnitOfWork implements PropertyChangedListener
$class->invokeLifecycleCallbacks(Events::postUpdate, $entity); $class->invokeLifecycleCallbacks(Events::postUpdate, $entity);
} }
if ($hasPostUpdateListeners) { 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 ...@@ -796,7 +798,7 @@ class UnitOfWork implements PropertyChangedListener
$class->invokeLifecycleCallbacks(Events::postRemove, $entity); $class->invokeLifecycleCallbacks(Events::postRemove, $entity);
} }
if ($hasListeners) { 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 ...@@ -1198,7 +1200,7 @@ class UnitOfWork implements PropertyChangedListener
$class->invokeLifecycleCallbacks(Events::prePersist, $entity); $class->invokeLifecycleCallbacks(Events::prePersist, $entity);
} }
if ($this->_evm->hasListeners(Events::prePersist)) { 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; $idGen = $class->idGenerator;
...@@ -1276,7 +1278,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -1276,7 +1278,7 @@ class UnitOfWork implements PropertyChangedListener
$class->invokeLifecycleCallbacks(Events::preRemove, $entity); $class->invokeLifecycleCallbacks(Events::preRemove, $entity);
} }
if ($this->_evm->hasListeners(Events::preRemove)) { 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); $this->scheduleForDelete($entity);
break; break;
...@@ -1835,7 +1837,7 @@ class UnitOfWork implements PropertyChangedListener ...@@ -1835,7 +1837,7 @@ class UnitOfWork implements PropertyChangedListener
$class->invokeLifecycleCallbacks(Events::postLoad, $entity); $class->invokeLifecycleCallbacks(Events::postLoad, $entity);
} }
if ($this->_evm->hasListeners(Events::postLoad)) { 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; return $entity;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment