Permalink
Browse files

initial work on supporting automatic persisting/removing of children …

…collections
  • Loading branch information...
1 parent a8434f0 commit a2dc3bc827ded1f54c7bd4708c4e495935ad39e5 @lsmith77 lsmith77 committed Feb 15, 2012
Showing with 93 additions and 4 deletions.
  1. +47 −4 lib/Doctrine/ODM/PHPCR/UnitOfWork.php
  2. +46 −0 tests/Doctrine/Tests/ODM/PHPCR/Functional/ChildrenTest.php
View
51 lib/Doctrine/ODM/PHPCR/UnitOfWork.php
@@ -384,6 +384,9 @@ public function createDocument($className, $node, array &$hints = array())
foreach ($class->reflFields as $prop => $reflFields) {
$value = isset($documentState[$prop]) ? $documentState[$prop] : null;
$reflFields->setValue($document, $value);
+ if ($value instanceof ChildrenCollection) {
+ $value = clone $value;
@lsmith77
lsmith77 Feb 15, 2012

this is causing the HierarchyTest to fail .. and probably its not the right approach anyway .. but without it .. the original collection is updated when the user does changes to the collection on the object and so changes cannot be detected properly.

@lsmith77
lsmith77 Feb 16, 2012

btw .. i think this approach isn't good because i think this requires loading all the children in order to be able to determine which elements in the collection have been added or removed. ideally PHPCR would be adjusted to provide a method on NodeInterface to fetch the names of all the child nodes.

/cc @dbu

+ }
$this->originalData[$oid][$prop] = $value;
}
}
@@ -885,6 +888,47 @@ public function computeChangeSet(ClassMetadata $class, $document)
}
}
+ foreach ($class->childrenMappings as $name => $childMapping) {
+ if (empty($actualData[$name])) {
+ if ($this->originalData[$oid][$name]) {
+ foreach ($this->originalData[$oid][$name] as $child) {
+ $this->scheduleRemove($child);
+ }
+ }
+
+ continue;
+ }
+
+ if ($this->originalData[$oid][$name]) {
+ $childIds = array();
+
+ foreach ($actualData[$name] as $child) {
+ $childClass = $this->dm->getClassMetadata(get_class($child));
+ $nodename = $childClass->nodename
+ ? $childClass->reflFields[$childClass->nodename]->getValue($child)
+ : basename($childClass->getIdentifierValue($child));
+ $this->computeChildChanges($childMapping, $child, $id, $nodename);
+ $childIds[] = $this->documentIds[spl_object_hash($child)];
+ }
+
+ foreach ($this->originalData[$oid][$name] as $child) {
+ $childId = $this->documentIds[spl_object_hash($child)];
+ if (!in_array($childId, $childIds)) {
+ $this->scheduleRemove($child);
+ }
+ }
+
+ } else {
+ foreach ($actualData[$name] as $child) {
+ $childClass = $this->dm->getClassMetadata(get_class($child));
+ $nodename = $childClass->nodename
+ ? $childClass->reflFields[$childClass->nodename]->getValue($child)
+ : basename($childClass->getIdentifierValue($child));
+ $this->computeChildChanges($childMapping, $child, $id, $nodename);
+ }
+ }
+ }
+
foreach ($class->associationsMappings as $assocName => $assoc) {
if ($actualData[$assocName]) {
if (is_array($actualData[$assocName]) || $actualData[$assocName] instanceof Collection) {
@@ -913,17 +957,16 @@ public function computeChangeSet(ClassMetadata $class, $document)
*
* @param mixed $child the child document.
*/
- private function computeChildChanges($mapping, $child, $parentId)
+ private function computeChildChanges($mapping, $child, $parentId, $nodename = null)
{
$targetClass = $this->dm->getClassMetadata(get_class($child));
$state = $this->getDocumentState($child);
if ($state === self::STATE_NEW) {
- $targetClass->setIdentifierValue($child, $parentId.'/'.$mapping['name']);
+ $nodename = $nodename ?: $mapping['name'];
+ $targetClass->setIdentifierValue($child, $parentId.'/'.$nodename);
$this->persistNew($targetClass, $child, ClassMetadata::GENERATOR_TYPE_ASSIGNED);
$this->computeChangeSet($targetClass, $child);
- } elseif ($state === self::STATE_REMOVED) {
- throw new \InvalidArgumentException('Removed child document detected during flush');
@lsmith77
lsmith77 Feb 15, 2012

i am not sure why we have this error to begin with ..

} elseif ($state === self::STATE_DETACHED) {
throw new \InvalidArgumentException('A detached document was found through a child relationship during cascading a persist operation.');
}
View
46 tests/Doctrine/Tests/ODM/PHPCR/Functional/ChildrenTest.php
@@ -141,6 +141,52 @@ public function testRemoveChildParent()
$parent = $this->dm->find('Doctrine\Tests\ODM\PHPCR\Functional\ChildrenTestObj', '/functional/parent');
$this->assertNull($parent);
}
+
+ public function testModifyChildren()
+ {
+ $parent = $this->dm->find('Doctrine\Tests\ODM\PHPCR\Functional\ChildrenTestObj', '/functional/parent');
+ $this->assertCount(4, $parent->allChildren);
+
+ $child = $parent->allChildren->first();
+ $child->name = 'New name';
+
+ $parent->allChildren->remove('child-b');
+ $parent->allChildren->remove('child-c');
+
+ $child = new ChildrenTestObj();
+ $child->id = '/functional/parent/child-e';
+ $child->name = 'Child E';
+
+ $parent->allChildren->add($child);
+ $this->assertCount(3, $parent->allChildren);
+
+ $this->dm->flush();
+ $this->dm->clear();
+
+ $parent = $this->dm->find('Doctrine\Tests\ODM\PHPCR\Functional\ChildrenTestObj', '/functional/parent');
+ $this->assertEquals('New name', $parent->allChildren->first()->name);
+ $this->assertCount(3, $parent->allChildren);
+
+ $parent->allChildren->clear();
+
+ $this->dm->flush();
+ $this->dm->clear();
+
+ $parent = $this->dm->find('Doctrine\Tests\ODM\PHPCR\Functional\ChildrenTestObj', '/functional/parent');
+ $this->assertCount(0, $parent->allChildren);
+
+ $child = new ChildrenTestObj();
+ $child->id = '/functional/parent/child-f';
+ $child->name = 'Child F';
+
+ $parent->allChildren->add($child);
+
+ $this->dm->flush();
+ $this->dm->clear();
+
+ $parent = $this->dm->find('Doctrine\Tests\ODM\PHPCR\Functional\ChildrenTestObj', '/functional/parent');
+ $this->assertCount(1, $parent->allChildren);
+ }
}
/**

0 comments on commit a2dc3bc

Please sign in to comment.