/** * @param object $document * @param string $class * @param string $oid * @param boolean $isNew * @param array $changeSet * @throws Exception\RuntimeException * @throws PHPCRException */ private function computeChildrenChanges($document, $class, $oid, $isNew, $changeSet) { $id = $this->getDocumentId($document, false); foreach ($class->childrenMappings as $fieldName) { if ($changeSet[$fieldName] instanceof PersistentCollection) { if (!$changeSet[$fieldName]->isInitialized()) { continue; } } else { if (null === $changeSet[$fieldName]) { $changeSet[$fieldName] = array(); } if (!is_array($changeSet[$fieldName]) && !$changeSet[$fieldName] instanceof Collection) { throw PHPCRException::childrenFieldNoArray(self::objToStr($document, $this->dm), $fieldName); } $filter = isset($mapping['filter']) ? $mapping['filter'] : null; $fetchDepth = isset($mapping['fetchDepth']) ? $mapping['fetchDepth'] : null; // convert to a PersistentCollection $changeSet[$fieldName] = ChildrenCollection::createFromCollection($this->dm, $document, $changeSet[$fieldName], $filter, $fetchDepth, !$isNew); $class->setFieldValue($document, $fieldName, $changeSet[$fieldName]); $this->originalData[$oid][$fieldName] = $changeSet[$fieldName]; } $mapping = $class->mappings[$fieldName]; $childNames = $movedChildNames = array(); $coid = spl_object_hash($changeSet[$fieldName]); $this->visitedCollections[$coid] = $changeSet[$fieldName]; foreach ($changeSet[$fieldName] as $originalNodename => $child) { if (!is_object($child)) { throw PHPCRException::childrenContainsNonObject(self::objToStr($document, $this->dm), $fieldName, gettype($child)); } $nodename = $this->getChildNodename($id, $originalNodename, $child, $document); $changeSet[$fieldName][$nodename] = $this->computeChildChanges($mapping, $child, $id, $nodename, $document); if (0 !== strcmp($originalNodename, $nodename)) { unset($changeSet[$fieldName][$originalNodename]); $movedChildNames[] = (string) $originalNodename; } $childNames[] = $nodename; } if ($isNew) { continue; } if (!$this->originalData[$oid][$fieldName] instanceof ChildrenCollection) { throw new RuntimeException("OriginalData for a children association contains something else than a ChildrenCollection."); } $this->originalData[$oid][$fieldName]->initialize(); $originalNames = $this->originalData[$oid][$fieldName]->getOriginalNodenames(); foreach ($originalNames as $key => $childName) { // check moved children to not accidentally remove a child that simply moved away. if (!(in_array($childName, $childNames) || in_array($childName, $movedChildNames))) { $child = $this->getDocumentById($id . '/' . $childName); $this->scheduleRemove($child); unset($originalNames[$key]); } } if (!empty($childNames) && isset($originalNames)) { // reindex the arrays to avoid holes in the indexes $originalNames = array_values($originalNames); $originalNames = array_merge($originalNames, array_diff($childNames, $originalNames)); if ($originalNames !== $childNames) { $reordering = NodeHelper::calculateOrderBefore($originalNames, $childNames); if (empty($this->documentChangesets[$oid])) { $this->documentChangesets[$oid] = array('reorderings' => array($reordering)); } else { $this->documentChangesets[$oid]['reorderings'][] = $reordering; } $this->scheduledUpdates[$oid] = $document; } elseif (empty($this->documentChangesets[$oid]['fields'])) { unset($this->documentChangesets[$oid]); unset($this->scheduledUpdates[$oid]); } else { $this->documentChangesets[$oid]['reorderings'] = array(); } } } }