Jackalope\Node::addNode PHP Method

addNode() public method

{@inheritDoc} In Jackalope, the child node type definition is immediately applied if no primaryNodeTypeName is specified. The PathNotFoundException and ConstraintViolationException are thrown immediately. Version and Lock related exceptions are delayed until save.
public addNode ( $relPath, $primaryNodeTypeName = null )
    public function addNode($relPath, $primaryNodeTypeName = null)
    {
        $relPath = (string) $relPath;
        $this->checkState();
        $ntm = $this->session->getWorkspace()->getNodeTypeManager();
        // are we not the immediate parent?
        if (strpos($relPath, '/') !== false) {
            // forward to real parent
            $relPath = PathHelper::absolutizePath($relPath, $this->getPath(), true);
            $parentPath = PathHelper::getParentPath($relPath);
            $newName = PathHelper::getNodeName($relPath);
            try {
                $parentNode = $this->objectManager->getNodeByPath($parentPath);
            } catch (ItemNotFoundException $e) {
                //we have to throw a different exception if there is a property
                // with that name than if there is nothing at the path at all.
                // lets see if the property exists
                if ($this->session->propertyExists($parentPath)) {
                    throw new ConstraintViolationException("Node '{$this->path}': Not allowed to add a node below property at {$parentPath}");
                }
                throw new PathNotFoundException($e->getMessage(), $e->getCode(), $e);
            }
            return $parentNode->addNode($newName, $primaryNodeTypeName);
        }
        if (null === $primaryNodeTypeName) {
            if ($this->primaryType === 'rep:root') {
                $primaryNodeTypeName = 'nt:unstructured';
            } else {
                $type = $ntm->getNodeType($this->primaryType);
                $nodeDefinitions = $type->getChildNodeDefinitions();
                foreach ($nodeDefinitions as $def) {
                    if (!is_null($def->getDefaultPrimaryType())) {
                        $primaryNodeTypeName = $def->getDefaultPrimaryTypeName();
                        break;
                    }
                }
            }
            if (is_null($primaryNodeTypeName)) {
                throw new ConstraintViolationException("No matching child node definition found for `{$relPath}' in type `{$this->primaryType}' for node '{$this->path}'. Please specify the type explicitly.");
            }
        }
        // create child node
        //sanity check: no index allowed. TODO: we should verify this is a valid node name
        if (false !== strpos($relPath, ']')) {
            throw new RepositoryException("The node '{$this->path}' does not allow an index in name of newly created node: {$relPath}");
        }
        if (in_array($relPath, $this->nodes, true)) {
            throw new ItemExistsException("The node '{$this->path}' already has a child named '{$relPath}''.");
            //TODO: same-name siblings if nodetype allows for them
        }
        $data = array('jcr:primaryType' => $primaryNodeTypeName);
        $path = $this->getChildPath($relPath);
        $node = $this->factory->get('Node', array($data, $path, $this->session, $this->objectManager, true));
        $this->addChildNode($node, false);
        // no need to check the state, we just checked when entering this method
        $this->objectManager->addNode($path, $node);
        if (is_array($this->originalNodesOrder)) {
            // new nodes are added at the end
            $this->originalNodesOrder[] = $relPath;
        }
        //by definition, adding a node sets the parent to modified
        $this->setModified();
        return $node;
    }

Usage Example

Example #1
0
    /**
     * TODO: we should move that into the common Jackalope BaseTransport or as new method of NodeType
     * it will be helpful for other implementations.
     *
     * Validate this node with the nodetype and generate not yet existing
     * autogenerated properties as necessary.
     *
     * @param Node     $node
     * @param NodeType $def
     */
    private function validateNodeWithType(Node $node, NodeType $def)
    {
        foreach ($def->getDeclaredChildNodeDefinitions() as $childDef) {
            /* @var $childDef NodeDefinitionInterface */
            if (!$node->hasNode($childDef->getName())) {
                if ('*' === $childDef->getName()) {
                    continue;
                }

                if ($childDef->isMandatory() && !$childDef->isAutoCreated()) {
                    throw new RepositoryException(
                        "Child " . $childDef->getName() . " is mandatory, but is not present while ".
                            "saving " . $def->getName() . " at " . $node->getPath()
                    );
                }

                if ($childDef->isAutoCreated()) {
                    $requiredPrimaryTypeNames = $childDef->getRequiredPrimaryTypeNames();
                    $primaryType = count($requiredPrimaryTypeNames) ? current($requiredPrimaryTypeNames) : null;
                    $newNode = $node->addNode($childDef->getName(), $primaryType);
                    $absPath = $node->getPath() . '/' . $childDef->getName();
                    $operation = new AddNodeOperation($absPath, $newNode);
                    $this->additionalNodeAddOperations[] = $operation;
                }
            }
        }

        foreach ($def->getDeclaredPropertyDefinitions() as $propertyDef) {
            /* @var $propertyDef PropertyDefinitionInterface */
            if ('*' == $propertyDef->getName()) {
                continue;
            }

            if (!$node->hasProperty($propertyDef->getName())) {
                if ($propertyDef->isMandatory() && !$propertyDef->isAutoCreated()) {
                    throw new RepositoryException(
                        "Property " . $propertyDef->getName() . " is mandatory, but is not present while ".
                            "saving " . $def->getName() . " at " . $node->getPath()
                    );
                }
                if ($propertyDef->isAutoCreated()) {
                    switch ($propertyDef->getName()) {
                        case 'jcr:uuid':
                            $value = $this->generateUuid();
                            break;
                        case 'jcr:createdBy':
                        case 'jcr:lastModifiedBy':
                            $value = $this->credentials->getUserID();
                            break;
                        case 'jcr:created':
                        case 'jcr:lastModified':
                            $value = new \DateTime();
                            break;
                        case 'jcr:etag':
                            // TODO: http://www.day.com/specs/jcr/2.0/3_Repository_Model.html#3.7.12.1%20mix:etag
                            $value = 'TODO: generate from binary properties of this node';
                            break;

                        default:
                            $defaultValues = $propertyDef->getDefaultValues();
                            if ($propertyDef->isMultiple()) {
                                $value = $defaultValues;
                            } elseif (isset($defaultValues[0])) {
                                $value = $defaultValues[0];
                            } else {
                                // When implementing versionable or activity, we need to handle more properties explicitly
                                throw new RepositoryException('No default value for autocreated property '.
                                    $propertyDef->getName(). ' at '.$node->getPath());
                            }
                    }

                    $node->setProperty(
                        $propertyDef->getName(),
                        $value,
                        $propertyDef->getRequiredType()
                    );
                }
            } elseif ($propertyDef->isAutoCreated()) {
                $prop = $node->getProperty($propertyDef->getName());
                if (!$prop->isModified() && !$prop->isNew()) {
                    switch($propertyDef->getName()) {
                        case 'jcr:lastModified':
                            if ($this->getAutoLastModified()) {
                                $prop->setValue(new \DateTime());
                            }
                            break;
                        case 'jcr:lastModifiedBy':
                            if ($this->getAutoLastModified()) {
                                $prop->setValue($this->credentials->getUserID());
                            }
                            break;
                        case 'jcr:etag':
                            // TODO: update etag if needed
                            break;
                    }

                }
            }
        }

        foreach ($def->getDeclaredSupertypes() as $superType) {
            $this->validateNodeWithType($node, $superType);
        }

        foreach ($node->getProperties() as $property) {
            $this->assertValidProperty($property);
        }
    }