public setProperty ( $name, $value, $type = PropertyType::UNDEFINED, boolean $validate = true ) | ||
$validate | boolean | does the NodeType control throw an exception if the property can't be set? To use in case of UUID import |
public function setProperty($name, $value, $type = PropertyType::UNDEFINED, $validate = true)
{
$this->checkState();
if ($validate && 'jcr:uuid' === $name && !$this->isNodeType('mix:referenceable')) {
throw new ConstraintViolationException('You can only change the uuid of newly created nodes that have "referenceable" mixin.');
}
if ($validate) {
if (is_array($value)) {
foreach ($value as $key => $v) {
if (null === $v) {
unset($value[$key]);
}
}
}
$types = $this->getMixinNodeTypes();
array_push($types, $this->getPrimaryNodeType());
if (null !== $value) {
$exception = null;
foreach ($types as $nt) {
/** @var $nt NodeType */
try {
$nt->canSetProperty($name, $value, true);
$exception = null;
break;
// exit loop, we found a valid definition
} catch (RepositoryException $e) {
if (null === $exception) {
$exception = $e;
}
}
}
if (null !== $exception) {
throw $exception;
}
} else {
// $value is null for property removal
// if any type forbids, throw exception
foreach ($types as $nt) {
/** @var $nt \Jackalope\NodeType\NodeType */
$nt->canRemoveProperty($name, true);
}
}
}
//try to get a namespace for the set property
if (strpos($name, ':') !== false) {
list($prefix) = explode(':', $name);
//Check if the namespace exists. If not, throw an NamespaceException
$this->session->getNamespaceURI($prefix);
}
if (is_null($value)) {
if (isset($this->properties[$name])) {
$this->properties[$name]->remove();
}
return null;
}
return $this->_setProperty($name, $value, $type, false);
}
/** * 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); } }