function copySubtree($srcNodeID, $dstNodeID, &$notifications, $allVersions, $keepCreator, $keepTime) { // 1. Copy subtree and form the arrays of accordance of the old and new nodes and content objects. $sourceSubTreeMainNode = $srcNodeID ? eZContentObjectTreeNode::fetch($srcNodeID) : false; $destinationNode = $dstNodeID ? eZContentObjectTreeNode::fetch($dstNodeID) : false; if (!$sourceSubTreeMainNode) { eZDebug::writeError("Cannot get subtree main node (nodeID = {$srcNodeID}).", "Subtree copy Error!"); $notifications['Errors'][] = ezpI18n::tr('kernel/content/copysubtree', "Fatal error: cannot get subtree main node (ID = %1).", null, array($srcNodeID)); $notifications['Result'] = false; return $notifications; } if (!$destinationNode) { eZDebug::writeError("Cannot get destination node (nodeID = {$dstNodeID}).", "Subtree copy Error!"); $notifications['Errors'][] = ezpI18n::tr('kernel/content/copysubtree', "Fatal error: cannot get destination node (ID = %1).", null, array($dstNodeID)); $notifications['Result'] = false; return $notifications; } $sourceNodeList = array(); $syncNodeIDListSrc = array(); // arrays for synchronizing between source and new IDs of nodes $syncNodeIDListNew = array(); $syncObjectIDListSrc = array(); // arrays for synchronizing between source and new IDs of contentobjects $syncObjectIDListNew = array(); $sourceSubTreeMainNodeID = $sourceSubTreeMainNode->attribute('node_id'); $sourceNodeList[] = $sourceSubTreeMainNode; $syncNodeIDListSrc[] = $sourceSubTreeMainNode->attribute('parent_node_id'); $syncNodeIDListNew[] = (int) $dstNodeID; $nodeIDBlackList = array(); // array of nodes which are unable to copy $objectIDBlackList = array(); // array of contentobjects which are unable to copy in any location inside new subtree $sourceNodeList = array_merge($sourceNodeList, eZContentObjectTreeNode::subTreeByNodeID(array('Limitation' => array()), $sourceSubTreeMainNodeID)); $countNodeList = count($sourceNodeList); $notifications['Notifications'][] = ezpI18n::tr('kernel/content/copysubtree', "Number of nodes of source subtree - %1", null, array($countNodeList)); // Prepare list of source node IDs. We will need it in the future // for checking node is inside or outside of the subtree being copied. $sourceNodeIDList = array(); foreach ($sourceNodeList as $sourceNode) { $sourceNodeIDList[] = $sourceNode->attribute('node_id'); } eZDebug::writeDebug("Source NodeID = {$srcNodeID}, destination NodeID = {$dstNodeID}", "Subtree copy: START!"); // 1. copying and publishing source subtree $k = 0; while (count($sourceNodeList) > 0) { if ($k > $countNodeList) { eZDebug::writeError("Too many loops while copying nodes.", "Subtree Copy Error!"); break; } for ($i = 0; $i < count($sourceNodeList); $i) { $sourceNodeID = $sourceNodeList[$i]->attribute('node_id'); // if node was alreaty copied if (in_array($sourceNodeID, $syncNodeIDListSrc)) { array_splice($sourceNodeList, $i, 1); continue; } //////////// check permissions START // if node is already in black list, then skip current node: if (in_array($sourceNodeID, $nodeIDBlackList)) { array_splice($sourceNodeList, $i, 1); continue; } $sourceObject = $sourceNodeList[$i]->object(); $srcSubtreeNodeIDlist = $sourceNodeID == $sourceSubTreeMainNodeID ? $syncNodeIDListSrc : $sourceNodeIDList; $copyResult = copyPublishContentObject($sourceObject, $srcSubtreeNodeIDlist, $syncNodeIDListSrc, $syncNodeIDListNew, $syncObjectIDListSrc, $syncObjectIDListNew, $objectIDBlackList, $nodeIDBlackList, $notifications, $allVersions, $keepCreator, $keepTime); if ($copyResult === 0) { // if copying successful then remove $sourceNode from $sourceNodeList array_splice($sourceNodeList, $i, 1); } else { $i++; } } $k++; } array_shift($syncNodeIDListSrc); array_shift($syncNodeIDListNew); $countNewNodes = count($syncNodeIDListNew); $countNewObjects = count($syncObjectIDListNew); $notifications['Notifications'][] = ezpI18n::tr('kernel/content/copysubtree', "Number of copied nodes - %1", null, array($countNewNodes)); $notifications['Notifications'][] = ezpI18n::tr('kernel/content/copysubtree', "Number of copied contentobjects - %1", null, array($countNewObjects)); eZDebug::writeDebug(count($syncNodeIDListNew), "Number of copied nodes: "); eZDebug::writeDebug(count($syncObjectIDListNew), "Number of copied contentobjects: "); eZDebug::writeDebug($objectIDBlackList, "Copy subtree: Not copied object IDs list:"); eZDebug::writeDebug($nodeIDBlackList, "Copy subtree: Not copied node IDs list:"); $key = array_search($sourceSubTreeMainNodeID, $syncNodeIDListSrc); if ($key === false) { eZDebug::writeDebug("Root node of given subtree was not copied.", "Subtree copy:"); $notifications['Result'] = false; return $notifications; } // 2. fetch all new subtree $newSubTreeMainNodeID = $syncNodeIDListSrc[$key]; $newSubTreeMainNode = eZContentObjectTreeNode::fetch($newSubTreeMainNodeID); $newNodeList[] = $newSubTreeMainNode; $newNodeList = $sourceNodeList = array_merge($newNodeList, eZContentObjectTreeNode::subTreeByNodeID(false, $newSubTreeMainNodeID)); // 3. fix local links (in ezcontentobject_link) eZDebug::writeDebug("Fixing global and local links...", "Subtree copy:"); $db = eZDB::instance(); if (!$db) { eZDebug::writeError("Cannot create instance of eZDB for fixing local links (related objects).", "Subtree Copy Error!"); $notifications['Errors'][] = ezpI18n::tr('kernel/content/copysubtree', "Cannot create instance of eZDB to fix local links (related objects)."); return $notifications; } $idListINString = $db->generateSQLINStatement($syncObjectIDListNew, 'from_contentobject_id', false, false, 'int'); $relatedRecordsList = $db->arrayQuery("SELECT * FROM ezcontentobject_link WHERE {$idListINString}"); foreach ($relatedRecordsList as $relatedEntry) { $kindex = array_search($relatedEntry['to_contentobject_id'], $syncObjectIDListSrc); if ($kindex !== false) { $newToContentObjectID = (int) $syncObjectIDListNew[$kindex]; $linkID = (int) $relatedEntry['id']; $db->query("UPDATE ezcontentobject_link SET to_contentobject_id={$newToContentObjectID} WHERE id={$linkID}"); } } // 4. duplicating of global links for new contentobjects (in ezurl_object_link) are automatic during copy of contentobject. // it was fixed as bug patch. // 5. fixing node_ids and object_ids in ezxmltext attributes of copied objects $conditions = array('contentobject_id' => '', 'data_type_string' => 'ezxmltext'); foreach ($syncObjectIDListNew as $contentObjectID) { $conditions['contentobject_id'] = $contentObjectID; $attributeList = eZPersistentObject::fetchObjectList(eZContentObjectAttribute::definition(), null, $conditions); if (count($attributeList) == 0) { continue; } foreach ($attributeList as $xmlAttribute) { $xmlText = $xmlAttribute->attribute('data_text'); $xmlTextLen = strlen($xmlText); $isTextModified = false; $curPos = 0; while ($curPos < $xmlTextLen) { $literalTagBeginPos = strpos($xmlText, "<literal", $curPos); if ($literalTagBeginPos) { $literalTagEndPos = strpos($xmlText, "</literal>", $literalTagBeginPos); if ($literalTagEndPos === false) { break; } $curPos = $literalTagEndPos + 9; } if (($tagBeginPos = strpos($xmlText, "<link", $curPos)) !== false or ($tagBeginPos = strpos($xmlText, "<a", $curPos)) !== false or ($tagBeginPos = strpos($xmlText, "<embed", $curPos)) !== false) { $tagEndPos = strpos($xmlText, ">", $tagBeginPos + 1); if ($tagEndPos === false) { break; } $tagText = substr($xmlText, $tagBeginPos, $tagEndPos - $tagBeginPos); if (($nodeIDAttributePos = strpos($tagText, " node_id=\"")) !== false) { $idNumberPos = $nodeIDAttributePos + 10; $quoteEndPos = strpos($tagText, "\"", $idNumberPos); if ($quoteEndPos !== false) { $idNumber = substr($tagText, $idNumberPos, $quoteEndPos - $idNumberPos); $key = array_search((int) $idNumber, $syncNodeIDListSrc); if ($key !== false) { $tagText = substr_replace($tagText, (string) $syncNodeIDListNew[$key], $idNumberPos, $quoteEndPos - $idNumberPos); $xmlText = substr_replace($xmlText, $tagText, $tagBeginPos, $tagEndPos - $tagBeginPos); $isTextModified = true; } } } else { if (($objectIDAttributePos = strpos($tagText, " object_id=\"")) !== false) { $idNumberPos = $objectIDAttributePos + 12; $quoteEndPos = strpos($tagText, "\"", $idNumberPos); if ($quoteEndPos !== false) { $idNumber = substr($tagText, $idNumberPos, $quoteEndPos - $idNumberPos); $key = array_search((int) $idNumber, $syncObjectIDListSrc); if ($key !== false) { $tagText = substr_replace($tagText, (string) $syncObjectIDListNew[$key], $idNumberPos, $quoteEndPos - $idNumberPos); $xmlText = substr_replace($xmlText, $tagText, $tagBeginPos, $tagEndPos - $tagBeginPos); $isTextModified = true; } } } } $curPos = $tagEndPos; } else { if (($tagBeginPos = strpos($xmlText, "<object", $curPos)) !== false) { $tagEndPos = strpos($xmlText, ">", $tagBeginPos + 1); if (!$tagEndPos) { break; } $tagText = substr($xmlText, $tagBeginPos, $tagEndPos - $tagBeginPos); if (($idAttributePos = strpos($tagText, " id=\"")) !== false) { $idNumberPos = $idAttributePos + 5; $quoteEndPos = strpos($tagText, "\"", $idNumberPos); if ($quoteEndPos !== false) { $idNumber = substr($tagText, $idNumberPos, $quoteEndPos - $idNumberPos); $key = array_search((int) $idNumber, $syncObjectIDListSrc); if ($key !== false) { $tagText = substr_replace($tagText, (string) $syncObjectIDListNew[$key], $idNumberPos, $quoteEndPos - $idNumberPos); $xmlText = substr_replace($xmlText, $tagText, $tagBeginPos, $tagEndPos - $tagBeginPos); $isTextModified = true; } } } $curPos = $tagEndPos; } else { break; } } } // while END if ($isTextModified) { $xmlAttribute->setAttribute('data_text', $xmlText); $xmlAttribute->store(); } } // foreach END } // 6. fixing datatype ezobjectrelationlist $conditions = array('contentobject_id' => '', 'data_type_string' => 'ezobjectrelationlist'); foreach ($syncObjectIDListNew as $contentObjectID) { $conditions['contentobject_id'] = $contentObjectID; $attributeList = eZPersistentObject::fetchObjectList(eZContentObjectAttribute::definition(), null, $conditions); if (count($attributeList) == 0) { continue; } foreach ($attributeList as $relationListAttribute) { $relationsXmlText = $relationListAttribute->attribute('data_text'); $relationsDom = eZObjectRelationListType::parseXML($relationsXmlText); $relationItems = $relationsDom->getElementsByTagName('relation-item'); $isRelationModified = false; foreach ($relationItems as $relationItem) { $originalObjectID = $relationItem->getAttribute('contentobject-id'); $key = array_search($originalObjectID, $syncObjectIDListSrc); if ($key !== false) { $newObjectID = $syncObjectIDListNew[$key]; $relationItem->setAttribute('contentobject-id', $newObjectID); $isRelationModified = true; } $originalNodeID = $relationItem->getAttribute('node-id'); if ($originalNodeID) { $key = array_search($originalNodeID, $syncNodeIDListSrc); if ($key !== false) { $newNodeID = $syncNodeIDListNew[$key]; $relationItem->setAttribute('node-id', $newNodeID); $newNode = eZContentObjectTreeNode::fetch($newNodeID); $newParentNodeID = $newNode->attribute('parent_node_id'); $relationItem->setAttribute('parent-node-id', $newParentNodeID); $isRelationModified = true; } } } if ($isRelationModified) { $attributeID = $relationListAttribute->attribute('id'); $attributeVersion = $relationListAttribute->attribute('version'); $changedDomString = $db->escapeString(eZObjectRelationListType::domString($relationsDom)); $db->query("UPDATE ezcontentobject_attribute SET data_text='{$changedDomString}'\n WHERE id={$attributeID} AND version={$attributeVersion}"); } } } eZDebug::writeDebug("Successfuly DONE.", "Copy subtree:"); $notifications['Result'] = true; return $notifications; }
} $cli->output("Copying subtree:"); $k = 0; while (count($sourceNodeList) > 0) { if ($k > $countNodeList) { $cli->error("Subtree Copy Error!\nToo many loops while copying nodes."); $script->shutdown(6); } for ($i = 0; $i < count($sourceNodeList); $i) { $sourceNodeID = $sourceNodeList[$i]->attribute('node_id'); if (in_array($sourceNodeID, $syncNodeIDListSrc)) { array_splice($sourceNodeList, $i, 1); } else { $sourceObject = $sourceNodeList[$i]->object(); $srcSubtreeNodeIDlist = $sourceNodeID == $sourceSubTreeMainNodeID ? $syncNodeIDListSrc : $sourceNodeIDList; $copyResult = copyPublishContentObject($sourceObject, $srcSubtreeNodeIDlist, $syncNodeIDListSrc, $syncNodeIDListNew, $syncObjectIDListSrc, $syncObjectIDListNew, $allVersions, $keepCreator, $keepTime); if ($copyResult === 0) { // if copying successful then remove $sourceNode from $sourceNodeList array_splice($sourceNodeList, $i, 1); $cli->output(".", false); } else { $i++; } } } $k++; } array_shift($syncNodeIDListSrc); array_shift($syncNodeIDListNew); $cli->output("\nNumber of copied nodes: " . count($syncNodeIDListNew)); $cli->output("Number of copied contentobjects: " . count($syncObjectIDListNew));