Permalink
Browse files

Merge pull request #253 from doctrine/PHPCR-98-handle-child-replacing

[PHPCR-98] and allow replacing child documents
  • Loading branch information...
2 parents 076acf8 + e19624b commit 30db6258a00bfade6a955ef5e7caa77dfa201446 @dbu dbu committed Feb 28, 2013
@@ -20,6 +20,7 @@
namespace Doctrine\ODM\PHPCR;
use Doctrine\ODM\PHPCR\Mapping\ClassMetadata;
+use PHPCR\Util\PathHelper;
use PHPCR\Util\NodeHelper;
use PHPCR\PathNotFoundException;
use Doctrine\ODM\PHPCR\Exception\CascadeException;
@@ -902,13 +903,13 @@ private function getDocumentActualData(ClassMetadata $class, $document)
return $actualData;
}
- private function getChildNodename($id, $nodename, $child)
+ private function getChildNodename($id, $nodename, $child, $parent)
{
$childClass = $this->dm->getClassMetadata(get_class($child));
if ($childClass->nodename && $childClass->reflFields[$childClass->nodename]->getValue($child)) {
$nodename = $childClass->reflFields[$childClass->nodename]->getValue($child);
} else {
- $childId = $childClass->getIdentifierValue($child);
+ $childId = $childClass->getIdentifierValue($child) ?: $this->getIdGenerator($childClass->idGenerator)->generate($child, $childClass, $this->dm, $parent);
if ('' !== $childId) {
if ($childId !== $id.'/'.basename($childId)) {
throw PHPCRException::cannotMoveByAssignment(self::objToStr($child, $this->dm));
@@ -954,8 +955,8 @@ public function computeChangeSet(ClassMetadata $class, $document)
$mapping = $class->mappings[$fieldName];
if ($actualData[$fieldName]) {
foreach ($actualData[$fieldName] as $nodename => $child) {
- $nodename = $this->getChildNodename($id, $nodename, $child);
- $this->computeChildChanges($mapping, $child, $id, $nodename, $document);
+ $nodename = $this->getChildNodename($id, $nodename, $child, $document);
+ $actualData[$fieldName][$nodename] = $this->computeChildChanges($mapping, $child, $id, $nodename, $document);
$childNames[] = $nodename;
}
}
@@ -974,11 +975,8 @@ public function computeChangeSet(ClassMetadata $class, $document)
foreach ($class->childMappings as $fieldName) {
if ($actualData[$fieldName]) {
- if ($this->originalData[$oid][$fieldName] && $this->originalData[$oid][$fieldName] !== $actualData[$fieldName]) {
- throw PHPCRException::cannotMoveByAssignment(self::objToStr($actualData[$fieldName], $this->dm));
- }
$mapping = $class->mappings[$fieldName];
- $this->computeChildChanges($mapping, $actualData[$fieldName], $id);
+ $actualData[$fieldName] = $this->computeChildChanges($mapping, $actualData[$fieldName], $id, $mapping['name']);
}
}
@@ -1072,8 +1070,8 @@ public function computeChangeSet(ClassMetadata $class, $document)
$childNames = array();
if ($actualData[$fieldName]) {
foreach ($actualData[$fieldName] as $nodename => $child) {
- $nodename = $this->getChildNodename($id, $nodename, $child);
- $this->computeChildChanges($mapping, $child, $id, $nodename, $document);
+ $nodename = $this->getChildNodename($id, $nodename, $child, $document);
+ $actualData[$fieldName][$nodename] = $this->computeChildChanges($mapping, $child, $id, $nodename, $document);
$childNames[] = $nodename;
}
}
@@ -1145,8 +1143,10 @@ public function computeChangeSet(ClassMetadata $class, $document)
* @param string $parentId
* @param string $nodename
* @param mixed $parent
+ *
+ * @return object the child instance (if we are replacing a child this can be a different instance than was originally provided)
*/
- private function computeChildChanges($mapping, $child, $parentId, $nodename = null, $parent = null)
+ private function computeChildChanges($mapping, $child, $parentId, $nodename, $parent = null)
{
$targetClass = $this->dm->getClassMetadata(get_class($child));
$state = $this->getDocumentState($child);
@@ -1156,16 +1156,27 @@ private function computeChildChanges($mapping, $child, $parentId, $nodename = nu
if (!($mapping['cascade'] & ClassMetadata::CASCADE_PERSIST) ) {
throw CascadeException::newDocumentFound(self::objToStr($child));
}
- $nodename = $nodename ?: $mapping['name'];
- if ($nodename) {
- $targetClass->setIdentifierValue($child, $parentId.'/'.$nodename);
+
+ $childId = $parentId.'/'.$nodename;
+ $targetClass->setIdentifierValue($child, $childId);
+
+ if ($this->getDocumentById($childId)) {
+ $child = $this->merge($child);
+ } else {
+ $this->persistNew($targetClass, $child, ClassMetadata::GENERATOR_TYPE_ASSIGNED, $parent);
}
- $this->persistNew($targetClass, $child, ClassMetadata::GENERATOR_TYPE_ASSIGNED, $parent);
+
$this->computeChangeSet($targetClass, $child);
break;
case self::STATE_DETACHED:
throw new \InvalidArgumentException('A detached document was found through a child relationship during cascading a persist operation: '.self::objToStr($child, $this->dm));
+ default:
+ if (PathHelper::getParentPath($this->getDocumentId($child)) !== $parentId) {
+ throw PHPCRException::cannotMoveByAssignment(self::objToStr($child, $this->dm));
+ }
}
+
+ return $child;
}
/**
@@ -1934,15 +1945,11 @@ private function executeUpdates($documents, $dispatchEvents = true)
}
}
} elseif ('child' === $mapping['type']) {
- if ($fieldValue === null) {
- if ($node->hasNode($mapping['name'])) {
- $child = $node->getNode($mapping['name']);
- $childDocument = $this->getOrCreateDocument(null, $child);
- $this->purgeChildren($childDocument);
- $child->remove();
- }
- } elseif ($this->originalData[$oid][$fieldName] && $this->originalData[$oid][$fieldName] !== $fieldValue) {
- throw PHPCRException::cannotMoveByAssignment(self::objToStr($fieldValue, $this->dm));
+ if ($fieldValue === null && $node->hasNode($mapping['name'])) {
+ $child = $node->getNode($mapping['name']);
+ $childDocument = $this->getOrCreateDocument(null, $child);
+ $this->purgeChildren($childDocument);
+ $child->remove();
}
}
}
@@ -225,7 +225,36 @@ public function testChildSetNull()
$this->assertNull($parent->child);
}
- /* this fails as the newChild is not persisted */
+ /**
+ * @expectedException \Doctrine\ODM\PHPCR\PHPCRException
+ */
+ public function testMoveByAssignment()
+ {
+ $original = new ChildTestObj();
+ $child = new ChildChildTestObj();
+ $original->name = 'Parent';
+ $original->id = '/functional/original';
+ $original->child = $child;
+ $child->name = 'Child';
+
+ $this->dm->persist($original);
+
+ $other = new ChildTestObj();
+ $other->name = 'newparent';
+ $other->id = '/functional/newlocation';
+ $this->dm->persist($other);
+
+ $this->dm->flush();
+ $this->dm->clear();
+
+ $original = $this->dm->find($this->type, '/functional/original');
+ $other = $this->dm->find($this->type, '/functional/newlocation');
+
+ $other->child = $original->child;
+
+ $this->dm->flush();
+ }
+
public function testChildReplace()
{
$parent = new ChildTestObj();
@@ -244,9 +273,11 @@ public function testChildReplace()
$newChild->name = 'new name';
$parent->child = $newChild;
- $this->setExpectedException('Doctrine\ODM\PHPCR\PHPCRException');
-
$this->dm->flush();
+ $this->dm->clear();
+
+ $parent = $this->dm->find($this->type, '/functional/childtest');
+ $this->assertEquals('new name', $parent->child->name);
}
public function testModificationAfterPersist()
Oops, something went wrong.

0 comments on commit 30db625

Please sign in to comment.