[2.0] DDC-414 - Changed semantics of preUpdate Event to allow only changes to the entity changeset, not the internal state of the entity anymore.
This commit is contained in:
parent
0a9101d79e
commit
bc6714c2c8
@ -19,6 +19,13 @@ mapped fields inside PHP easily. Upon persist() invocation these values are save
|
||||
The 'inheritance-type' attribute changed to take last bit of ClassMetadata constant names, i.e.
|
||||
NONE, SINGLE_TABLE, INHERITANCE_TYPE_JOINED
|
||||
|
||||
## Change of PreUpdate Event Listener
|
||||
|
||||
Event Listeners listening to the 'preUpdate' event can only affect the primitive values of entity changesets
|
||||
by using the API on the `PreUpdateEventArgs` instance passed to the preUpdate listener method. Any changes
|
||||
to the state of the entitys properties won't affect the database UPDATE statement anymore. This gives drastic
|
||||
performance benefits for the preUpdate event.
|
||||
|
||||
# Upgrade from 2.0-ALPHA3 to 2.0-ALPHA4
|
||||
|
||||
## CLI Controller changes
|
||||
|
98
lib/Doctrine/ORM/Event/PreUpdateEventArgs.php
Normal file
98
lib/Doctrine/ORM/Event/PreUpdateEventArgs.php
Normal file
@ -0,0 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\ORM\Event;
|
||||
|
||||
use Doctrine\Common\EventArgs,
|
||||
Doctrine\ORM\EntityManager;
|
||||
|
||||
/**
|
||||
* Class that holds event arguments for a preInsert/preUpdate event.
|
||||
*
|
||||
* @author Roman Borschel <roman@code-factory.org>
|
||||
* @author Benjamin Eberlei <kontakt@beberlei.de>
|
||||
* @since 2.0
|
||||
*/
|
||||
class PreUpdateEventArgs extends LifecycleEventArgs
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $_entityChangeSet;
|
||||
|
||||
/**
|
||||
*
|
||||
* @param object $entity
|
||||
* @param EntityManager $em
|
||||
* @param array $changeSet
|
||||
*/
|
||||
public function __construct($entity, $em, array &$changeSet)
|
||||
{
|
||||
parent::__construct($entity, $em);
|
||||
$this->_entityChangeSet = &$changeSet;
|
||||
}
|
||||
|
||||
public function getEntityChangeSet()
|
||||
{
|
||||
return $this->_entityChangeSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Field has a changeset?
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasChangedField($field)
|
||||
{
|
||||
return isset($this->_entityChangeSet[$field]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the old value of the changeset of the changed field.
|
||||
*
|
||||
* @param string $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function getOldValue($field)
|
||||
{
|
||||
$this->_assertValidField($field);
|
||||
|
||||
return $this->_entityChangeSet[$field][0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the new value of the changeset of the changed field.
|
||||
*
|
||||
* @param string $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function getNewValue($field)
|
||||
{
|
||||
$this->_assertValidField($field);
|
||||
|
||||
return $this->_entityChangeSet[$field][1];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the new value of this field.
|
||||
*
|
||||
* @param string $field
|
||||
* @param mixed $value
|
||||
*/
|
||||
public function setNewValue($field, $value)
|
||||
{
|
||||
$this->_assertValidField($field);
|
||||
|
||||
$this->_entityChangeSet[$field][1] = $value;
|
||||
}
|
||||
|
||||
private function _assertValidField($field)
|
||||
{
|
||||
if (!isset($this->_entityChangeSet[$field])) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Field '".$field."' is not a valid field of the entity ".
|
||||
"'".get_class($this->getEntity())."' in PreInsertUpdateEventArgs."
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -752,16 +752,14 @@ class UnitOfWork implements PropertyChangedListener
|
||||
|
||||
if ($hasPreUpdateLifecycleCallbacks) {
|
||||
$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);
|
||||
}
|
||||
|
||||
if ($hasPreUpdateListeners) {
|
||||
$this->_evm->dispatchEvent(Events::preUpdate, new Event\PreUpdateEventArgs(
|
||||
$entity, $this->_em, $this->_entityChangeSets[$oid])
|
||||
);
|
||||
}
|
||||
|
||||
$persister->update($entity);
|
||||
unset($this->_entityUpdates[$oid]);
|
||||
|
@ -1,6 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace Doctrine\Tests\ORM\Functional;
|
||||
use Doctrine\ORM\Event\PreUpdateEventArgs;
|
||||
|
||||
require_once __DIR__ . '/../../TestInit.php';
|
||||
|
||||
@ -111,6 +112,32 @@ class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase
|
||||
$childMeta = $this->_em->getClassMetadata(__NAMESPACE__ . '\LifecycleCallbackChildEntity');
|
||||
$this->assertEquals(array('prePersist' => array(0 => 'doStuff')), $childMeta->lifecycleCallbacks);
|
||||
}
|
||||
|
||||
public function testLifecycleListener_ChangeUpdateChangeSet()
|
||||
{
|
||||
$listener = new LifecycleListenerPreUpdate;
|
||||
$this->_em->getEventManager()->addEventListener(array('preUpdate'), $listener);
|
||||
|
||||
$user = new LifecycleCallbackTestUser;
|
||||
$user->setName('Bob');
|
||||
$user->setValue('value');
|
||||
$this->_em->persist($user);
|
||||
$this->_em->flush();
|
||||
$this->_em->clear();
|
||||
|
||||
$dql = "SELECT u FROM Doctrine\Tests\ORM\Functional\LifecycleCallbackTestUser u WHERE u.name = 'Bob'";
|
||||
$bob = $this->_em->createQuery($dql)->getSingleResult();
|
||||
$bob->setName('Alice');
|
||||
|
||||
$this->_em->flush(); // preUpdate reverts Alice to Bob
|
||||
$this->_em->clear();
|
||||
|
||||
$this->_em->getEventManager()->removeEventListener(array('preUpdate'), $listener);
|
||||
|
||||
$bob = $this->_em->createQuery($dql)->getSingleResult();
|
||||
|
||||
$this->assertEquals('Bob', $bob->getName());
|
||||
}
|
||||
}
|
||||
|
||||
/** @Entity @HasLifecycleCallbacks */
|
||||
@ -219,3 +246,11 @@ class LifecycleCallbackChildEntity extends LifecycleCallbackParentEntity {
|
||||
/** @Id @Column(type="integer") @GeneratedValue */
|
||||
private $id;
|
||||
}
|
||||
|
||||
class LifecycleListenerPreUpdate
|
||||
{
|
||||
public function preUpdate(PreUpdateEventArgs $eventArgs)
|
||||
{
|
||||
$eventArgs->setNewValue('name', 'Bob');
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user