/** * Moves the given item to another location * * @param string $id The id or alias of the layout item to be moved * @param string|null $parentId The id or alias of a parent item the specified item is moved to * If this parameter is null only the order of the item is changed * @param string|null $siblingId The id or alias of an item which should be nearest neighbor * @param bool $prepend Determines whether the moving item should be located before or after * the specified sibling item * * @throws Exception\InvalidArgumentException if the id is empty * @throws Exception\ItemNotFoundException if the layout item, parent item or sibling item does not exist * @throws Exception\LogicException if the layout item cannot be moved by other reasons * * @SuppressWarnings(PHPMD.NPathComplexity) * @SuppressWarnings(PHPMD.CyclomaticComplexity) */ public function move($id, $parentId = null, $siblingId = null, $prepend = false) { $id = $this->validateAndResolveId($id); if ($parentId) { $parentId = $this->resolveId($parentId); if (!isset($this->items[$parentId])) { throw new Exception\ItemNotFoundException(sprintf('The "%s" parent item does not exist.', $parentId)); } if ($parentId === $id) { throw new Exception\LogicException('The parent item cannot be the same as the moving item.'); } } if ($siblingId) { $siblingId = $this->resolveId($siblingId); if (!isset($this->items[$siblingId])) { throw new Exception\ItemNotFoundException(sprintf('The "%s" sibling item does not exist.', $siblingId)); } if ($siblingId === $id) { throw new Exception\LogicException('The sibling item cannot be the same as the moving item.'); } } if (!$parentId && !$siblingId) { throw new Exception\LogicException('At least one parent or sibling item must be specified.'); } $path = $this->items[$id][self::PATH]; if (!$parentId) { $parentPath = array_slice($path, 0, -1); } else { if ($siblingId && $siblingId === $parentId) { throw new Exception\LogicException('The sibling item cannot be the same as the parent item.'); } $parentPath = $this->items[$parentId][self::PATH]; if (strpos(implode('/', $parentPath) . '/', implode('/', $path) . '/') === 0) { throw new Exception\LogicException(sprintf('The parent item (path: %s) cannot be a child of the moving item (path: %s).', implode('/', $parentPath), implode('/', $path))); } } // update hierarchy $hierarchy = $this->hierarchy->get($path); $this->hierarchy->remove($path); $this->hierarchy->add($parentPath, $id, $siblingId, $prepend, $hierarchy); if ($parentId) { // build the new path $newPath = $parentPath; $newPath[] = $id; // update the path of the moving item $this->items[$id][self::PATH] = $newPath; // update the path for all children $prevPathLength = count($path); $iterator = $this->getHierarchyIterator($id); foreach ($iterator as $childId) { $this->items[$childId][self::PATH] = array_merge($newPath, array_slice($this->items[$childId][self::PATH], $prevPathLength)); } } }