/**
* Copy location object identified by $sourceId, into destination identified by $destinationParentId.
*
* Performs a deep copy of the location identified by $sourceId and all of
* its child locations, copying the most recent published content object
* for each location to a new content object without any additional version
* information. Relations are not copied. URLs are not touched at all.
*
* @todo update subtree modification time, optionally retain dates and set creator
*
* @param mixed $sourceId
* @param mixed $destinationParentId
*
* @return Location the newly created Location.
*/
public function copySubtree($sourceId, $destinationParentId)
{
$children = $this->locationGateway->getSubtreeContent($sourceId);
$destinationParentData = $this->locationGateway->getBasicNodeData($destinationParentId);
$defaultObjectStates = $this->getDefaultContentStates();
$contentMap = array();
$locationMap = array($children[0]["parent_node_id"] => array("id" => $destinationParentId, "hidden" => (bool) $destinationParentData["is_hidden"], "invisible" => (bool) $destinationParentData["is_invisible"], "path_identification_string" => $destinationParentData["path_identification_string"]));
$locations = array();
foreach ($children as $child) {
$locations[$child["contentobject_id"]][$child["node_id"]] = true;
}
$time = time();
$mainLocations = array();
$mainLocationsUpdate = array();
foreach ($children as $index => $child) {
// Copy content
if (!isset($contentMap[$child["contentobject_id"]])) {
$content = $this->contentHandler->copy($child["contentobject_id"], $child["contentobject_version"]);
$this->setContentStates($content, $defaultObjectStates);
$content = $this->contentHandler->publish($content->versionInfo->contentInfo->id, $content->versionInfo->contentInfo->currentVersionNo, new MetadataUpdateStruct(array("publicationDate" => $time, "modificationDate" => $time)));
$contentMap[$child["contentobject_id"]] = $content->versionInfo->contentInfo->id;
}
$createStruct = $this->locationMapper->getLocationCreateStruct($child);
$createStruct->contentId = $contentMap[$child["contentobject_id"]];
$parentData = $locationMap[$child["parent_node_id"]];
$createStruct->parentId = $parentData["id"];
$createStruct->invisible = $createStruct->hidden || $parentData["hidden"] || $parentData["invisible"];
$pathString = explode("/", $child["path_identification_string"]);
$pathString = end($pathString);
$createStruct->pathIdentificationString = strlen($pathString) > 0 ? $parentData["path_identification_string"] . "/" . $pathString : null;
// Use content main location if already set, otherwise create location as main
if (isset($mainLocations[$child["contentobject_id"]])) {
$createStruct->mainLocationId = $locationMap[$mainLocations[$child["contentobject_id"]]]["id"];
} else {
$createStruct->mainLocationId = true;
$mainLocations[$child["contentobject_id"]] = $child["node_id"];
// If needed mark for update
if (isset($locations[$child["contentobject_id"]][$child["main_node_id"]]) && count($locations[$child["contentobject_id"]]) > 1 && $child["node_id"] !== $child["main_node_id"]) {
$mainLocationsUpdate[$child["contentobject_id"]] = $child["main_node_id"];
}
}
$newLocation = $this->create($createStruct);
$locationMap[$child["node_id"]] = array("id" => $newLocation->id, "hidden" => $newLocation->hidden, "invisible" => $newLocation->invisible, "path_identification_string" => $newLocation->pathIdentificationString);
if ($index === 0) {
$copiedSubtreeRootLocation = $newLocation;
}
}
// Update main locations
foreach ($mainLocationsUpdate as $contentId => $mainLocationId) {
$this->changeMainLocation($contentMap[$contentId], $locationMap[$mainLocationId]["id"]);
}
// If subtree root is main location for its content, update subtree section to the one of the
// parent location content
$subtreeRootContentInfo = $this->contentHandler->loadContentInfo($copiedSubtreeRootLocation->contentId);
if ($subtreeRootContentInfo->mainLocationId === $copiedSubtreeRootLocation->id) {
$this->setSectionForSubtree($copiedSubtreeRootLocation->id, $this->contentHandler->loadContentInfo($this->load($destinationParentId)->contentId)->sectionId);
}
return $copiedSubtreeRootLocation;
}