diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index 194e45e30..d27748a99 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -1870,7 +1870,7 @@ class UnitOfWork implements PropertyChangedListener } } - if ($class->isVersioned) { + if ($class->isVersioned && $this->isLoaded($managedCopy) && $this->isLoaded($entity)) { $reflField = $class->reflFields[$class->versionField]; $managedCopyVersion = $reflField->getValue($managedCopy); $entityVersion = $reflField->getValue($entity); @@ -1883,7 +1883,7 @@ class UnitOfWork implements PropertyChangedListener $visited[$oid] = $managedCopy; // mark visited - if (!($entity instanceof Proxy && ! $entity->__isInitialized())) { + if ($this->isLoaded($entity)) { if ($managedCopy instanceof Proxy && ! $managedCopy->__isInitialized()) { $managedCopy->__load(); } @@ -1908,6 +1908,18 @@ class UnitOfWork implements PropertyChangedListener return $managedCopy; } + /** + * Tests if an entity is loaded - must either be a loaded proxy or not a proxy + * + * @param object $entity + * + * @return bool + */ + private function isLoaded($entity) + { + return !($entity instanceof Proxy) || $entity->__isInitialized(); + } + /** * Sets/adds associated managed copies into the previous entity's association field * diff --git a/tests/Doctrine/Tests/Models/VersionedManyToOne/Article.php b/tests/Doctrine/Tests/Models/VersionedManyToOne/Article.php new file mode 100644 index 000000000..0e5b1683f --- /dev/null +++ b/tests/Doctrine/Tests/Models/VersionedManyToOne/Article.php @@ -0,0 +1,37 @@ +useModelSet('versioned_many_to_one'); + + parent::setUp(); + } + + /** + * This test case asserts that a detached and unmodified entity could be merge without firing + * OptimisticLockException. + */ + public function testSetVersionOnCreate() + { + $category = new Category(); + $article = new Article(); + + $article->name = 'Article'; + $article->category = $category; + + $this->_em->persist($article); + $this->_em->flush(); + $this->_em->clear(); + + $articleMerged = $this->_em->merge($article); + + $articleMerged->name = 'Article Merged'; + + $this->_em->flush(); + $this->assertEquals(2, $articleMerged->version); + } +} diff --git a/tests/Doctrine/Tests/OrmFunctionalTestCase.php b/tests/Doctrine/Tests/OrmFunctionalTestCase.php index 855fac617..b36a83487 100644 --- a/tests/Doctrine/Tests/OrmFunctionalTestCase.php +++ b/tests/Doctrine/Tests/OrmFunctionalTestCase.php @@ -280,6 +280,10 @@ abstract class OrmFunctionalTestCase extends OrmTestCase 'Doctrine\Tests\Models\Pagination\User', 'Doctrine\Tests\Models\Pagination\User1', ), + 'versioned_many_to_one' => array( + 'Doctrine\Tests\Models\VersionedManyToOne\Category', + 'Doctrine\Tests\Models\VersionedManyToOne\Article', + ), ); /** @@ -535,6 +539,11 @@ abstract class OrmFunctionalTestCase extends OrmTestCase $conn->executeUpdate('DELETE FROM pagination_user'); } + if (isset($this->_usedModelSets['versioned_many_to_one'])) { + $conn->executeUpdate('DELETE FROM versioned_many_to_one_article'); + $conn->executeUpdate('DELETE FROM versioned_many_to_one_category'); + } + $this->_em->clear(); }