From 94d771172e63c8a5d73e3f1afc24a6871556a52f Mon Sep 17 00:00:00 2001 From: romanb Date: Fri, 13 Nov 2009 16:39:28 +0000 Subject: [PATCH] [2.0][DDC-74] Fixed. --- lib/Doctrine/ORM/UnitOfWork.php | 46 ++++++++++--------- .../ORM/Functional/LifecycleCallbackTest.php | 41 ++++++++++++++++- 2 files changed, 63 insertions(+), 24 deletions(-) diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 76583c7e5..c38c697eb 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -613,15 +613,22 @@ class UnitOfWork implements PropertyChangedListener * Computes the changeset of an individual entity, independently of the * computeChangeSets() routine that is used at the beginning of a UnitOfWork#commit(). * - * The passed entity must be a managed entity. + * The passed entity must be a managed entity. If the entity already has a change set + * because this method is invoked during a commit cycle then the change sets are added. + * whereby changes detected in this method prevail. * * @ignore - * @param $class - * @param $entity + * @param ClassMetadata $class The class descriptor of the entity. + * @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) { $oid = spl_object_hash($entity); + + if ( ! isset($this->_entityStates[$oid]) || $this->_entityStates[$oid] != self::STATE_MANAGED) { + throw new \InvalidArgumentException('Entity must be managed.'); + } if ( ! $class->isInheritanceTypeNone()) { $class = $this->_em->getClassMetadata(get_class($entity)); @@ -634,28 +641,23 @@ class UnitOfWork implements PropertyChangedListener } } - if ( ! isset($this->_originalEntityData[$oid])) { - $this->_originalEntityData[$oid] = $actualData; - $this->_entityChangeSets[$oid] = array_map( - function($e) { return array(null, $e); }, $actualData - ); - } else { - $originalData = $this->_originalEntityData[$oid]; - $changeSet = array(); + $originalData = $this->_originalEntityData[$oid]; + $changeSet = array(); - foreach ($actualData as $propName => $actualValue) { - $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null; - if (is_object($orgValue) && $orgValue !== $actualValue) { - $changeSet[$propName] = array($orgValue, $actualValue); - } else if ($orgValue != $actualValue || ($orgValue === null ^ $actualValue === null)) { - $changeSet[$propName] = array($orgValue, $actualValue); - } + foreach ($actualData as $propName => $actualValue) { + $orgValue = isset($originalData[$propName]) ? $originalData[$propName] : null; + if (is_object($orgValue) && $orgValue !== $actualValue) { + $changeSet[$propName] = array($orgValue, $actualValue); + } else if ($orgValue != $actualValue || ($orgValue === null ^ $actualValue === null)) { + $changeSet[$propName] = array($orgValue, $actualValue); } - - if ($changeSet) { - $this->_entityChangeSets[$oid] = $changeSet; - $this->_originalEntityData[$oid] = $actualData; + } + + if ($changeSet) { + if (isset($this->_entityChangeSets[$oid])) { + $this->_entityChangeSets[$oid] = $changeSet + $this->_entityChangeSets[$oid]; } + $this->_originalEntityData[$oid] = $actualData; } } diff --git a/tests/Doctrine/Tests/ORM/Functional/LifecycleCallbackTest.php b/tests/Doctrine/Tests/ORM/Functional/LifecycleCallbackTest.php index d37cdb367..b655d8cea 100644 --- a/tests/Doctrine/Tests/ORM/Functional/LifecycleCallbackTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/LifecycleCallbackTest.php @@ -10,7 +10,8 @@ class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase parent::setUp(); try { $this->_schemaTool->createSchema(array( - $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity') + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestEntity'), + $this->_em->getClassMetadata('Doctrine\Tests\ORM\Functional\LifecycleCallbackTestUser') )); } catch (\Exception $e) { // Swallow all exceptions. We do not test the schema tool here. @@ -39,6 +40,42 @@ class LifecycleCallbackTest extends \Doctrine\Tests\OrmFunctionalTestCase $this->assertEquals('changed from preUpdate callback!', $result[0]->value); } + + public function testChangesDontGetLost() + { + $user = new LifecycleCallbackTestUser; + $user->setName('Bob'); + $user->setValue(''); + $this->_em->persist($user); + $this->_em->flush(); + + $user->setName('Alice'); + $this->_em->flush(); // Triggers preUpdate + + $this->_em->clear(); + + $user2 = $this->_em->find(get_class($user), $user->getId()); + + $this->assertEquals('Alice', $user2->getName()); + $this->assertEquals('Hello World', $user2->getValue()); + } +} + +/** @Entity @HasLifecycleCallbacks */ +class LifecycleCallbackTestUser { + /** @Id @Column(type="integer") @GeneratedValue(strategy="AUTO") */ + private $id; + /** @Column(type="string") */ + private $value; + /** @Column(type="string") */ + private $name; + public function getId() {return $this->id;} + public function getValue() {return $this->value;} + public function setValue($value) {$this->value = $value;} + public function getName() {return $this->name;} + public function setName($name) {$this->name = $name;} + /** @PreUpdate */ + public function testCallback() {$this->value = 'Hello World';} } /** @@ -59,7 +96,7 @@ class LifecycleCallbackTestEntity */ private $id; /** - * @Column(type="string", length=255) + * @Column(type="string") */ public $value;