/**
  * Execute moving a single node
  */
 protected function moveNode($srcAbsPath, $dstAbsPath)
 {
     $this->assertLoggedIn();
     PathHelper::assertValidAbsolutePath($srcAbsPath, false, true, $this->getNamespacePrefixes());
     PathHelper::assertValidAbsolutePath($dstAbsPath, true, true, $this->getNamespacePrefixes());
     if (!$this->pathExists($srcAbsPath)) {
         throw new PathNotFoundException("Source path '{$srcAbsPath}' not found");
     }
     if ($this->getSystemIdForNode($dstAbsPath)) {
         throw new ItemExistsException("Cannot move '{$srcAbsPath}' to '{$dstAbsPath}' because destination node already exists.");
     }
     if (!$this->getSystemIdForNode(PathHelper::getParentPath($dstAbsPath))) {
         throw new PathNotFoundException("Parent of the destination path '" . $dstAbsPath . "' has to exist.");
     }
     $query = 'SELECT path, id FROM phpcr_nodes WHERE path LIKE ? OR path = ? AND workspace_name = ? ' . $this->getConnection()->getDatabasePlatform()->getForUpdateSQL();
     $stmt = $this->getConnection()->executeQuery($query, array($srcAbsPath . '/%', $srcAbsPath, $this->workspaceName));
     /*
      * TODO: https://github.com/jackalope/jackalope-doctrine-dbal/pull/26/files#L0R1057
      * the other thing i wonder: can't you do the replacement inside sql instead of loading and then storing
      * the node? this will be extremely slow for a large set of nodes. i think you should use query builder here
      * rather than raw sql, to make it work on a maximum of platforms.
      *
      * can you try to do this please? if we don't figure out how to do it, at least fix the where criteria, and
      * we can ask the doctrine community how to do the substring operation.
      * http://stackoverflow.com/questions/8619421/correct-syntax-for-doctrine2s-query-builder-substring-helper-method
      */
     $query = "UPDATE phpcr_nodes SET ";
     $updatePathCase = "path = CASE ";
     $updateParentCase = "parent = CASE ";
     $updateLocalNameCase = "local_name = CASE ";
     $updateSortOrderCase = "sort_order = CASE ";
     $updateDepthCase = "depth = CASE ";
     // TODO: Find a better way to do this
     // Calculate CAST type for CASE statement
     switch ($this->getConnection()->getDatabasePlatform()->getName()) {
         case 'pgsql':
             $intType = 'integer';
             break;
         case 'mysql':
             $intType = 'unsigned';
             break;
         default:
             $intType = 'integer';
     }
     $i = 0;
     $values = $ids = array();
     $srcAbsPathPattern = '/^' . preg_quote($srcAbsPath, '/') . '/';
     while ($row = $stmt->fetch(\PDO::FETCH_ASSOC)) {
         $values[':id' . $i] = $row['id'];
         $values[':path' . $i] = preg_replace($srcAbsPathPattern, $dstAbsPath, $row['path'], 1);
         $values[':parent' . $i] = PathHelper::getParentPath($values[':path' . $i]);
         $values[':depth' . $i] = PathHelper::getPathDepth($values[':path' . $i]);
         $updatePathCase .= "WHEN id = :id" . $i . " THEN :path" . $i . " ";
         $updateParentCase .= "WHEN id = :id" . $i . " THEN :parent" . $i . " ";
         $updateDepthCase .= "WHEN id = :id" . $i . " THEN CAST(:depth" . $i . " AS " . $intType . ") ";
         if ($srcAbsPath === $row['path']) {
             $values[':localname' . $i] = PathHelper::getNodeName($values[':path' . $i]);
             $updateLocalNameCase .= "WHEN id = :id" . $i . " THEN :localname" . $i . " ";
             $updateSortOrderCase .= "WHEN id = :id" . $i . " THEN (SELECT * FROM ( SELECT MAX(x.sort_order) + 1 FROM phpcr_nodes x WHERE x.parent = :parent" . $i . ") y) ";
         }
         $ids[] = $row['id'];
         $i++;
     }
     if (!$i) {
         return;
     }
     $ids = implode($ids, ',');
     $updateLocalNameCase .= "ELSE local_name END, ";
     $updateSortOrderCase .= "ELSE sort_order END ";
     $query .= $updatePathCase . "END, " . $updateParentCase . "END, " . $updateDepthCase . "END, " . $updateLocalNameCase . $updateSortOrderCase;
     $query .= "WHERE id IN (" . $ids . ")";
     try {
         $this->getConnection()->executeUpdate($query, $values);
     } catch (DBALException $e) {
         throw new RepositoryException("Unexpected exception while moving node from {$srcAbsPath} to {$dstAbsPath}", $e->getCode(), $e);
     }
     $this->cleanIdentifierCache($srcAbsPath);
 }
 public function addNode($workspaceName, \DOMElement $node)
 {
     $properties = $this->getAttributes($node);
     $uuid = isset($properties['jcr:uuid']['value'][0]) ? (string) $properties['jcr:uuid']['value'][0] : UUIDHelper::generateUUID();
     $this->ids[$uuid] = $id = isset($this->expectedNodes[$uuid]) ? $this->expectedNodes[$uuid] : self::$idCounter++;
     $dom = new \DOMDocument('1.0', 'UTF-8');
     $phpcrNode = $dom->createElement('sv:node');
     foreach ($this->namespaces as $namespace => $uri) {
         $phpcrNode->setAttribute('xmlns:' . $namespace, $uri);
     }
     $dom->appendChild($phpcrNode);
     foreach ($properties as $propertyName => $propertyData) {
         if ($propertyName == 'jcr:uuid') {
             continue;
         }
         if (!isset($this->jcrTypes[$propertyData['type']])) {
             throw new \InvalidArgumentException('"' . $propertyData['type'] . '" is not a valid JCR type.');
         }
         $phpcrNode->appendChild($this->createPropertyNode($workspaceName, $propertyName, $propertyData, $id, $dom, $phpcrNode));
     }
     list($parentPath, $childPath) = $this->getPath($node);
     $namespace = '';
     $name = $node->getAttributeNS($this->namespaces['sv'], 'name');
     if (count($parts = explode(':', $name, 2)) == 2) {
         list($namespace, $name) = $parts;
     }
     if ($namespace == 'jcr' && $name == 'root') {
         $id = 1;
         $childPath = '/';
         $parentPath = '';
         $name = '';
         $namespace = '';
     }
     $this->addRow('phpcr_nodes', array('id' => $id, 'path' => $childPath, 'parent' => $parentPath, 'local_name' => $name, 'namespace' => $namespace, 'workspace_name' => $workspaceName, 'identifier' => $uuid, 'type' => $properties['jcr:primaryType']['value'][0], 'props' => $dom->saveXML(), 'depth' => PathHelper::getPathDepth($childPath), 'sort_order' => $id - 2));
     return $this;
 }
