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);
}