Skip to content

Instantly share code, notes, and snippets.

@doctrinebot
Created December 13, 2015 18:49
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save doctrinebot/43212926007c27f7a6e5 to your computer and use it in GitHub Desktop.
Save doctrinebot/43212926007c27f7a6e5 to your computer and use it in GitHub Desktop.
Attachments to Doctrine Jira Issue DDC-758 - https://github.com/doctrine/doctrine2/issues/5271
<?php
namespace Doctrine\Tests\ORM\Functional\Ticket;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Tests\Models\CMS\CmsUser;
use Doctrine\Tests\Models\CMS\CmsPhonenumber;
use Doctrine\Tests\Models\CMS\CmsGroup;
require_once __DIR__ . '/../../../TestInit.php';
class DDC758Test extends \Doctrine\Tests\OrmFunctionalTestCase {
public function setUp() {
$this->useModelSet("cms");
parent::setUp();
}
/**
* Helper method to set cascade to merge only
*/
private function setCascadeMergeFor($class) {
$metadata = $this->_em->getMetadataFactory()->getMetaDataFor($class);
foreach ($metadata->associationMappings as $key => $associationMapping) {
$metadata->associationMappings[$key]["isCascadePersist"] = false;
$metadata->associationMappings[$key]["isCascadeMerge"] = true;
$metadata->associationMappings[$key]["isCascadeRemove"] = false;
$metadata->associationMappings[$key]["isCascadeDetach"] = false;
}
}
/**
* Test that changing associations on detached entities and then cascade merging them causes the database to be updated with the new associations.
* This specifically tests adding new associations.
*/
public function testManyToManyMergeAssociationAdds() {
$this->setCascadeMergeFor('Doctrine\Tests\Models\CMS\CmsUser');
$this->setCascadeMergeFor('Doctrine\Tests\Models\CMS\CmsGroup');
// Put entities in the database
$cmsUser = new CmsUser();
$cmsUser->username = "dave";
$cmsUser->name = "Dave Keen";
$cmsUser->status = "testing";
$group1 = new CmsGroup();
$group1->name = "Group 1";
$group2 = new CmsGroup();
$group2->name = "Group 2";
$this->_em->persist($cmsUser);
$this->_em->persist($group1);
$this->_em->persist($group2);
$this->_em->flush();
$cmsUserId = $cmsUser->id;
$group1Id = $group1->id;
$group2Id = $group2->id;
$this->_em->clear();
// Now create detached versions of the entities with some new associations.
$cmsUser = new CmsUser();
$cmsUser->id = $cmsUserId;
$cmsUser->username = "dave";
$cmsUser->name = "Dave Keen";
$cmsUser->status = "testing";
$cmsUser->groups = new ArrayCollection();
$group1 = new CmsGroup();
$group1->id = $group1Id;
$group1->name = "Group 1";
$group1->users = new ArrayCollection();
$group2 = new CmsGroup();
$group2->id = $group2Id;
$group2->name = "Group 2";
$group2->users = new ArrayCollection();
$cmsUser->addGroup($group1);
$cmsUser->addGroup($group2);
// Cascade merge of cmsUser followed by a flush should add in the birectional new many-to-many associations between the user and the groups
$this->_em->merge($cmsUser);
$this->_em->flush();
$this->_em->clear();
$cmsUsers = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->findAll();
$cmsGroups = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll();
// Check the entities are in the database
$this->assertEquals(1, sizeof($cmsUsers));
$this->assertEquals(2, sizeof($cmsGroups));
// Check the associations between the entities are now in the database
$this->assertEquals(2, sizeof($cmsUsers[0]->groups));
$this->assertEquals(1, sizeof($cmsGroups[0]->users));
$this->assertEquals(1, sizeof($cmsGroups[1]->users));
$this->assertSame($cmsUsers[0]->groups[0], $cmsGroups[0]);
$this->assertSame($cmsUsers[0]->groups[1], $cmsGroups[1]);
$this->assertSame($cmsGroups[0]->users[0], $cmsUsers[0]);
$this->assertSame($cmsGroups[1]->users[0], $cmsUsers[0]);
}
/**
* Test that changing associations on detached entities and then cascade merging them causes the database to be updated with the new associations.
*/
public function testManyToManyMergeAssociationRemoves() {
$this->setCascadeMergeFor('Doctrine\Tests\Models\CMS\CmsUser');
$this->setCascadeMergeFor('Doctrine\Tests\Models\CMS\CmsGroup');
$cmsUser = new CmsUser();
$cmsUser->username = "dave";
$cmsUser->name = "Dave Keen";
$cmsUser->status = "testing";
$group1 = new CmsGroup();
$group1->name = "Group 1";
$group2 = new CmsGroup();
$group2->name = "Group 2";
$cmsUser->addGroup($group1);
$cmsUser->addGroup($group2);
$this->_em->persist($cmsUser);
$this->_em->persist($group1);
$this->_em->persist($group2);
$this->_em->flush();
$cmsUserId = $cmsUser->id;
$group1Id = $group1->id;
$group2Id = $group2->id;
$this->_em->clear();
// Now create detached versions of the entities with NO associations.
$cmsUser = new CmsUser();
$cmsUser->id = $cmsUserId;
$cmsUser->username = "dave";
$cmsUser->name = "Dave Keen";
$cmsUser->status = "testing";
$cmsUser->groups = new ArrayCollection();
$group1 = new CmsGroup();
$group1->id = $group1Id;
$group1->name = "Group 1";
$group1->users = new ArrayCollection();
$group2 = new CmsGroup();
$group2->id = $group2Id;
$group2->name = "Group 2";
$group2->users = new ArrayCollection();
// Cascade merge of cmsUser followed by a flush should result in the association array collection being empty
$this->_em->merge($cmsUser);
$this->_em->flush();
$this->_em->clear();
$cmsUsers = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsUser')->findAll();
$cmsGroups = $this->_em->getRepository('Doctrine\Tests\Models\CMS\CmsGroup')->findAll();
// Check the entities are in the database
$this->assertEquals(1, sizeof($cmsUsers));
$this->assertEquals(2, sizeof($cmsGroups));
// Check the associations between the entities are now in the database
$this->assertEquals(0, sizeof($cmsUsers[0]->groups));
$this->assertEquals(0, sizeof($cmsGroups[0]->users));
$this->assertEquals(0, sizeof($cmsGroups[1]->users));
}
}
From ffc47733b73528dd520189a1af12f12e7c05f1b4 Mon Sep 17 00:00:00 2001
From: Dave Keen <dev@ruffness.com>
Date: Wed, 22 Sep 2010 00:06:35 +0200
Subject: [PATCH 147/147] DDC-758
---
lib/Doctrine/ORM/PersistentCollection.php | 11 +++++++++++
lib/Doctrine/ORM/UnitOfWork.php | 3 +++
2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/lib/Doctrine/ORM/PersistentCollection.php b/lib/Doctrine/ORM/PersistentCollection.php
index 6c09e96..4380d5e 100644
--- a/lib/Doctrine/ORM/PersistentCollection.php
+++ b/lib/Doctrine/ORM/PersistentCollection.php
@@ -217,6 +217,17 @@ final class PersistentCollection implements Collection
}
}
+ public function takeSnapshotFromDatabase()
+ {
+ $dummyCollection = new PersistentCollection($this->em, $this->typeClass, new \Doctrine\Common\Collections\ArrayCollection());
+ $dummyCollection->setOwner($this->owner, $this->association);
+ $this->em->getUnitOfWork()->loadCollection($dummyCollection);
+
+ $this->snapshot = $dummyCollection->coll->toArray();
+
+ $this->setDirty(true);
+ }
+
/**
* INTERNAL:
* Tells this collection to take a snapshot of its current state.
diff --git a/lib/Doctrine/ORM/UnitOfWork.php b/lib/Doctrine/ORM/UnitOfWork.php
index e3cd015..a051785 100644
--- a/lib/Doctrine/ORM/UnitOfWork.php
+++ b/lib/Doctrine/ORM/UnitOfWork.php
@@ -1634,6 +1634,9 @@ class UnitOfWork implements PropertyChangedListener
foreach ($relatedEntities as $relatedEntity) {
$this->doMerge($relatedEntity, $visited, $managedCopy, $assoc);
}
+ // Now we want to initialize $snapshot to whatever was originally in the database
+ $managedCollection = $class->reflFields[$assoc['fieldName']]->getValue($managedCopy);
+ $managedCollection->takeSnapshotFromDatabase();
} else if ($relatedEntities !== null) {
$this->doMerge($relatedEntities, $visited, $managedCopy, $assoc);
}
--
1.6.5.1.1367.gcd48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment