|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00004 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00005 * @version //autogentag// 00006 * @package kernel 00007 */ 00008 00009 $Module = $Params['Module']; 00010 $NodeID = $Params['NodeID']; 00011 00012 $http = eZHTTPTool::instance(); 00013 00014 if ( $http->hasPostVariable( 'BrowseCancelButton' ) ) 00015 { 00016 if ( $http->hasPostVariable( 'BrowseCancelURI' ) ) 00017 return $Module->redirectTo( $http->postVariable( 'BrowseCancelURI' ) ); 00018 } 00019 00020 if ( $NodeID === null ) // NodeID is returned after browsing 00021 { 00022 $NodeID = $http->postVariable( 'NodeID' ); 00023 } 00024 00025 $srcNode = eZContentObjectTreeNode::fetch( $NodeID ); 00026 00027 if ( $srcNode === null ) 00028 return $Module->handleError( eZError::KERNEL_NOT_AVAILABLE, 'kernel' ); 00029 00030 if ( !$srcNode->attribute( 'can_read' ) ) 00031 return $Module->handleError( eZError::KERNEL_ACCESS_DENIED, 'kernel' ); 00032 00033 if ( $Module->isCurrentAction( 'Cancel' ) ) 00034 { 00035 $parentNodeID = $srcNode->attribute( 'parent_node_id' ); 00036 return $Module->redirectToView( 'view', array( 'full', $parentNodeID ) ); 00037 } 00038 00039 ///// functions START ============================================================================= 00040 function copyPublishContentObject( $sourceObject, 00041 $sourceSubtreeNodeIDList, 00042 &$syncNodeIDListSrc, &$syncNodeIDListNew, 00043 &$syncObjectIDListSrc, &$syncObjectIDListNew, 00044 $objectIDBlackList, &$nodeIDBlackList, 00045 &$notifications, 00046 $allVersions = false, $keepCreator = false, $keepTime = false ) 00047 { 00048 $sourceObjectID = $sourceObject->attribute( 'id' ); 00049 00050 $key = array_search( $sourceObjectID, $syncObjectIDListSrc ); 00051 if ( $key !== false ) 00052 { 00053 eZDebug::writeDebug( "Object (ID = $sourceObjectID) has been already copied.", 00054 "Subtree copy: copyPublishContentObject()" ); 00055 return 1; // object already copied 00056 } 00057 00058 $srcNodeList = $sourceObject->attribute( 'assigned_nodes' ); 00059 00060 // if we already failed to copy that contentobject, then just skip it: 00061 if ( in_array( $sourceObjectID, $objectIDBlackList ) ) 00062 return 0; 00063 // if we already failed to copy that node, then just skip it: 00064 //if ( in_array( $sourceNodeID, $nodeIDBlackList ) ) 00065 // return 0; 00066 00067 // if cannot read contentobject then remember it and all its nodes (nodes 00068 // which are inside subtree being copied) in black list, and skip current node: 00069 if ( !$sourceObject->attribute( 'can_read' ) ) 00070 { 00071 $objectIDBlackList[] = $sourceObjectID; 00072 $notifications['Warnings'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00073 "Object (ID = %1) was not copied: you do not have permission to read the object.", 00074 null, array( $sourceObjectID ) ); 00075 00076 $srcNodeList = $sourceObject->attribute( 'assigned_nodes' ); 00077 foreach( $srcNodeList as $srcNode ) 00078 { 00079 $srcNodeID = $srcNode->attribute( 'node_id' ); 00080 $sourceParentNodeID = $srcNode->attribute( 'parent_node_id' ); 00081 00082 $key = array_search( $sourceParentNodeID, $sourceSubtreeNodeIDList ); 00083 if ( $key !== false ) 00084 { 00085 $nodeIDBlackList[] = $srcNodeID; 00086 $notifications['Warnings'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00087 "Node (ID = %1) was not copied: you do not have permission to read object (ID = %2).", 00088 null, array( $srcNodeID, $sourceObjectID ) ); 00089 } 00090 } 00091 return 0; 00092 } 00093 00094 // check if all possible parent nodes for given contentobject are already published: 00095 $isReadyToPublish = false; 00096 foreach ( $srcNodeList as $srcNode ) 00097 { 00098 $srcNodeID = $srcNode->attribute( 'node_id' ); 00099 00100 if ( in_array( $srcNodeID, $nodeIDBlackList ) ) 00101 continue; 00102 00103 $srcParentNodeID = $srcNode->attribute( 'parent_node_id' ); 00104 00105 // if parent node for this node is outside 00106 // of subtree being copied, then skip this node: 00107 $key = array_search( $srcParentNodeID, $sourceSubtreeNodeIDList ); 00108 if ( $key === false ) 00109 continue; 00110 00111 // if parent node for this node wasn't copied yet and is in black list 00112 // then add that node in black list and just skip it: 00113 $key = array_search( $srcParentNodeID, $nodeIDBlackList ); 00114 if ( $key !== false ) 00115 { 00116 $nodeIDBlackList[] = $srcNodeID; 00117 $notifications['Warnings'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00118 "Node (ID = %1) was not copied: parent node (ID = %2) was not copied.", 00119 null, array( $srcNodeID, $srcParentNodeID ) ); 00120 continue; 00121 } 00122 00123 $key = array_search( $srcParentNodeID, $syncNodeIDListSrc ); 00124 if ( $key === false ) 00125 { 00126 // if parent node is not copied yet and not in black list, 00127 // then just skip sourceObject from copying for next time 00128 eZDebug::writeDebug( "Parent node (ID = $srcParentNodeID) for contentobject (ID = $sourceObjectID) is not published yet.", 00129 "Subtree copy: copyPublishContentObject()" ); 00130 return 2; 00131 } 00132 else 00133 { 00134 $newParentNodeID = $syncNodeIDListNew[ $key ]; 00135 $newParentNode = eZContentObjectTreeNode::fetch( $newParentNodeID ); 00136 if ( $newParentNode === null ) 00137 { 00138 eZDebug::writeError( "Cannot fetch one of parent nodes. Error are somewhere above", 00139 "Subtree copy error: copyPublishContentObject()" ); 00140 return 3; 00141 } 00142 00143 if ( $newParentNode->checkAccess( 'create', $sourceObject->attribute( 'contentclass_id' ) ) != 1 ) 00144 { 00145 $nodeIDBlackList[] = $srcNodeID; 00146 $notifications['Warnings'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00147 "Node (ID = %1) was not copied: you do not have permission to create.", 00148 null, array( $srcNodeID ) ); 00149 00150 continue; 00151 } 00152 else 00153 $isReadyToPublish = true; 00154 } 00155 } 00156 00157 // if all nodes of sourceObject were skiped as black list entry or 00158 // as outside of subtree being copied, then sourceObject cannot be 00159 // copied and published in any new location. So insert sourceObject 00160 // in a black list and skip it. 00161 if ( $isReadyToPublish == false ) 00162 { 00163 $objectIDBlackList[] = $sourceObjectID; 00164 $notifications['Warnings'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00165 "Object (ID = %1) was not copied: no one nodes of object was not copied.", 00166 null, array( $sourceObjectID) ); 00167 return 0; 00168 } 00169 00170 // make copy of source object 00171 $newObject = $sourceObject->copy( $allVersions ); // insert source and new object's ids in $syncObjectIDList 00172 // We should reset section that will be updated in updateSectionID(). 00173 // If sectionID is 0 than the object has been newly created 00174 $newObject->setAttribute( 'section_id', 0 ); 00175 $newObject->store(); 00176 00177 $syncObjectIDListSrc[] = $sourceObjectID; 00178 00179 $curVersion = $newObject->attribute( 'current_version' ); 00180 $curVersionObject = $newObject->attribute( 'current' ); 00181 00182 $newObjAssignments = $curVersionObject->attribute( 'node_assignments' ); 00183 00184 // copy nodeassigments: 00185 $assignmentsForRemoving = array(); 00186 $foundMainAssignment = false; 00187 foreach ( $newObjAssignments as $assignment ) 00188 { 00189 $parentNodeID = $assignment->attribute( 'parent_node' ); 00190 00191 // if assigment is outside of subtree being copied then do not copy this assigment 00192 $key1 = array_search( $parentNodeID, $sourceSubtreeNodeIDList ); 00193 $key2 = array_search( $parentNodeID, $nodeIDBlackList ); 00194 if ( $key1 === false or $key2 !== false ) 00195 { 00196 $assignmentsForRemoving[] = $assignment->attribute( 'id' ); 00197 continue; 00198 } 00199 00200 $key = array_search( $parentNodeID, $syncNodeIDListSrc ); 00201 if ( $key === false ) 00202 { 00203 eZDebug::writeError( "Cannot publish contentobject (ID=$sourceObjectID). Parent is not published yet.", 00204 "Subtree Copy error: copyPublishContentObject()" ); 00205 return 4; 00206 } 00207 00208 if ( $assignment->attribute( 'is_main' ) ) 00209 $foundMainAssignment = true; 00210 00211 $newParentNodeID = $syncNodeIDListNew[ $key ]; 00212 $assignment->setAttribute( 'parent_node', $newParentNodeID ); 00213 $assignment->store(); 00214 } 00215 // remove assigments which are outside of subtree being copied: 00216 eZNodeAssignment::purgeByID( $assignmentsForRemoving ); 00217 00218 // if main nodeassigment was not copied then set as main first nodeassigment 00219 if ( $foundMainAssignment == false ) 00220 { 00221 $newObjAssignments = $curVersionObject->attribute( 'node_assignments' ); 00222 // We need to check if it has any assignments before changing the data. 00223 if ( isset( $newObjAssignments[0] ) ) 00224 { 00225 $newObjAssignments[0]->setAttribute( 'is_main', 1 ); 00226 $newObjAssignments[0]->store(); 00227 } 00228 } 00229 00230 // publish the newly created object 00231 $result = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $newObject->attribute( 'id' ), 00232 'version' => $curVersion ) ); 00233 // Refetch the object data since it might change in the database. 00234 $newObjectID = $newObject->attribute( 'id' ); 00235 $newObject = eZContentObject::fetch( $newObjectID ); 00236 $newNodeList = $newObject->attribute( 'assigned_nodes' ); 00237 if ( count($newNodeList) == 0 ) 00238 { 00239 $newObject->purge(); 00240 eZDebug::writeError( "Cannot publish contentobject.", 00241 "Subtree Copy Error!" ); 00242 $sourceObjectName = $srcNode->getName(); 00243 $notifications['Warnings'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00244 "Cannot publish object (Name: %1, ID: %2).", 00245 null, array( $sourceObjectName, $sourceObjectID ) ); 00246 return -1; 00247 } 00248 // Only if the object has been published successfully, the object id can be added into $syncObjectIDListNew 00249 $syncObjectIDListNew[] = $newObject->attribute( 'id' ); 00250 00251 $objAssignments = $curVersionObject->attribute( 'node_assignments' ); 00252 foreach ( $newNodeList as $newNode ) 00253 { 00254 $newParentNode = $newNode->fetchParent(); 00255 $newParentNodeID = $newParentNode->attribute( 'node_id' ); 00256 00257 $keyA = array_search( $newParentNodeID, $syncNodeIDListNew ); 00258 if ( $keyA === false ) 00259 { 00260 eZDebug::writeError( "Algoritm ERROR! Cannot find new parent node ID in new ID's list", 00261 "Subtree Copy Error!" ); 00262 return -2; 00263 } 00264 00265 $srcParentNodeID = $syncNodeIDListSrc[ $keyA ]; 00266 00267 // Update attributes of node 00268 $bSrcParentFound = false; 00269 foreach ( $srcNodeList as $srcNode ) 00270 { 00271 if ( $srcNode->attribute( 'parent_node_id' ) == $srcParentNodeID ) 00272 { 00273 $newNode->setAttribute( 'priority', $srcNode->attribute( 'priority' ) ); 00274 $newNode->setAttribute( 'is_hidden', $srcNode->attribute( 'is_hidden' ) ); 00275 // Update node visibility 00276 if ( $newParentNode->attribute( 'is_invisible' ) or $newParentNode->attribute( 'is_hidden' ) ) 00277 $newNode->setAttribute( 'is_invisible', 1 ); 00278 else 00279 $newNode->setAttribute( 'is_invisible', $srcNode->attribute( 'is_invisible' ) ); 00280 00281 $syncNodeIDListSrc[] = $srcNode->attribute( 'node_id' ); 00282 $syncNodeIDListNew[] = $newNode->attribute( 'node_id' ); 00283 $bSrcParentFound = true; 00284 break; 00285 } 00286 } 00287 if ( $bSrcParentFound == false ) 00288 { 00289 eZDebug::writeError( "Cannot find source parent node in list of nodes already copied.", 00290 "Subtree Copy Error!" ); 00291 } 00292 // Create unique remote_id 00293 $newRemoteID = eZRemoteIdUtility::generate( 'node' ); 00294 $oldRemoteID = $newNode->attribute( 'remote_id' ); 00295 $newNode->setAttribute( 'remote_id', $newRemoteID ); 00296 // Change parent_remote_id for object assignments 00297 foreach ( $objAssignments as $assignment ) 00298 { 00299 if ( $assignment->attribute( 'parent_remote_id' ) == $oldRemoteID ) 00300 { 00301 $assignment->setAttribute( 'parent_remote_id', $newRemoteID ); 00302 $assignment->store(); 00303 } 00304 } 00305 $newNode->store(); 00306 } 00307 00308 // if $keepCreator == true then keep owner of contentobject being 00309 // copied and creator of its published version Unchaged 00310 $isModified = false; 00311 if ( $keepTime ) 00312 { 00313 $srcPublished = $sourceObject->attribute( 'published' ); 00314 $newObject->setAttribute( 'published', $srcPublished ); 00315 $srcModified = $sourceObject->attribute( 'modified' ); 00316 $newObject->setAttribute( 'modified', $srcModified ); 00317 $isModified = true; 00318 } 00319 if ( $keepCreator ) 00320 { 00321 $srcOwnerID = $sourceObject->attribute( 'owner_id' ); 00322 $newObject->setAttribute( 'owner_id', $srcOwnerID ); 00323 $isModified = true; 00324 } 00325 if ( $isModified ) 00326 $newObject->store(); 00327 00328 if ( $allVersions ) 00329 { // copy time of creation and midification and creator id for 00330 // all versions of content object being copied. 00331 $srcVersionsList = $sourceObject->versions(); 00332 00333 foreach ( $srcVersionsList as $srcVersionObject ) 00334 { 00335 $newVersionObject = $newObject->version( $srcVersionObject->attribute( 'version' ) ); 00336 if ( !is_object( $newVersionObject ) ) 00337 continue; 00338 00339 $isModified = false; 00340 if ( $keepTime ) 00341 { 00342 $srcVersionCreated = $srcVersionObject->attribute( 'created' ); 00343 $newVersionObject->setAttribute( 'created', $srcVersionCreated ); 00344 $srcVersionModified = $srcVersionObject->attribute( 'modified' ); 00345 $newVersionObject->setAttribute( 'modified', $srcVersionModified ); 00346 $isModified = true; 00347 } 00348 if ( $keepCreator ) 00349 { 00350 $srcVersionCreatorID = $srcVersionObject->attribute( 'creator_id' ); 00351 $newVersionObject->setAttribute( 'creator_id', $srcVersionCreatorID ); 00352 00353 $isModified = true; 00354 } 00355 if ( $isModified ) 00356 $newVersionObject->store(); 00357 } 00358 } 00359 else // if not all versions copied 00360 { 00361 $srcVersionObject = $sourceObject->attribute( 'current' ); 00362 $newVersionObject = $newObject->attribute( 'current' ); 00363 00364 $isModified = false; 00365 if ( $keepTime ) 00366 { 00367 $srcVersionCreated = $srcVersionObject->attribute( 'created' ); 00368 $newVersionObject->setAttribute( 'created', $srcVersionCreated ); 00369 $srcVersionModified = $srcVersionObject->attribute( 'modified' ); 00370 $newVersionObject->setAttribute( 'modified', $srcVersionModified ); 00371 $isModified = true; 00372 } 00373 if ( $keepCreator ) 00374 { 00375 $srcVersionCreatorID = $srcVersionObject->attribute( 'creator_id' ); 00376 $newVersionObject->setAttribute( 'creator_id', $srcVersionCreatorID ); 00377 $isModified = true; 00378 } 00379 if ( $isModified ) 00380 $newVersionObject->store(); 00381 } 00382 00383 return 0; // source object was copied successfully. 00384 00385 } // function copyPublishContentObject END 00386 00387 00388 function copySubtree( $srcNodeID, $dstNodeID, &$notifications, $allVersions, $keepCreator, $keepTime ) 00389 { 00390 // 1. Copy subtree and form the arrays of accordance of the old and new nodes and content objects. 00391 00392 $sourceSubTreeMainNode = ( $srcNodeID ) ? eZContentObjectTreeNode::fetch( $srcNodeID ) : false; 00393 $destinationNode = ( $dstNodeID ) ? eZContentObjectTreeNode::fetch( $dstNodeID ) : false; 00394 00395 if ( !$sourceSubTreeMainNode ) 00396 { 00397 eZDebug::writeError( "Cannot get subtree main node (nodeID = $srcNodeID).", 00398 "Subtree copy Error!" ); 00399 $notifications['Errors'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00400 "Fatal error: cannot get subtree main node (ID = %1).", 00401 null, array( $srcNodeID ) ); 00402 $notifications['Result'] = false; 00403 return $notifications; 00404 } 00405 if ( !$destinationNode ) 00406 { 00407 eZDebug::writeError( "Cannot get destination node (nodeID = $dstNodeID).", 00408 "Subtree copy Error!" ); 00409 $notifications['Errors'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00410 "Fatal error: cannot get destination node (ID = %1).", 00411 null, array( $dstNodeID ) ); 00412 $notifications['Result'] = false; 00413 return $notifications; 00414 } 00415 00416 $sourceNodeList = array(); 00417 00418 $syncNodeIDListSrc = array(); // arrays for synchronizing between source and new IDs of nodes 00419 $syncNodeIDListNew = array(); 00420 $syncObjectIDListSrc = array(); // arrays for synchronizing between source and new IDs of contentobjects 00421 $syncObjectIDListNew = array(); 00422 00423 $sourceSubTreeMainNodeID = $sourceSubTreeMainNode->attribute( 'node_id' ); 00424 $sourceNodeList[] = $sourceSubTreeMainNode; 00425 00426 $syncNodeIDListSrc[] = $sourceSubTreeMainNode->attribute( 'parent_node_id' ); 00427 $syncNodeIDListNew[] = (int) $dstNodeID; 00428 00429 $nodeIDBlackList = array(); // array of nodes which are unable to copy 00430 $objectIDBlackList = array(); // array of contentobjects which are unable to copy in any location inside new subtree 00431 00432 $sourceNodeList = array_merge( $sourceNodeList, 00433 eZContentObjectTreeNode::subTreeByNodeID( array( 'Limitation' => array() ), $sourceSubTreeMainNodeID ) ); 00434 $countNodeList = count( $sourceNodeList ); 00435 00436 $notifications['Notifications'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00437 "Number of nodes of source subtree - %1", 00438 null, array( $countNodeList ) ); 00439 00440 // Prepare list of source node IDs. We will need it in the future 00441 // for checking node is inside or outside of the subtree being copied. 00442 $sourceNodeIDList = array(); 00443 foreach ( $sourceNodeList as $sourceNode ) 00444 $sourceNodeIDList[] = $sourceNode->attribute( 'node_id' ); 00445 00446 eZDebug::writeDebug( "Source NodeID = $srcNodeID, destination NodeID = $dstNodeID", 00447 "Subtree copy: START!" ); 00448 00449 // 1. copying and publishing source subtree 00450 $k = 0; 00451 while ( count( $sourceNodeList ) > 0 ) 00452 { 00453 if ( $k > $countNodeList ) 00454 { 00455 eZDebug::writeError( "Too many loops while copying nodes.", 00456 "Subtree Copy Error!" ); 00457 break; 00458 } 00459 00460 for ( $i = 0; $i < count( $sourceNodeList ); $i) 00461 { 00462 $sourceNodeID = $sourceNodeList[ $i ]->attribute( 'node_id' ); 00463 00464 // if node was alreaty copied 00465 if ( in_array( $sourceNodeID, $syncNodeIDListSrc ) ) 00466 { 00467 array_splice( $sourceNodeList, $i, 1 ); 00468 continue; 00469 } 00470 00471 //////////// check permissions START 00472 // if node is already in black list, then skip current node: 00473 if ( in_array( $sourceNodeID, $nodeIDBlackList ) ) 00474 { 00475 array_splice( $sourceNodeList, $i, 1 ); 00476 continue; 00477 } 00478 00479 $sourceObject = $sourceNodeList[ $i ]->object(); 00480 00481 $srcSubtreeNodeIDlist = ($sourceNodeID == $sourceSubTreeMainNodeID) ? $syncNodeIDListSrc : $sourceNodeIDList; 00482 $copyResult = copyPublishContentObject( $sourceObject, 00483 $srcSubtreeNodeIDlist, 00484 $syncNodeIDListSrc, $syncNodeIDListNew, 00485 $syncObjectIDListSrc, $syncObjectIDListNew, 00486 $objectIDBlackList, $nodeIDBlackList, 00487 $notifications, 00488 $allVersions, $keepCreator, $keepTime ); 00489 if ( $copyResult === 0 ) 00490 { // if copying successful then remove $sourceNode from $sourceNodeList 00491 array_splice( $sourceNodeList, $i, 1 ); 00492 } 00493 else 00494 $i++; 00495 } 00496 $k++; 00497 } 00498 00499 array_shift( $syncNodeIDListSrc ); 00500 array_shift( $syncNodeIDListNew ); 00501 00502 $countNewNodes = count( $syncNodeIDListNew ); 00503 $countNewObjects = count( $syncObjectIDListNew ); 00504 00505 $notifications['Notifications'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00506 "Number of copied nodes - %1", 00507 null, array( $countNewNodes ) ); 00508 $notifications['Notifications'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00509 "Number of copied contentobjects - %1", 00510 null, array( $countNewObjects ) ); 00511 00512 eZDebug::writeDebug( count( $syncNodeIDListNew ), "Number of copied nodes: " ); 00513 eZDebug::writeDebug( count( $syncObjectIDListNew ), "Number of copied contentobjects: " ); 00514 00515 eZDebug::writeDebug( $objectIDBlackList, "Copy subtree: Not copied object IDs list:" ); 00516 eZDebug::writeDebug( $nodeIDBlackList, "Copy subtree: Not copied node IDs list:" ); 00517 00518 $key = array_search( $sourceSubTreeMainNodeID, $syncNodeIDListSrc ); 00519 if ( $key === false ) 00520 { 00521 eZDebug::writeDebug( "Root node of given subtree was not copied.", 00522 "Subtree copy:" ); 00523 $notifications['Result'] = false; 00524 return $notifications; 00525 } 00526 00527 // 2. fetch all new subtree 00528 00529 $newSubTreeMainNodeID = $syncNodeIDListSrc[ $key ]; 00530 $newSubTreeMainNode = eZContentObjectTreeNode::fetch( $newSubTreeMainNodeID ); 00531 00532 $newNodeList[] = $newSubTreeMainNode; 00533 $newNodeList = $sourceNodeList = array_merge( $newNodeList, 00534 eZContentObjectTreeNode::subTreeByNodeID( false, $newSubTreeMainNodeID ) ); 00535 00536 // 3. fix local links (in ezcontentobject_link) 00537 eZDebug::writeDebug( "Fixing global and local links...", 00538 "Subtree copy:" ); 00539 00540 $db = eZDB::instance(); 00541 if ( !$db ) 00542 { 00543 eZDebug::writeError( "Cannot create instance of eZDB for fixing local links (related objects).", 00544 "Subtree Copy Error!" ); 00545 $notifications['Errors'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00546 "Cannot create instance of eZDB to fix local links (related objects)." ); 00547 return $notifications; 00548 } 00549 00550 $idListINString = $db->generateSQLINStatement( $syncObjectIDListNew, 'from_contentobject_id', false, false, 'int' ); 00551 $relatedRecordsList = $db->arrayQuery( "SELECT * FROM ezcontentobject_link WHERE $idListINString" ); 00552 00553 foreach ( $relatedRecordsList as $relatedEntry ) 00554 { 00555 $kindex = array_search( $relatedEntry[ 'to_contentobject_id' ], $syncObjectIDListSrc ); 00556 if ( $kindex !== false ) 00557 { 00558 $newToContentObjectID = (int) $syncObjectIDListNew[ $kindex ]; 00559 $linkID = (int) $relatedEntry[ 'id' ]; 00560 $db->query( "UPDATE ezcontentobject_link SET to_contentobject_id=$newToContentObjectID WHERE id=$linkID" ); 00561 } 00562 } 00563 00564 // 4. duplicating of global links for new contentobjects (in ezurl_object_link) are automatic during copy of contentobject. 00565 // it was fixed as bug patch. 00566 00567 // 5. fixing node_ids and object_ids in ezxmltext attributes of copied objects 00568 $conditions = array( 'contentobject_id' => '', // 5 00569 'data_type_string' => 'ezxmltext' ); 00570 00571 foreach ( $syncObjectIDListNew as $contentObjectID ) 00572 { 00573 $conditions[ 'contentobject_id' ] = $contentObjectID; 00574 $attributeList = eZPersistentObject::fetchObjectList( eZContentObjectAttribute::definition(), null, $conditions ); 00575 if ( count( $attributeList ) == 0 ) 00576 { 00577 continue; 00578 } 00579 foreach ( $attributeList as $xmlAttribute ) 00580 { 00581 $xmlText = $xmlAttribute->attribute( 'data_text' ); 00582 $xmlTextLen = strlen ( $xmlText ); 00583 $isTextModified = false; 00584 $curPos = 0; 00585 00586 while ( $curPos < $xmlTextLen ) 00587 { 00588 $literalTagBeginPos = strpos( $xmlText, "<literal", $curPos ); 00589 if ( $literalTagBeginPos ) 00590 { 00591 $literalTagEndPos = strpos( $xmlText, "</literal>", $literalTagBeginPos ); 00592 if ( $literalTagEndPos === false ) 00593 break; 00594 $curPos = $literalTagEndPos + 9; 00595 } 00596 00597 if ( ($tagBeginPos = strpos( $xmlText, "<link", $curPos )) !== false or 00598 ($tagBeginPos = strpos( $xmlText, "<a" , $curPos )) !== false or 00599 ($tagBeginPos = strpos( $xmlText, "<embed",$curPos )) !== false ) 00600 { 00601 $tagEndPos = strpos( $xmlText, ">", $tagBeginPos + 1 ); 00602 if ( $tagEndPos === false ) 00603 break; 00604 00605 $tagText = substr( $xmlText, $tagBeginPos, $tagEndPos - $tagBeginPos ); 00606 00607 if ( ($nodeIDAttributePos = strpos( $tagText, " node_id=\"" )) !== false ) 00608 { 00609 $idNumberPos = $nodeIDAttributePos + 10; 00610 $quoteEndPos = strpos( $tagText, "\"", $idNumberPos ); 00611 00612 if ( $quoteEndPos !== false ) 00613 { 00614 $idNumber = substr( $tagText, $idNumberPos, $quoteEndPos - $idNumberPos ); 00615 $key = array_search( (int) $idNumber, $syncNodeIDListSrc ); 00616 00617 if ( $key !== false ) 00618 { 00619 $tagText = substr_replace( $tagText, (string) $syncNodeIDListNew[ $key ], $idNumberPos, $quoteEndPos - $idNumberPos ); 00620 $xmlText = substr_replace( $xmlText, $tagText, $tagBeginPos, $tagEndPos - $tagBeginPos ); 00621 $isTextModified = true; 00622 } 00623 } 00624 } 00625 else if ( ($objectIDAttributePos = strpos( $tagText, " object_id=\"" )) !== false ) 00626 { 00627 $idNumberPos = $objectIDAttributePos + 12; 00628 $quoteEndPos = strpos( $tagText, "\"", $idNumberPos ); 00629 00630 if ( $quoteEndPos !== false ) 00631 { 00632 $idNumber = substr( $tagText, $idNumberPos, $quoteEndPos - $idNumberPos ); 00633 $key = array_search( (int) $idNumber, $syncObjectIDListSrc ); 00634 if ( $key !== false ) 00635 { 00636 $tagText = substr_replace( $tagText, (string) $syncObjectIDListNew[ $key ], $idNumberPos, $quoteEndPos - $idNumberPos ); 00637 $xmlText = substr_replace( $xmlText, $tagText, $tagBeginPos, $tagEndPos - $tagBeginPos ); 00638 $isTextModified = true; 00639 } 00640 } 00641 } 00642 $curPos = $tagEndPos; 00643 } 00644 else if ( ($tagBeginPos = strpos( $xmlText, "<object", $curPos )) !== false ) 00645 { 00646 $tagEndPos = strpos( $xmlText, ">", $tagBeginPos + 1 ); 00647 if ( !$tagEndPos ) 00648 break; 00649 00650 $tagText = substr( $xmlText, $tagBeginPos, $tagEndPos - $tagBeginPos ); 00651 00652 if ( ($idAttributePos = strpos( $tagText, " id=\"" )) !== false ) 00653 { 00654 $idNumberPos = $idAttributePos + 5; 00655 $quoteEndPos = strpos( $tagText, "\"", $idNumberPos ); 00656 00657 if ( $quoteEndPos !== false ) 00658 { 00659 $idNumber = substr( $tagText, $idNumberPos, $quoteEndPos - $idNumberPos ); 00660 $key = array_search( (int) $idNumber, $syncObjectIDListSrc ); 00661 if ( $key !== false ) 00662 { 00663 $tagText = substr_replace( $tagText, (string) $syncObjectIDListNew[ $key ], $idNumberPos, $quoteEndPos - $idNumberPos ); 00664 $xmlText = substr_replace( $xmlText, $tagText, $tagBeginPos, $tagEndPos - $tagBeginPos ); 00665 $isTextModified = true; 00666 } 00667 } 00668 } 00669 $curPos = $tagEndPos; 00670 } 00671 else 00672 break; 00673 00674 } // while END 00675 00676 if ( $isTextModified ) 00677 { 00678 $xmlAttribute->setAttribute( 'data_text', $xmlText ); 00679 $xmlAttribute->store(); 00680 } 00681 } // foreach END 00682 } 00683 00684 // 6. fixing datatype ezobjectrelationlist 00685 $conditions = array( 'contentobject_id' => '', 00686 'data_type_string' => 'ezobjectrelationlist' ); 00687 foreach ( $syncObjectIDListNew as $contentObjectID ) 00688 { 00689 $conditions[ 'contentobject_id' ] = $contentObjectID; 00690 $attributeList = eZPersistentObject::fetchObjectList( eZContentObjectAttribute::definition(), null, $conditions ); 00691 if ( count( $attributeList ) == 0 ) 00692 { 00693 continue; 00694 } 00695 foreach ( $attributeList as $relationListAttribute ) 00696 { 00697 $relationsXmlText = $relationListAttribute->attribute( 'data_text' ); 00698 $relationsDom = eZObjectRelationListType::parseXML( $relationsXmlText ); 00699 $relationItems = $relationsDom->getElementsByTagName( 'relation-item' ); 00700 $isRelationModified = false; 00701 00702 foreach ( $relationItems as $relationItem ) 00703 { 00704 $originalObjectID = $relationItem->getAttribute( 'contentobject-id' ); 00705 00706 $key = array_search( $originalObjectID, $syncObjectIDListSrc ); 00707 if ( $key !== false ) 00708 { 00709 $newObjectID = $syncObjectIDListNew[ $key ]; 00710 $relationItem->setAttribute( 'contentobject-id', $newObjectID ); 00711 $isRelationModified = true; 00712 } 00713 00714 $originalNodeID = $relationItem->getAttribute( 'node-id' ); 00715 if ( $originalNodeID ) 00716 { 00717 $key = array_search( $originalNodeID, $syncNodeIDListSrc ); 00718 if ( $key !== false ) 00719 { 00720 $newNodeID = $syncNodeIDListNew[ $key ]; 00721 $relationItem->setAttribute( 'node-id', $newNodeID ); 00722 00723 $newNode = eZContentObjectTreeNode::fetch( $newNodeID ); 00724 $newParentNodeID = $newNode->attribute( 'parent_node_id' ); 00725 $relationItem->setAttribute( 'parent-node-id', $newParentNodeID ); 00726 $isRelationModified = true; 00727 } 00728 } 00729 } 00730 if ( $isRelationModified ) 00731 { 00732 $attributeID = $relationListAttribute->attribute( 'id' ); 00733 $attributeVersion = $relationListAttribute->attribute( 'version' ); 00734 $changedDomString =$db->escapeString( eZObjectRelationListType::domString( $relationsDom ) ); 00735 $db->query( "UPDATE ezcontentobject_attribute SET data_text='$changedDomString' 00736 WHERE id=$attributeID AND version=$attributeVersion" ); 00737 } 00738 } 00739 } 00740 00741 eZDebug::writeDebug( "Successfuly DONE.", 00742 "Copy subtree:" ); 00743 00744 $notifications['Result'] = true; 00745 return $notifications; 00746 } // function copySubtree END 00747 00748 /*! 00749 Browse for node to place the object copy into 00750 */ 00751 function browse( $Module, $srcNode ) 00752 { 00753 if ( $Module->hasActionParameter( 'LanguageCode' ) ) 00754 $languageCode = $Module->actionParameter( 'LanguageCode' ); 00755 else 00756 { 00757 $languageCode = false; 00758 } 00759 00760 $nodeID = $srcNode->attribute( 'node_id' ); 00761 $object = $srcNode->attribute( 'object' ); 00762 $objectID = $object->attribute( 'id' ); 00763 $class = $object->contentClass(); 00764 $classID = $class->attribute( 'id' ); 00765 $srcParentNodeID = $srcNode->attribute( 'parent_node_id' ); 00766 00767 $ignoreNodesSelect = array(); 00768 $ignoreNodesClick = array(); 00769 foreach ( $object->assignedNodes( false ) as $element ) 00770 { 00771 $ignoreNodesSelect[] = $element['node_id']; 00772 $ignoreNodesClick[] = $element['node_id']; 00773 } 00774 $ignoreNodesSelect = array_unique( $ignoreNodesSelect ); 00775 $ignoreNodesClick = array_unique( $ignoreNodesClick ); 00776 00777 $viewMode = 'full'; 00778 if ( $Module->hasActionParameter( 'ViewMode' ) ) 00779 $viewMode = $Module->actionParameter( 'ViewMode' ); 00780 00781 eZContentBrowse::browse( 00782 array( 'action_name' => 'CopySubtree', 00783 'description_template' => 'design:content/browse_copy_subtree.tpl', 00784 'keys' => array( 'class' => $classID, 00785 'class_id' => $class->attribute( 'identifier' ), 00786 'classgroup' => $class->attribute( 'ingroup_id_list' ), 00787 'section' => $object->attribute( 'section_id' ) ), 00788 'ignore_nodes_select' => $ignoreNodesSelect, 00789 'ignore_nodes_click' => $ignoreNodesClick, 00790 'persistent_data' => array( 'ObjectID' => $objectID, 00791 'NodeID' => $nodeID ), 00792 'permission' => array( 'access' => 'create', 'contentclass_id' => $classID ), 00793 'content' => array( 'node_id' => $nodeID ), 00794 'start_node' => $srcParentNodeID, 00795 'cancel_page' => $Module->redirectionURIForModule( $Module, 'view', 00796 array( $viewMode, $srcParentNodeID, $languageCode ) ), 00797 'from_page' => "/content/copysubtree" ), 00798 $Module ); 00799 } 00800 00801 /*! 00802 Redirect to the page that lets a user to choose which versions to copy: 00803 either all version or the current one. 00804 */ 00805 function chooseOptionsToCopy( $Module, &$Result, $srcNode, $chooseVersions, $chooseCreator, $chooseTime ) 00806 { 00807 $selectedNodeIDArray = eZContentBrowse::result( $Module->currentAction() ); 00808 00809 00810 $tpl = eZTemplate::factory(); 00811 $tpl->setVariable( 'node', $srcNode ); 00812 $tpl->setVariable( 'selected_node_id', $selectedNodeIDArray[0] ); 00813 $tpl->setVariable( 'choose_versions', $chooseVersions ); 00814 $tpl->setVariable( 'choose_creator', $chooseCreator ); 00815 $tpl->setVariable( 'choose_time', $chooseTime ); 00816 00817 $Result['content'] = $tpl->fetch( 'design:content/copy_subtree.tpl' ); 00818 $Result['path'] = array( array( 'url' => false, 00819 'text' => ezpI18n::tr( 'kernel/content', 'Content' ) ), 00820 array( 'url' => false, 00821 'text' => ezpI18n::tr( 'kernel/content', 'Copy subtree' ) ) ); 00822 } 00823 00824 function showNotificationAfterCopying( $http, $Module, &$Result, &$Notifications, $srcNode ) 00825 { 00826 $tpl = eZTemplate::factory(); 00827 00828 if ( $http->hasSessionVariable( "LastAccessesURI", false ) ) 00829 { 00830 $tpl->setVariable( 'redirect_url', $http->sessionVariable( "LastAccessesURI" ) ); 00831 } 00832 else 00833 { 00834 $parentRootNodeID = $srcNode->attribute( 'parent_node_id' ); 00835 if ( $Module->hasActionParameter( 'LanguageCode' ) ) 00836 $languageCode = $Module->actionParameter( 'LanguageCode' ); 00837 else 00838 { 00839 $languageCode = false; 00840 } 00841 00842 if ( $Module->hasActionParameter( 'ViewMode' ) ) 00843 $viewMode = $Module->actionParameter( 'ViewMode' ); 00844 else 00845 $viewMode = 'full'; 00846 00847 $redirectURI = $Module->redirectionURIForModule( $Module, 'view', array( $viewMode, $parentRootNodeID, $languageCode ) ); 00848 $tpl->setVariable( 'redirect_url', $redirectURI ); 00849 } 00850 00851 $tpl->setVariable( 'source_node', $srcNode ); 00852 //$tpl->setVariable( 'subtree_nodes_count', $srcSubtreeNodesCount ); 00853 $tpl->setVariable( 'notifications', $Notifications ); 00854 00855 $Result['content'] = $tpl->fetch( 'design:content/copy_subtree_notification.tpl' ); 00856 $Result['path'] = array( array( 'url' => false, 00857 'text' => ezpI18n::tr( 'kernel/content', 'Content' ) ), 00858 array( 'url' => false, 00859 'text' => ezpI18n::tr( 'kernel/content', 'Copy subtree' ) ) ); 00860 } 00861 /////////// functions END ================================================================== 00862 00863 $Result = array(); 00864 $notifications = array( 'Notifications' => array(), 00865 'Warnings' => array(), 00866 'Errors' => array(), 00867 'Result' => false ); 00868 $contentINI = eZINI::instance( 'content.ini' ); 00869 00870 // check if number of nodes being copied not more then MaxNodesCopySubtree setting 00871 $maxNodesCopySubtree = $contentINI->variable( 'CopySettings', 'MaxNodesCopySubtree' ); 00872 $srcSubtreeNodesCount = $srcNode->subTreeCount(); 00873 00874 if ( $srcSubtreeNodesCount > $maxNodesCopySubtree ) 00875 { 00876 $notifications['Warnings'][] = ezpI18n::tr( 'kernel/content/copysubtree', 00877 "You are trying to copy a subtree that contains more than ". 00878 "the maximum possible nodes for subtree copying. ". 00879 "You can copy this subtree using Subtree Copy script.", 00880 null, array( $maxNodesCopySubtree ) ); 00881 $notifications['Result'] = false; 00882 showNotificationAfterCopying( $http, $Module, $Result, $notifications, $srcNode ); 00883 return; 00884 } 00885 00886 $versionHandling = $contentINI->variable( 'CopySettings', 'VersionHandling' ); 00887 $creatorHandling = $contentINI->variable( 'CopySettings', 'CreatorHandling' ); 00888 $timeHandling = $contentINI->variable( 'CopySettings', 'TimeHandling' ); 00889 $showCopySubtreeNotification = $contentINI->variable( 'CopySettings', 'ShowCopySubtreeNotification' ); 00890 00891 $chooseVersions = ( $versionHandling == 'user-defined' ); 00892 $chooseCreator = ( $creatorHandling == 'user-defined' ); 00893 $chooseTime = ( $timeHandling == 'user-defined' ); 00894 $showNotification = ( $showCopySubtreeNotification == 'enabled' ); 00895 00896 if( $chooseVersions ) 00897 $allVersions = ( $Module->hasActionParameter( 'VersionChoice' ) and 00898 $Module->actionParameter( 'VersionChoice' ) == 1 ) ? true : false; 00899 else 00900 $allVersions = ( $versionHandling == 'last-published' ) ? false : true; 00901 00902 if ( $chooseCreator ) 00903 $keepCreator = ( $Module->hasActionParameter( 'CreatorChoice' ) and 00904 $Module->actionParameter( 'CreatorChoice' ) == 1 ) ? true : false; 00905 else 00906 $keepCreator = ( $creatorHandling == 'keep-unchanged' ); 00907 00908 if ( $chooseTime ) 00909 $keepTime = ( $Module->hasActionParameter( 'TimeChoice' ) and 00910 $Module->actionParameter( 'TimeChoice' ) == 1 ) ? true : false; 00911 else 00912 $keepTime = ( $timeHandling == 'keep-unchanged' ); 00913 00914 00915 $keepCreator = false; 00916 $keepTime = false; 00917 00918 if ( $Module->isCurrentAction( 'Copy' ) ) 00919 { 00920 // actually do copying after a user has selected object versions to copy 00921 $newParentNodeID = $http->postVariable( 'SelectedNodeID' ); 00922 copySubtree( $NodeID, $newParentNodeID, $notifications, $allVersions, $keepCreator, $keepTime ); 00923 00924 if ( $showNotification ) 00925 { 00926 showNotificationAfterCopying( $http, $Module, $Result, $notifications, $srcNode ); 00927 return; 00928 } 00929 return $Module->redirectToView( 'view', array( 'full', $newParentNodeID ) ); 00930 } 00931 else if ( $Module->isCurrentAction( 'CopySubtree' ) ) 00932 { 00933 // we get here after a user selects target node to place the source object under 00934 if( $chooseVersions or $chooseCreator or $chooseTime ) 00935 { 00936 // redirect to the page with choice of versions to copy 00937 chooseOptionsToCopy( $Module, $Result, $srcNode, $chooseVersions, $chooseCreator, $chooseTime ); 00938 } 00939 else 00940 { 00941 // actually do copying of the pre-configured object version(s) 00942 $selectedNodeIDArray = eZContentBrowse::result( $Module->currentAction() ); 00943 $newParentNodeID = $selectedNodeIDArray[0]; 00944 copySubtree( $NodeID, $newParentNodeID, $notifications, $allVersions, $keepCreator, $keepTime ); 00945 00946 if ( $showNotification ) 00947 { 00948 showNotificationAfterCopying( $http, $Module, $Result, $notifications, $srcNode ); 00949 return; 00950 } 00951 return $Module->redirectToView( 'view', array( 'full', $newParentNodeID ) ); 00952 } 00953 } 00954 else // default, initial action 00955 { //Browse for target node. 00956 //We get here when a user clicks "copy" button when viewing some node. 00957 browse( $Module, $srcNode ); 00958 } 00959 00960 ?>