/** * @param Node $node */ private function clearNodeCache(Node $node) { $cacheKey = "nodes: {$node->getPath()}, " . $this->workspaceName; $this->caches['node']->delete($cacheKey); // actually in the DBAL all nodes have a uuid .. if ($node->isNodeType('mix:referenceable')) { $uuid = $node->getIdentifier(); $cacheKey = "nodes by uuid: {$uuid}, " . $this->workspaceName; $this->caches['node']->delete($cacheKey); } }
/** * {@inheritDoc} */ public function reorderChildren(Node $node) { $this->assertLoggedIn(); $values[':absPath'] = $node->getPath(); $sql = "UPDATE phpcr_nodes SET sort_order = CASE CONCAT(\n namespace,\n (CASE namespace WHEN '' THEN '' ELSE ':' END),\n local_name\n )"; $i = 0; foreach ($node->getNodeNames() as $name) { $values[':name' . $i] = $name; $values[':order' . $i] = $i; // use our counter to avoid gaps $sql .= " WHEN :name" . $i . " THEN :order" . $i; $i++; } $sql .= " ELSE sort_order END WHERE parent = :absPath"; try { $this->getConnection()->executeUpdate($sql, $values); } catch (DBALException $e) { throw new RepositoryException('Unexpected exception while reordering nodes', $e->getCode(), $e); } return true; }
/** * 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); } }
/** * 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 validateNode(Node $node, NodeType $def) { foreach ($def->getDeclaredChildNodeDefinitions() as $childDef) { /* @var $childDef \PHPCR\NodeType\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()) { throw new NotImplementedException("Auto-creation of child node '" . $def->getName() . "#" . $childDef->getName() . "' is not yet supported in DoctrineDBAL transport."); } } } foreach ($def->getDeclaredPropertyDefinitions() as $propertyDef) { /* @var $propertyDef \PHPCR\NodeType\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 = UUIDHelper::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()); } } } foreach ($node->getProperties() as $property) { $this->assertValidProperty($property); } }
/** * {@inheritDoc} */ public function updateNode(Node $node, $srcWorkspace) { $path = $this->encodeAndValidatePathForDavex($node->getPath()); $srcWorkspaceUri = $this->server . $srcWorkspace; $body = ' <D:update xmlns:D="DAV:"> <D:workspace> ' . $srcWorkspaceUri . ' <D:href> ' . $srcWorkspaceUri . ' </D:href> </D:workspace> </D:update> '; $request = $this->getRequest(Request::UPDATE, $path, true); $request->setBody($body); $request->execute(); }