private static function addNode(NodeInterface $parentNode, $nodename, $type, array $properties, $uuidBehavior)
{
$forceReferenceable = false;
if (array_key_exists('jcr:uuid', $properties)) {
try {
$existing = $parentNode->getSession()->getNodeByIdentifier($properties['jcr:uuid']['values']);
switch ($uuidBehavior) {
case self::IMPORT_UUID_CREATE_NEW:
unset($properties['jcr:uuid']);
$forceReferenceable = true;
break;
case self::IMPORT_UUID_COLLISION_THROW:
throw new ItemExistsException('There already is a node with uuid ' . $properties['jcr:uuid']['values'] . ' in this workspace.');
case self::IMPORT_UUID_COLLISION_REMOVE_EXISTING:
case self::IMPORT_UUID_COLLISION_REPLACE_EXISTING:
if (self::IMPORT_UUID_COLLISION_REPLACE_EXISTING === $uuidBehavior && 'jcr:root' === $nodename && $existing->getDepth() === 0) {
break;
}
if (!strncmp($existing->getPath() . '/', $parentNode->getPath() . "/{$nodename}", strlen($existing->getPath() . '/'))) {
throw new ConstraintViolationException('Trying to remove/replace parent of the path we are adding to. ' . $existing->getIdentifier() . ' at ' . $existing->getPath());
}
if (self::IMPORT_UUID_COLLISION_REPLACE_EXISTING === $uuidBehavior) {
// replace the found node. spec is not precise: do we keep the name or use the one of existing?
$parentNode = $existing->getParent();
}
$existing->remove();
break;
default:
// @codeCoverageIgnoreStart
throw new RepositoryException("Unexpected type {$uuidBehavior}");
// @codeCoverageIgnoreEnd
}
} catch (ItemNotFoundException $e) {
// nothing to do, we can add the node without conflict
}
}
/* we add a jcr:root somewhere in the tree (either create new ids or
* the root was not referenceable. do not make jackrabbit think it
* would be the real root node.
*/
if ('jcr:root' === $nodename && 'rep:root' === $type) {
$type = 'nt:unstructured';
}
if ('jcr:root' === $nodename && isset($existing) && self::IMPORT_UUID_COLLISION_REPLACE_EXISTING === $uuidBehavior && $existing->getDepth() === 0) {
// update the root node properties
// http://www.day.com/specs/jcr/2.0/11_Import.html#11.9%20Importing%20%3CI%3Ejcr:root%3C/I%3E
NodeHelper::purgeWorkspace($parentNode->getSession());
$node = $existing;
} else {
$node = $parentNode->addNode($nodename, $type);
}
foreach ($properties as $name => $info) {
if ('jcr:primaryType' === $name) {
// handled in node constructor
} elseif ('jcr:mixinTypes' === $name) {
if (is_array($info['values'])) {
foreach ($info['values'] as $type) {
$node->addMixin($type);
}
} else {
$node->addMixin($info['values']);
}
} elseif ('jcr:created' === $name || 'jcr:createdBy' === $name) {
// skip PROTECTED properties. TODO: get the names from node type instead of hardcode
} elseif ('jcr:uuid' === $name) {
//avoid to throw an exception when trying to set a UUID when importing from XML
$node->setProperty($name, $info['values'], $info['type'], false);
} else {
$node->setProperty($name, $info['values'], $info['type']);
}
}
if ($forceReferenceable && !$node->isNodeType('mix:referenceable')) {
$node->addMixin('mix:referenceable');
}
return $node;
}