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;
}
Example #2
0
}
$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));