diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php index 83eab8cf1ab..9c0439f5963 100644 --- a/lib/Doctrine/ORM/PersistentCollection.php +++ b/lib/Doctrine/ORM/PersistentCollection.php @@ -470,6 +470,10 @@ public function set($key, $value) parent::set($key, $value); $this->changed(); + + if ($this->em) { + $this->em->getUnitOfWork()->cancelOrphanRemoval($value); + } } /** @@ -481,6 +485,10 @@ public function add($value) $this->changed(); + if ($this->em) { + $this->em->getUnitOfWork()->cancelOrphanRemoval($value); + } + return true; } diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php index fe12e55df8c..0c036a86ced 100644 --- a/lib/Doctrine/ORM/UnitOfWork.php +++ b/lib/Doctrine/ORM/UnitOfWork.php @@ -2430,6 +2430,21 @@ public function scheduleOrphanRemoval($entity) $this->orphanRemovals[spl_object_hash($entity)] = $entity; } + /** + * INTERNAL: + * Cancels a previously scheduled orphan removal. + * + * @ignore + * + * @param object $entity + * + * @return void + */ + public function cancelOrphanRemoval($entity) + { + unset($this->orphanRemovals[spl_object_hash($entity)]); + } + /** * INTERNAL: * Schedules a complete collection for removal when this UnitOfWork commits. diff --git a/tests/Doctrine/Tests/ORM/Functional/OneToManyOrphanRemovalTest.php b/tests/Doctrine/Tests/ORM/Functional/OneToManyOrphanRemovalTest.php index c17a8e07c50..640f078d945 100644 --- a/tests/Doctrine/Tests/ORM/Functional/OneToManyOrphanRemovalTest.php +++ b/tests/Doctrine/Tests/ORM/Functional/OneToManyOrphanRemovalTest.php @@ -24,10 +24,14 @@ protected function setUp() $user->username = 'romanb'; $user->name = 'Roman B.'; - $phone = new CmsPhonenumber; - $phone->phonenumber = '123456'; + $phone1 = new CmsPhonenumber; + $phone1->phonenumber = '123456'; - $user->addPhonenumber($phone); + $phone2 = new CmsPhonenumber; + $phone2->phonenumber = '234567'; + + $user->addPhonenumber($phone1); + $user->addPhonenumber($phone2); $this->_em->persist($user); $this->_em->flush(); @@ -55,6 +59,44 @@ public function testOrphanRemoval() $this->assertEquals(0, count($result), 'CmsPhonenumber should be removed by orphanRemoval'); } + /** + * @group DDC-3382 + */ + public function testOrphanRemovalRemoveFromCollection() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + + $phonenumber = $user->getPhonenumbers()->remove(0); + + $this->_em->flush(); + $this->_em->clear(); + + $query = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p'); + $result = $query->getResult(); + + $this->assertEquals(1, count($result), 'CmsPhonenumber should be removed by orphanRemoval'); + } + + /** + * @group DDC-3382 + */ + public function testOrphanRemovalClearCollectionAndReAdd() + { + $user = $this->_em->find('Doctrine\Tests\Models\CMS\CmsUser', $this->userId); + + $phone1 = $user->getPhonenumbers()->first(); + + $user->getPhonenumbers()->clear(); + $user->addPhonenumber($phone1); + + $this->_em->flush(); + + $query = $this->_em->createQuery('SELECT p FROM Doctrine\Tests\Models\CMS\CmsPhonenumber p'); + $result = $query->getResult(); + + $this->assertEquals(1, count($result), 'CmsPhonenumber should be removed by orphanRemoval'); + } + /** * @group DDC-1496 */ diff --git a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php index 016961935a1..a63eab8eb0d 100644 --- a/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php +++ b/tests/Doctrine/Tests/ORM/Functional/Ticket/DDC1654Test.php @@ -16,6 +16,14 @@ public function setUp() )); } + public function tearDown() + { + $conn = static::$_sharedConn; + $conn->executeUpdate('DELETE FROM ddc1654post_ddc1654comment'); + $conn->executeUpdate('DELETE FROM DDC1654Comment'); + $conn->executeUpdate('DELETE FROM DDC1654Post'); + } + public function testManyToManyRemoveFromCollectionOrphanRemoval() { $post = new DDC1654Post(); @@ -54,6 +62,29 @@ public function testManyToManyRemoveElementFromCollectionOrphanRemoval() $this->assertEquals(0, count($comments)); } + /** + * @group DDC-3382 + */ + public function testManyToManyRemoveElementFromReAddToCollectionOrphanRemoval() + { + $post = new DDC1654Post(); + $post->comments[] = new DDC1654Comment(); + $post->comments[] = new DDC1654Comment(); + + $this->_em->persist($post); + $this->_em->flush(); + + $comment = $post->comments[0]; + $post->comments->removeElement($comment); + $post->comments->add($comment); + + $this->_em->flush(); + $this->_em->clear(); + + $comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll(); + $this->assertEquals(2, count($comments)); + } + public function testManyToManyClearCollectionOrphanRemoval() { $post = new DDC1654Post(); @@ -72,6 +103,29 @@ public function testManyToManyClearCollectionOrphanRemoval() $this->assertEquals(0, count($comments)); } + + /** + * @group DDC-3382 + */ + public function testManyToManyClearCollectionReAddOrphanRemoval() + { + $post = new DDC1654Post(); + $post->comments[] = new DDC1654Comment(); + $post->comments[] = new DDC1654Comment(); + + $this->_em->persist($post); + $this->_em->flush(); + + $comment = $post->comments[0]; + $post->comments->clear(); + $post->comments->add($comment); + + $this->_em->flush(); + $this->_em->clear(); + + $comments = $this->_em->getRepository(__NAMESPACE__ . '\\DDC1654Comment')->findAll(); + $this->assertEquals(1, count($comments)); + } } /**