Esempio n. 3
0
 /**
  * @dataProvider dataproviderPathDepth
  */
 public function testGetPathDepth($path, $depth)
 {
     $this->assertEquals($depth, PathHelper::getPathDepth($path));
 }
Esempio n. 4
0
 /**
  * Search for a next document.
  *
  * @param string|object $path       document instance or path from which to search
  * @param string|object $anchor     document instance or path which serves as an anchor from which to flatten the hierarchy
  * @param null|int      $depth      depth up to which to traverse down the tree when an anchor is provided
  * @param bool          $ignoreRole if to ignore the role
  * @param null|string   $class      the class to filter by
  *
  * @return null|object
  */
 private function searchDepthNext($path, $anchor, $depth = null, $ignoreRole = false, $class = null)
 {
     if (is_object($path)) {
         $path = $this->getDm()->getUnitOfWork()->getDocumentId($path);
     }
     if (null === $path || '/' === $path) {
         return;
     }
     $node = $this->getDm()->getPhpcrSession()->getNode($path);
     if (is_object($anchor)) {
         $anchor = $this->getDm()->getUnitOfWork()->getDocumentId($anchor);
     }
     if (0 !== strpos($path, $anchor)) {
         throw new \RuntimeException("The anchor path '{$anchor}' is not a parent of the current path '{$path}'.");
     }
     // take the first eligible child if there are any
     if (null === $depth || PathHelper::getPathDepth($path) - PathHelper::getPathDepth($anchor) < $depth) {
         $childNames = $node->getNodeNames()->getArrayCopy();
         $result = $this->checkChildren($childNames, $path, $ignoreRole, $class);
         if ($result) {
             return $result;
         }
     }
     $parent = $node->getParent();
     $parentPath = PathHelper::getParentPath($path);
     // take the first eligible sibling
     if (0 === strpos($parentPath, $anchor)) {
         $childNames = $parent->getNodeNames()->getArrayCopy();
         $key = array_search($node->getName(), $childNames);
         $childNames = array_slice($childNames, $key + 1);
         $result = $this->checkChildren($childNames, $parentPath, $ignoreRole, $class);
         if ($result) {
             return $result;
         }
     }
     // take the first eligible parent, traverse up
     while ('/' !== $parentPath) {
         $parent = $parent->getParent();
         if (false === strpos($parent->getPath(), $anchor)) {
             return;
         }
         $childNames = $parent->getNodeNames()->getArrayCopy();
         $key = array_search(PathHelper::getNodeName($parentPath), $childNames);
         $childNames = array_slice($childNames, $key + 1);
         $parentPath = $parent->getPath();
         $result = $this->checkChildren($childNames, $parentPath, $ignoreRole, $class);
         if ($result) {
             return $result;
         }
     }
     return;
 }
Esempio n. 5
0
 /**
  * {@inheritdoc}
  */
 public function findParentsWithSiblingsByUuid($uuid, $locale, $webspaceKey, MappingInterface $mapping, UserInterface $user = null)
 {
     $contentPath = $this->sessionManager->getContentPath($webspaceKey);
     $path = $this->resolvePathByUuid($uuid);
     $locales = $this->getLocalesByWebspaceKey($webspaceKey);
     $queryBuilder = $this->getQueryBuilder($locale, $locales, $user)->orderBy($this->qomFactory->propertyValue('node', 'jcr:path'))->where($this->qomFactory->childNode('node', $path));
     while (PathHelper::getPathDepth($path) > PathHelper::getPathDepth($contentPath)) {
         $path = PathHelper::getParentPath($path);
         $queryBuilder->orWhere($this->qomFactory->childNode('node', $path));
     }
     $mapping->addProperties(['order']);
     $this->appendMapping($queryBuilder, $mapping, $locale, $locales);
     $result = $this->resolveQueryBuilder($queryBuilder, $locale, $locales, $mapping, $user);
     return $this->generateTreeByPath($result);
 }