|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZContentOperationCollection class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package kernel 00009 */ 00010 00011 /*! 00012 \class eZContentOperationCollection ezcontentoperationcollection.php 00013 \brief The class eZContentOperationCollection does 00014 00015 */ 00016 00017 class eZContentOperationCollection 00018 { 00019 /*! 00020 Constructor 00021 */ 00022 function eZContentOperationCollection() 00023 { 00024 } 00025 00026 static public function readNode( $nodeID ) 00027 { 00028 00029 } 00030 00031 static public function readObject( $nodeID, $userID, $languageCode ) 00032 { 00033 if ( $languageCode != '' ) 00034 { 00035 $node = eZContentObjectTreeNode::fetch( $nodeID, $languageCode ); 00036 } 00037 else 00038 { 00039 $node = eZContentObjectTreeNode::fetch( $nodeID ); 00040 } 00041 00042 if ( $node === null ) 00043 // return $Module->handleError( eZError::KERNEL_NOT_AVAILABLE, 'kernel' ); 00044 return false; 00045 00046 00047 $object = $node->attribute( 'object' ); 00048 00049 if ( $object === null ) 00050 // return $Module->handleError( eZError::KERNEL_ACCESS_DENIED, 'kernel' ); 00051 { 00052 return false; 00053 } 00054 /* 00055 if ( !$object->attribute( 'can_read' ) ) 00056 { 00057 // return $Module->handleError( eZError::KERNEL_ACCESS_DENIED, 'kernel' ); 00058 return false; 00059 } 00060 */ 00061 00062 return array( 'status' => true, 'object' => $object, 'node' => $node ); 00063 } 00064 00065 static public function loopNodes( $nodeID ) 00066 { 00067 return array( 'parameters' => array( array( 'parent_node_id' => 3 ), 00068 array( 'parent_node_id' => 5 ), 00069 array( 'parent_node_id' => 12 ) ) ); 00070 } 00071 00072 static public function loopNodeAssignment( $objectID, $versionNum ) 00073 { 00074 $object = eZContentObject::fetch( $objectID ); 00075 00076 $version = $object->version( $versionNum ); 00077 $nodeAssignmentList = $version->attribute( 'node_assignments' ); 00078 00079 $parameters = array(); 00080 foreach ( $nodeAssignmentList as $nodeAssignment ) 00081 { 00082 if ( $nodeAssignment->attribute( 'parent_node' ) > 0 ) 00083 { 00084 if ( $nodeAssignment->attribute( 'is_main' ) == 1 ) 00085 { 00086 $mainNodeID = self::publishNode( $nodeAssignment->attribute( 'parent_node' ), $objectID, $versionNum, false ); 00087 } 00088 else 00089 { 00090 $parameters[] = array( 'parent_node_id' => $nodeAssignment->attribute( 'parent_node' ) ); 00091 } 00092 } 00093 } 00094 for ( $i = 0; $i < count( $parameters ); $i++ ) 00095 { 00096 $parameters[$i]['main_node_id'] = $mainNodeID; 00097 } 00098 00099 return array( 'parameters' => $parameters ); 00100 } 00101 00102 function publishObjectExtensionHandler( $contentObjectID, $contentObjectVersion ) 00103 { 00104 eZContentObjectEditHandler::executePublish( $contentObjectID, $contentObjectVersion ); 00105 } 00106 00107 static public function setVersionStatus( $objectID, $versionNum, $status ) 00108 { 00109 $object = eZContentObject::fetch( $objectID ); 00110 00111 if ( !$versionNum ) 00112 { 00113 $versionNum = $object->attribute( 'current_version' ); 00114 } 00115 $version = $object->version( $versionNum ); 00116 if ( !$version ) 00117 return; 00118 00119 $version->setAttribute( 'status', $status ); 00120 $version->store(); 00121 } 00122 00123 static public function setObjectStatusPublished( $objectID, $versionNum ) 00124 { 00125 $object = eZContentObject::fetch( $objectID ); 00126 $version = $object->version( $versionNum ); 00127 00128 $db = eZDB::instance(); 00129 $db->begin(); 00130 00131 $object->publishContentObjectRelations( $versionNum ); 00132 $object->setAttribute( 'status', eZContentObject::STATUS_PUBLISHED ); 00133 $version->setAttribute( 'status', eZContentObjectVersion::STATUS_PUBLISHED ); 00134 $object->setAttribute( 'current_version', $versionNum ); 00135 00136 $objectIsAlwaysAvailable = $object->isAlwaysAvailable(); 00137 $object->setAttribute( 'language_mask', eZContentLanguage::maskByLocale( $version->translationList( false, false ), $objectIsAlwaysAvailable ) ); 00138 00139 if ( $object->attribute( 'published' ) == 0 ) 00140 { 00141 $object->setAttribute( 'published', time() ); 00142 } 00143 $object->setAttribute( 'modified', time() ); 00144 $classID = $object->attribute( 'contentclass_id' ); 00145 00146 $class = eZContentClass::fetch( $classID ); 00147 $objectName = $class->contentObjectName( $object ); 00148 $object->setName( $objectName, $versionNum ); 00149 $existingTranslations = $version->translations( false ); 00150 foreach( $existingTranslations as $translation ) 00151 { 00152 $translatedName = $class->contentObjectName( $object, $versionNum, $translation ); 00153 $object->setName( $translatedName, $versionNum, $translation ); 00154 } 00155 00156 if ( $objectIsAlwaysAvailable ) 00157 { 00158 $initialLanguageID = $object->attribute( 'initial_language_id' ); 00159 $object->setAlwaysAvailableLanguageID( $initialLanguageID ); 00160 } 00161 00162 $version->store(); 00163 $object->store(); 00164 00165 eZContentObjectTreeNode::setVersionByObjectID( $objectID, $versionNum ); 00166 00167 $nodes = $object->assignedNodes(); 00168 foreach ( $nodes as $node ) 00169 { 00170 $node->setName( $object->attribute( 'name' ) ); 00171 $node->updateSubTreePath(); 00172 } 00173 00174 $db->commit(); 00175 00176 /* Check if current class is the user class, and if so, clean up the user-policy cache */ 00177 if ( in_array( $classID, eZUser::contentClassIDs() ) ) 00178 { 00179 eZUser::purgeUserCacheByUserId( $object->attribute( 'id' ) ); 00180 } 00181 } 00182 00183 static public function attributePublishAction( $objectID, $versionNum ) 00184 { 00185 $object = eZContentObject::fetch( $objectID ); 00186 $nodes = $object->assignedNodes(); 00187 $version = $object->version( $versionNum ); 00188 $contentObjectAttributes = $object->contentObjectAttributes( true, $versionNum, $version->initialLanguageCode(), false ); 00189 foreach ( $contentObjectAttributes as $contentObjectAttribute ) 00190 { 00191 $contentObjectAttribute->onPublish( $object, $nodes ); 00192 } 00193 } 00194 00195 /*! 00196 \static 00197 Generates the related viewcaches (PreGeneration) for the content object. 00198 It will only do this if [ContentSettings]/PreViewCache in site.ini is enabled. 00199 00200 \param $objectID The ID of the content object to generate caches for. 00201 */ 00202 static public function generateObjectViewCache( $objectID ) 00203 { 00204 eZContentCacheManager::generateObjectViewCache( $objectID ); 00205 } 00206 00207 /*! 00208 \static 00209 Clears the related viewcaches for the content object using the smart viewcache system. 00210 00211 \param $objectID The ID of the content object to clear caches for 00212 \param $versionNum The version of the object to use or \c true for current version 00213 \param $additionalNodeList An array with node IDs to add to clear list, 00214 or \c false for no additional nodes. 00215 */ 00216 static public function clearObjectViewCache( $objectID, $versionNum = true, $additionalNodeList = false ) 00217 { 00218 eZContentCacheManager::clearContentCacheIfNeeded( $objectID, $versionNum, $additionalNodeList ); 00219 } 00220 00221 00222 static public function publishNode( $parentNodeID, $objectID, $versionNum, $mainNodeID ) 00223 { 00224 $object = eZContentObject::fetch( $objectID ); 00225 $nodeAssignment = eZNodeAssignment::fetch( $objectID, $versionNum, $parentNodeID ); 00226 $version = $object->version( $versionNum ); 00227 00228 $fromNodeID = $nodeAssignment->attribute( 'from_node_id' ); 00229 $originalObjectID = $nodeAssignment->attribute( 'contentobject_id' ); 00230 00231 $nodeID = $nodeAssignment->attribute( 'parent_node' ); 00232 $opCode = $nodeAssignment->attribute( 'op_code' ); 00233 $parentNode = eZContentObjectTreeNode::fetch( $nodeID ); 00234 00235 // if parent doesn't exist, return. See issue #18320 00236 if ( !$parentNode instanceof eZContentObjectTreeNode ) 00237 { 00238 eZDebug::writeError( "Parent node doesn't exist. object id: $objectID, node_assignment id: " . $nodeAssignment->attribute( 'id' ), __METHOD__ ); 00239 return; 00240 } 00241 $parentNodeID = $parentNode->attribute( 'node_id' ); 00242 $existingNode = null; 00243 00244 $db = eZDB::instance(); 00245 $db->begin(); 00246 if ( strlen( $nodeAssignment->attribute( 'parent_remote_id' ) ) > 0 ) 00247 { 00248 $existingNode = eZContentObjectTreeNode::fetchByRemoteID( $nodeAssignment->attribute( 'parent_remote_id' ) ); 00249 } 00250 if ( !$existingNode ); 00251 { 00252 $existingNode = eZContentObjectTreeNode::findNode( $nodeID , $object->attribute( 'id' ), true ); 00253 } 00254 $updateSectionID = false; 00255 // now we check the op_code to see what to do 00256 if ( ( $opCode & 1 ) == eZNodeAssignment::OP_CODE_NOP ) 00257 { 00258 // There is nothing to do so just return 00259 $db->commit(); 00260 if ( $mainNodeID == false ) 00261 { 00262 return $object->attribute( 'main_node_id' ); 00263 } 00264 00265 return; 00266 } 00267 00268 $updateFields = false; 00269 00270 if ( $opCode == eZNodeAssignment::OP_CODE_MOVE || 00271 $opCode == eZNodeAssignment::OP_CODE_CREATE ) 00272 { 00273 // if ( $fromNodeID == 0 || $fromNodeID == -1) 00274 if ( $opCode == eZNodeAssignment::OP_CODE_CREATE || 00275 $opCode == eZNodeAssignment::OP_CODE_SET ) 00276 { 00277 // If the node already exists it means we have a conflict (for 'CREATE'). 00278 // We resolve this by leaving node-assignment data be. 00279 if ( $existingNode == null ) 00280 { 00281 $parentNode = eZContentObjectTreeNode::fetch( $nodeID ); 00282 00283 $user = eZUser::currentUser(); 00284 if ( !eZSys::isShellExecution() and !$user->isAnonymous() ) 00285 { 00286 eZContentBrowseRecent::createNew( $user->id(), $parentNode->attribute( 'node_id' ), $parentNode->attribute( 'name' ) ); 00287 } 00288 $updateFields = true; 00289 00290 $existingNode = $parentNode->addChild( $object->attribute( 'id' ), true ); 00291 00292 if ( $fromNodeID == -1 ) 00293 { 00294 $updateSectionID = true; 00295 } 00296 } 00297 elseif ( $opCode == eZNodeAssignment::OP_CODE_SET ) 00298 { 00299 $updateFields = true; 00300 } 00301 } 00302 elseif ( $opCode == eZNodeAssignment::OP_CODE_MOVE ) 00303 { 00304 if ( $fromNodeID == 0 || $fromNodeID == -1 ) 00305 { 00306 eZDebug::writeError( "NodeAssignment '" . $nodeAssignment->attribute( 'id' ) . "' is marked with op_code='$opCode' but has no data in from_node_id. Cannot use it for moving node.", __METHOD__ ); 00307 } 00308 else 00309 { 00310 // clear cache for old placement. 00311 $additionalNodeIDList = array( $fromNodeID ); 00312 00313 eZContentCacheManager::clearContentCacheIfNeeded( $objectID, $versionNum, $additionalNodeIDList ); 00314 00315 $originalNode = eZContentObjectTreeNode::fetchNode( $originalObjectID, $fromNodeID ); 00316 if ( $originalNode->attribute( 'main_node_id' ) == $originalNode->attribute( 'node_id' ) ) 00317 { 00318 $updateSectionID = true; 00319 } 00320 $originalNode->move( $parentNodeID ); 00321 $existingNode = eZContentObjectTreeNode::fetchNode( $originalObjectID, $parentNodeID ); 00322 $updateFields = true; 00323 } 00324 } 00325 } 00326 elseif ( $opCode == eZNodeAssignment::OP_CODE_REMOVE ) 00327 { 00328 $db->commit(); 00329 return; 00330 } 00331 00332 if ( $updateFields ) 00333 { 00334 if ( strlen( $nodeAssignment->attribute( 'parent_remote_id' ) ) > 0 ) 00335 { 00336 $existingNode->setAttribute( 'remote_id', $nodeAssignment->attribute( 'parent_remote_id' ) ); 00337 } 00338 $existingNode->setAttribute( 'sort_field', $nodeAssignment->attribute( 'sort_field' ) ); 00339 $existingNode->setAttribute( 'sort_order', $nodeAssignment->attribute( 'sort_order' ) ); 00340 } 00341 $existingNode->setAttribute( 'contentobject_is_published', 1 ); 00342 00343 eZDebug::createAccumulatorGroup( 'nice_urls_total', 'Nice urls' ); 00344 00345 if ( $mainNodeID > 0 ) 00346 { 00347 $existingNodeID = $existingNode->attribute( 'node_id' ); 00348 if ( $existingNodeID != $mainNodeID ) 00349 { 00350 eZContentBrowseRecent::updateNodeID( $existingNodeID, $mainNodeID ); 00351 } 00352 $existingNode->setAttribute( 'main_node_id', $mainNodeID ); 00353 } 00354 else 00355 { 00356 $existingNode->setAttribute( 'main_node_id', $existingNode->attribute( 'node_id' ) ); 00357 } 00358 00359 $existingNode->store(); 00360 00361 if ( $updateSectionID ) 00362 { 00363 eZContentOperationCollection::updateSectionID( $objectID, $versionNum ); 00364 } 00365 $db->commit(); 00366 if ( $mainNodeID == false ) 00367 { 00368 return $existingNode->attribute( 'node_id' ); 00369 } 00370 } 00371 00372 static public function updateSectionID( $objectID, $versionNum ) 00373 { 00374 $object = eZContentObject::fetch( $objectID ); 00375 00376 $version = $object->version( $versionNum ); 00377 00378 if ( $versionNum == 1 or 00379 $object->attribute( 'current_version' ) == $versionNum ) 00380 { 00381 $newMainAssignment = null; 00382 $newMainAssignments = eZNodeAssignment::fetchForObject( $objectID, $versionNum, 1 ); 00383 if ( isset( $newMainAssignments[0] ) ) 00384 { 00385 $newMainAssignment = $newMainAssignments[0]; 00386 } 00387 // we should not update section id for toplevel nodes 00388 if ( $newMainAssignment && $newMainAssignment->attribute( 'parent_node' ) != 1 ) 00389 { 00390 // We should check if current object already has been updated for section_id 00391 // If yes we should not update object section_id by $parentNodeSectionID 00392 $sectionID = $object->attribute( 'section_id' ); 00393 if ( $sectionID > 0 ) 00394 return; 00395 00396 $newParentObject = $newMainAssignment->getParentObject(); 00397 if ( !$newParentObject ) 00398 { 00399 return array( 'status' => eZModuleOperationInfo::STATUS_CANCELLED ); 00400 } 00401 $parentNodeSectionID = $newParentObject->attribute( 'section_id' ); 00402 $object->setAttribute( 'section_id', $parentNodeSectionID ); 00403 $object->store(); 00404 } 00405 00406 return; 00407 } 00408 00409 $newMainAssignmentList = eZNodeAssignment::fetchForObject( $objectID, $versionNum, 1 ); 00410 $newMainAssignment = ( count( $newMainAssignmentList ) ) ? array_pop( $newMainAssignmentList ) : null; 00411 00412 $currentVersion = $object->attribute( 'current' ); 00413 // Here we need to fetch published nodes and not old node assignments. 00414 $oldMainNode = $object->mainNode(); 00415 00416 if ( $newMainAssignment && $oldMainNode 00417 && $newMainAssignment->attribute( 'parent_node' ) != $oldMainNode->attribute( 'parent_node_id' ) ) 00418 { 00419 $oldMainParentNode = $oldMainNode->attribute( 'parent' ); 00420 if ( $oldMainParentNode ) 00421 { 00422 $oldParentObject = $oldMainParentNode->attribute( 'object' ); 00423 $oldParentObjectSectionID = $oldParentObject->attribute( 'section_id' ); 00424 if ( $oldParentObjectSectionID == $object->attribute( 'section_id' ) ) 00425 { 00426 $newParentNode = $newMainAssignment->attribute( 'parent_node_obj' ); 00427 if ( !$newParentNode ) 00428 return; 00429 $newParentObject = $newParentNode->attribute( 'object' ); 00430 if ( !$newParentObject ) 00431 return; 00432 00433 $newSectionID = $newParentObject->attribute( 'section_id' ); 00434 00435 if ( $newSectionID != $object->attribute( 'section_id' ) ) 00436 { 00437 $oldSectionID = $object->attribute( 'section_id' ); 00438 $object->setAttribute( 'section_id', $newSectionID ); 00439 00440 $db = eZDB::instance(); 00441 $db->begin(); 00442 $object->store(); 00443 $mainNodeID = $object->attribute( 'main_node_id' ); 00444 if ( $mainNodeID > 0 ) 00445 { 00446 eZContentObjectTreeNode::assignSectionToSubTree( $mainNodeID, 00447 $newSectionID, 00448 $oldSectionID ); 00449 } 00450 $db->commit(); 00451 } 00452 } 00453 } 00454 } 00455 } 00456 00457 static public function removeOldNodes( $objectID, $versionNum ) 00458 { 00459 $object = eZContentObject::fetch( $objectID ); 00460 00461 00462 $version = $object->version( $versionNum ); 00463 $moveToTrash = true; 00464 00465 $assignedExistingNodes = $object->attribute( 'assigned_nodes' ); 00466 00467 $curentVersionNodeAssignments = $version->attribute( 'node_assignments' ); 00468 $removeParentNodeList = array(); 00469 $removeAssignmentsList = array(); 00470 foreach ( $curentVersionNodeAssignments as $nodeAssignment ) 00471 { 00472 $nodeAssignmentOpcode = $nodeAssignment->attribute( 'op_code' ); 00473 if ( $nodeAssignmentOpcode == eZNodeAssignment::OP_CODE_REMOVE || 00474 $nodeAssignmentOpcode == eZNodeAssignment::OP_CODE_REMOVE_NOP ) 00475 { 00476 $removeAssignmentsList[] = $nodeAssignment->attribute( 'id' ); 00477 if ( $nodeAssignmentOpcode == eZNodeAssignment::OP_CODE_REMOVE ) 00478 { 00479 $removeParentNodeList[] = $nodeAssignment->attribute( 'parent_node' ); 00480 } 00481 } 00482 } 00483 00484 $db = eZDB::instance(); 00485 $db->begin(); 00486 foreach ( $assignedExistingNodes as $node ) 00487 { 00488 if ( in_array( $node->attribute( 'parent_node_id' ), $removeParentNodeList ) ) 00489 { 00490 eZContentObjectTreeNode::removeSubtrees( array( $node->attribute( 'node_id' ) ), $moveToTrash ); 00491 } 00492 } 00493 00494 if ( count( $removeAssignmentsList ) > 0 ) 00495 { 00496 eZNodeAssignment::purgeByID( $removeAssignmentsList ); 00497 } 00498 00499 $db->commit(); 00500 } 00501 00502 // New function which resets the op_code field when the object is published. 00503 static public function resetNodeassignmentOpcodes( $objectID, $versionNum ) 00504 { 00505 $object = eZContentObject::fetch( $objectID ); 00506 $version = $object->version( $versionNum ); 00507 $nodeAssignments = $version->attribute( 'node_assignments' ); 00508 foreach ( $nodeAssignments as $nodeAssignment ) 00509 { 00510 if ( ( $nodeAssignment->attribute( 'op_code' ) & 1 ) == eZNodeAssignment::OP_CODE_EXECUTE ) 00511 { 00512 $nodeAssignment->setAttribute( 'op_code', ( $nodeAssignment->attribute( 'op_code' ) & ~1 ) ); 00513 $nodeAssignment->store(); 00514 } 00515 } 00516 } 00517 00518 /** 00519 * Registers the object in search engine. 00520 * 00521 * @note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00522 * the calls within a db transaction; thus within db->begin and db->commit. 00523 * 00524 * @param int $objectID Id of the object. 00525 */ 00526 static public function registerSearchObject( $objectID ) 00527 { 00528 $objectID = (int)$objectID; 00529 eZDebug::createAccumulatorGroup( 'search_total', 'Search Total' ); 00530 00531 $ini = eZINI::instance( 'site.ini' ); 00532 $insertPendingAction = false; 00533 $object = null; 00534 00535 switch ( $ini->variable( 'SearchSettings', 'DelayedIndexing' ) ) 00536 { 00537 case 'enabled': 00538 $insertPendingAction = true; 00539 break; 00540 case 'classbased': 00541 $classList = $ini->variable( 'SearchSettings', 'DelayedIndexingClassList' ); 00542 $object = eZContentObject::fetch( $objectID ); 00543 if ( is_array( $classList ) && in_array( $object->attribute( 'class_identifier' ), $classList ) ) 00544 { 00545 $insertPendingAction = true; 00546 } 00547 } 00548 00549 if ( $insertPendingAction ) 00550 { 00551 eZDB::instance()->query( "INSERT INTO ezpending_actions( action, param ) VALUES ( 'index_object', '$objectID' )" ); 00552 return; 00553 } 00554 00555 if ( $object === null ) 00556 $object = eZContentObject::fetch( $objectID ); 00557 00558 // Register the object in the search engine. 00559 $needCommit = eZSearch::needCommit(); 00560 if ( eZSearch::needRemoveWithUpdate() ) 00561 { 00562 eZDebug::accumulatorStart( 'remove_object', 'search_total', 'remove object' ); 00563 eZSearch::removeObject( $object, $needCommit ); 00564 eZDebug::accumulatorStop( 'remove_object' ); 00565 } 00566 00567 eZDebug::accumulatorStart( 'add_object', 'search_total', 'add object' ); 00568 if ( !eZSearch::addObject( $object, $needCommit ) ) 00569 { 00570 eZDebug::writeError( "Failed adding object ID {$object->attribute( 'id' )} in the search engine", __METHOD__ ); 00571 } 00572 eZDebug::accumulatorStop( 'add_object' ); 00573 } 00574 00575 /*! 00576 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00577 the calls within a db transaction; thus within db->begin and db->commit. 00578 */ 00579 static public function createNotificationEvent( $objectID, $versionNum ) 00580 { 00581 $event = eZNotificationEvent::create( 'ezpublish', array( 'object' => $objectID, 00582 'version' => $versionNum ) ); 00583 $event->store(); 00584 } 00585 00586 /*! 00587 Start global transaction. 00588 00589 \deprecated since version 4.1.0, this method will be removed in future major releases 00590 */ 00591 function beginPublish() 00592 { 00593 $db = eZDB::instance(); 00594 $db->begin(); 00595 } 00596 00597 /*! 00598 Stop (commit) global transaction. 00599 00600 \deprecated since version 4.1.0, this method will be removed in future major releases 00601 */ 00602 function endPublish() 00603 { 00604 $db = eZDB::instance(); 00605 $db->commit(); 00606 } 00607 00608 /*! 00609 Copies missing translations from published version to the draft. 00610 */ 00611 static public function copyTranslations( $objectID, $versionNum ) 00612 { 00613 $object = eZContentObject::fetch( $objectID ); 00614 $publishedVersionNum = $object->attribute( 'current_version' ); 00615 if ( !$publishedVersionNum ) 00616 { 00617 return; 00618 } 00619 $publishedVersion = $object->version( $publishedVersionNum ); 00620 $publishedVersionTranslations = $publishedVersion->translations(); 00621 $publishedLanguages = eZContentLanguage::languagesByMask( $object->attribute( 'language_mask' ) ); 00622 $publishedLanguageCodes = array_keys( $publishedLanguages ); 00623 00624 $version = $object->version( $versionNum ); 00625 $versionTranslationList = $version->translationList( false, false ); 00626 00627 foreach ( $publishedVersionTranslations as $translation ) 00628 { 00629 if ( in_array( $translation->attribute( 'language_code' ), $versionTranslationList ) 00630 || !in_array( $translation->attribute( 'language_code' ), $publishedLanguageCodes ) ) 00631 { 00632 continue; 00633 } 00634 00635 $contentObjectAttributes = $translation->objectAttributes(); 00636 foreach ( $contentObjectAttributes as $attribute ) 00637 { 00638 $clonedAttribute = $attribute->cloneContentObjectAttribute( $versionNum, $publishedVersionNum, $objectID ); 00639 $clonedAttribute->sync(); 00640 } 00641 } 00642 00643 $version->updateLanguageMask(); 00644 } 00645 00646 /*! 00647 Updates non-translatable attributes. 00648 */ 00649 static public function updateNontranslatableAttributes( $objectID, $versionNum ) 00650 { 00651 $object = eZContentObject::fetch( $objectID ); 00652 $version = $object->version( $versionNum ); 00653 00654 $nonTranslatableAttributes = $version->nonTranslatableAttributesToUpdate(); 00655 if ( $nonTranslatableAttributes ) 00656 { 00657 $attributes = $version->contentObjectAttributes( $version->initialLanguageCode() ); 00658 $attributeByClassAttrID = array(); 00659 foreach ( $attributes as $attribute ) 00660 { 00661 $attributeByClassAttrID[$attribute->attribute( 'contentclassattribute_id' )] = $attribute; 00662 } 00663 00664 foreach ( $nonTranslatableAttributes as $attributeToUpdate ) 00665 { 00666 $originalAttribute =& $attributeByClassAttrID[$attributeToUpdate->attribute( 'contentclassattribute_id' )]; 00667 if ( $originalAttribute ) 00668 { 00669 unset( $tmp ); 00670 $tmp = $attributeToUpdate; 00671 $tmp->initialize( $attributeToUpdate->attribute( 'version' ), $originalAttribute ); 00672 $tmp->setAttribute( 'id', $attributeToUpdate->attribute( 'id' ) ); 00673 $tmp->setAttribute( 'language_code', $attributeToUpdate->attribute( 'language_code' ) ); 00674 $tmp->setAttribute( 'language_id', $attributeToUpdate->attribute( 'language_id' ) ); 00675 $tmp->setAttribute( 'attribute_original_id', $originalAttribute->attribute( 'id' ) ); 00676 $tmp->store(); 00677 $tmp->postInitialize( $attributeToUpdate->attribute( 'version' ), $originalAttribute ); 00678 } 00679 } 00680 } 00681 } 00682 00683 static public function removeTemporaryDrafts( $objectID, $versionNum ) 00684 { 00685 $object = eZContentObject::fetch( $objectID ); 00686 $object->cleanupInternalDrafts( eZUser::currentUserID() ); 00687 } 00688 00689 /** 00690 * Moves a node 00691 * 00692 * @param int $nodeID 00693 * @param int $objectID 00694 * @param int $newParentNodeID 00695 * 00696 * @return array An array with operation status, always true 00697 */ 00698 static public function moveNode( $nodeID, $objectID, $newParentNodeID ) 00699 { 00700 if( !eZContentObjectTreeNodeOperations::move( $nodeID, $newParentNodeID ) ) 00701 { 00702 eZDebug::writeError( "Failed to move node $nodeID as child of parent node $newParentNodeID", 00703 __METHOD__ ); 00704 00705 return array( 'status' => false ); 00706 } 00707 00708 eZContentObject::fixReverseRelations( $objectID, 'move' ); 00709 00710 return array( 'status' => true ); 00711 } 00712 00713 /** 00714 * Adds a new nodeAssignment 00715 * 00716 * @param int $nodeID 00717 * @param int $objectId 00718 * @param array $selectedNodeIDArray 00719 * 00720 * @return array An array with operation status, always true 00721 */ 00722 static public function addAssignment( $nodeID, $objectID, $selectedNodeIDArray ) 00723 { 00724 $userClassIDArray = eZUser::contentClassIDs(); 00725 00726 $object = eZContentObject::fetch( $objectID ); 00727 $class = $object->contentClass(); 00728 00729 $nodeAssignmentList = eZNodeAssignment::fetchForObject( $objectID, $object->attribute( 'current_version' ), 0, false ); 00730 $assignedNodes = $object->assignedNodes(); 00731 00732 $parentNodeIDArray = array(); 00733 00734 foreach ( $assignedNodes as $assignedNode ) 00735 { 00736 $append = false; 00737 foreach ( $nodeAssignmentList as $nodeAssignment ) 00738 { 00739 if ( $nodeAssignment['parent_node'] == $assignedNode->attribute( 'parent_node_id' ) ) 00740 { 00741 $append = true; 00742 break; 00743 } 00744 } 00745 if ( $append ) 00746 { 00747 $parentNodeIDArray[] = $assignedNode->attribute( 'parent_node_id' ); 00748 } 00749 } 00750 00751 $db = eZDB::instance(); 00752 $db->begin(); 00753 $locationAdded = false; 00754 $node = eZContentObjectTreeNode::fetch( $nodeID ); 00755 foreach ( $selectedNodeIDArray as $selectedNodeID ) 00756 { 00757 if ( !in_array( $selectedNodeID, $parentNodeIDArray ) ) 00758 { 00759 $parentNode = eZContentObjectTreeNode::fetch( $selectedNodeID ); 00760 $parentNodeObject = $parentNode->attribute( 'object' ); 00761 00762 $canCreate = ( ( $parentNode->checkAccess( 'create', $class->attribute( 'id' ), $parentNodeObject->attribute( 'contentclass_id' ) ) == 1 ) || 00763 ( $parentNode->canAddLocation() && $node->canRead() ) ); 00764 00765 if ( $canCreate ) 00766 { 00767 $insertedNode = $object->addLocation( $selectedNodeID, true ); 00768 00769 // Now set is as published and fix main_node_id 00770 $insertedNode->setAttribute( 'contentobject_is_published', 1 ); 00771 $insertedNode->setAttribute( 'main_node_id', $node->attribute( 'main_node_id' ) ); 00772 $insertedNode->setAttribute( 'contentobject_version', $node->attribute( 'contentobject_version' ) ); 00773 // Make sure the url alias is set updated. 00774 $insertedNode->updateSubTreePath(); 00775 $insertedNode->sync(); 00776 00777 $locationAdded = true; 00778 } 00779 } 00780 } 00781 if ( $locationAdded ) 00782 { 00783 00784 //call appropriate method from search engine 00785 eZSearch::addNodeAssignment( $nodeID, $objectID, $selectedNodeIDArray ); 00786 00787 // clear user policy cache if this was a user object 00788 if ( in_array( $object->attribute( 'contentclass_id' ), $userClassIDArray ) ) 00789 { 00790 eZUser::purgeUserCacheByUserId( $object->attribute( 'id' ) ); 00791 } 00792 00793 00794 } 00795 $db->commit(); 00796 00797 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 00798 00799 return array( 'status' => true ); 00800 } 00801 00802 /** 00803 * Removes a nodeAssignment or a list of nodeAssigments 00804 * 00805 * @deprecated since 4.3 00806 * 00807 * @param int $nodeID 00808 * @param int $objectID 00809 * @param array $removeList 00810 * @param bool $moveToTrash 00811 * 00812 * @return array An array with operation status, always true 00813 */ 00814 static public function removeAssignment( $nodeID, $objectID, $removeList, $moveToTrash ) 00815 { 00816 $mainNodeChanged = false; 00817 $nodeIDList = array(); 00818 $mainNodeID = $nodeID; 00819 $userClassIDArray = eZUser::contentClassIDs(); 00820 $object = eZContentObject::fetch( $objectID ); 00821 $nodeAssignmentIDList = array(); 00822 00823 $db = eZDB::instance(); 00824 $db->begin(); 00825 00826 foreach ( $removeList as $key => $node ) 00827 { 00828 $removeObjectID = $node->attribute( 'contentobject_id' ); 00829 $removeObject = eZContentObject::fetch( $removeObjectID ); 00830 $nodeAssignmentList = eZNodeAssignment::fetchForObject( $removeObjectID, $removeObject->attribute( 'current_version' ), 0, false ); 00831 foreach ( $nodeAssignmentList as $nodeAssignmentKey => $nodeAssignment ) 00832 { 00833 if ( $nodeAssignment['parent_node'] == $node->attribute( 'parent_node_id' ) ) 00834 { 00835 $nodeAssignmentIDList[] = $nodeAssignment['id']; 00836 unset( $nodeAssignmentList[$nodeAssignmentKey] ); 00837 } 00838 } 00839 00840 if ( $node->attribute( 'node_id' ) == $node->attribute( 'main_node_id' ) ) 00841 $mainNodeChanged = true; 00842 $node->removeThis(); 00843 00844 $nodeIDList[] = $node->attribute( 'node_id' ); 00845 } 00846 00847 eZNodeAssignment::purgeByID( array_unique( $nodeAssignmentIDList ) ); 00848 00849 if ( $mainNodeChanged ) 00850 { 00851 $allNodes = $object->assignedNodes(); 00852 $mainNode = $allNodes[0]; 00853 $mainNodeID = $mainNode->attribute( 'node_id' ); 00854 eZContentObjectTreeNode::updateMainNodeID( $mainNodeID, $objectID, false, $mainNode->attribute( 'parent_node_id' ) ); 00855 } 00856 00857 // Give other search engines that the default one a chance to reindex 00858 // when removing locations. 00859 if ( !eZSearch::getEngine() instanceof eZSearchEngine ) 00860 { 00861 eZContentOperationCollection::registerSearchObject( $objectID ); 00862 } 00863 00864 $db->commit(); 00865 00866 00867 //call appropriate method from search engine 00868 eZSearch::removeNodeAssignment( $nodeID, $mainNodeID, $objectID, $nodeIDList ); 00869 00870 eZContentCacheManager::clearObjectViewCacheIfNeeded( $objectID ); 00871 00872 // clear user policy cache if this was a user object 00873 if ( in_array( $object->attribute( 'contentclass_id' ), $userClassIDArray ) ) 00874 { 00875 eZUser::purgeUserCacheByUserId( $object->attribute( 'id' ) ); 00876 } 00877 00878 // we don't clear template block cache here since it's cleared in eZContentObjectTreeNode::removeNode() 00879 00880 return array( 'status' => true ); 00881 } 00882 00883 /** 00884 * Removes nodes 00885 * 00886 * This function does not check about permissions, this is the responsibility of the caller! 00887 * 00888 * @param array $removeNodeIdList Array of Node ID to remove 00889 * 00890 * @return array An array with operation status, always true 00891 */ 00892 static public function removeNodes( array $removeNodeIdList ) 00893 { 00894 $mainNodeChanged = array(); 00895 $nodeAssignmentIdList = array(); 00896 $objectIdList = array(); 00897 00898 $db = eZDB::instance(); 00899 $db->begin(); 00900 00901 foreach ( $removeNodeIdList as $nodeId ) 00902 { 00903 $node = eZContentObjectTreeNode::fetch($nodeId); 00904 $objectId = $node->attribute( 'contentobject_id' ); 00905 foreach ( eZNodeAssignment::fetchForObject( $objectId, 00906 eZContentObject::fetch( $objectId )->attribute( 'current_version' ), 00907 0, false ) as $nodeAssignmentKey => $nodeAssignment ) 00908 { 00909 if ( $nodeAssignment['parent_node'] == $node->attribute( 'parent_node_id' ) ) 00910 { 00911 $nodeAssignmentIdList[$nodeAssignment['id']] = 1; 00912 } 00913 } 00914 00915 if ( $nodeId == $node->attribute( 'main_node_id' ) ) 00916 $mainNodeChanged[$objectId] = 1; 00917 $node->removeThis(); 00918 00919 if ( !isset( $objectIdList[$objectId] ) ) 00920 $objectIdList[$objectId] = eZContentObject::fetch( $objectId ); 00921 } 00922 00923 eZNodeAssignment::purgeByID( array_keys( $nodeAssignmentIdList ) ); 00924 00925 foreach ( array_keys( $mainNodeChanged ) as $objectId ) 00926 { 00927 $allNodes = $objectIdList[$objectId]->assignedNodes(); 00928 // Registering node that will be promoted as 'main' 00929 $mainNodeChanged[$objectId] = $allNodes[0]; 00930 eZContentObjectTreeNode::updateMainNodeID( $allNodes[0]->attribute( 'node_id' ), $objectId, false, $allNodes[0]->attribute( 'parent_node_id' ) ); 00931 } 00932 00933 // Give other search engines that the default one a chance to reindex 00934 // when removing locations. 00935 if ( !eZSearch::getEngine() instanceof eZSearchEngine ) 00936 { 00937 foreach ( array_keys( $objectIdList ) as $objectId ) 00938 eZContentOperationCollection::registerSearchObject( $objectId ); 00939 } 00940 00941 $db->commit(); 00942 00943 //call appropriate method from search engine 00944 eZSearch::removeNodes( $removeNodeIdList ); 00945 00946 $userClassIdList = eZUser::contentClassIDs(); 00947 foreach ( $objectIdList as $objectId => $object ) 00948 { 00949 eZContentCacheManager::clearObjectViewCacheIfNeeded( $objectId ); 00950 00951 // clear user policy cache if this was a user object 00952 if ( in_array( $object->attribute( 'contentclass_id' ), $userClassIdList ) ) 00953 { 00954 eZUser::purgeUserCacheByUserId( $object->attribute( 'id' ) ); 00955 } 00956 } 00957 00958 // we don't clear template block cache here since it's cleared in eZContentObjectTreeNode::removeNode() 00959 00960 return array( 'status' => true ); 00961 } 00962 00963 /** 00964 * Deletes a content object, or a list of content objects 00965 * 00966 * @param array $deleteIDArray 00967 * @param bool $moveToTrash 00968 * 00969 * @return array An array with operation status, always true 00970 */ 00971 static public function deleteObject( $deleteIDArray, $moveToTrash = false ) 00972 { 00973 $ini = eZINI::instance(); 00974 $delayedIndexingValue = $ini->variable( 'SearchSettings', 'DelayedIndexing' ); 00975 if ( $delayedIndexingValue === 'enabled' || $delayedIndexingValue === 'classbased' ) 00976 { 00977 $pendingActionsToDelete = array(); 00978 $classList = $ini->variable( 'SearchSettings', 'DelayedIndexingClassList' ); // Will be used below if DelayedIndexing is classbased 00979 $assignedNodesByObject = array(); 00980 $nodesToDeleteByObject = array(); 00981 $aNodes = eZContentObjectTreeNode::fetch( $deleteIDArray ); 00982 if( !is_array( $aNodes ) ) 00983 $aNodes = array( $aNodes ); 00984 00985 foreach ( $aNodes as $node ) 00986 { 00987 $object = $node->object(); 00988 $objectID = $object->attribute( 'id' ); 00989 $assignedNodes = $object->attribute( 'assigned_nodes' ); 00990 // Only delete pending action if this is the last object's node that is requested for deletion 00991 // But $deleteIDArray can also contain all the object's node (mainly if this method is called programmatically) 00992 // So if this is not the last node, then store its id in a temp array 00993 // This temp array will then be compared to the whole object's assigned nodes array 00994 if ( count( $assignedNodes ) > 1 ) 00995 { 00996 // $assignedNodesByObject will be used as a referent to check if we want to delete all lasting nodes 00997 if ( !isset( $assignedNodesByObject[$objectID] ) ) 00998 { 00999 $assignedNodesByObject[$objectID] = array(); 01000 01001 foreach ( $assignedNodes as $assignedNode ) 01002 { 01003 $assignedNodesByObject[$objectID][] = $assignedNode->attribute( 'node_id' ); 01004 } 01005 } 01006 01007 // Store the node assignment we want to delete 01008 // Then compare the array to the referent node assignment array 01009 $nodesToDeleteByObject[$objectID][] = $node->attribute( 'node_id' ); 01010 $diff = array_diff( $assignedNodesByObject[$objectID], $nodesToDeleteByObject[$objectID] ); 01011 if ( !empty( $diff ) ) // We still have more node assignments for object, pending action is not to be deleted considering this iteration 01012 { 01013 continue; 01014 } 01015 } 01016 01017 if ( $delayedIndexingValue !== 'classbased' || 01018 ( is_array( $classList ) && in_array( $object->attribute( 'class_identifier' ), $classList ) ) ) 01019 { 01020 $pendingActionsToDelete[] = $objectID; 01021 } 01022 } 01023 01024 if ( !empty( $pendingActionsToDelete ) ) 01025 { 01026 $filterConds = array( 'param' => array ( $pendingActionsToDelete ) ); 01027 eZPendingActions::removeByAction( 'index_object', $filterConds ); 01028 } 01029 } 01030 01031 eZContentObjectTreeNode::removeSubtrees( $deleteIDArray, $moveToTrash ); 01032 return array( 'status' => true ); 01033 } 01034 01035 /** 01036 * Changes an contentobject's status 01037 * 01038 * @param int $nodeID 01039 * 01040 * @return array An array with operation status, always true 01041 */ 01042 static public function changeHideStatus( $nodeID ) 01043 { 01044 $action = 'hide'; 01045 01046 $curNode = eZContentObjectTreeNode::fetch( $nodeID ); 01047 if ( is_object( $curNode ) ) 01048 { 01049 if ( $curNode->attribute( 'is_hidden' ) ) 01050 { 01051 eZContentObjectTreeNode::unhideSubTree( $curNode ); 01052 $action = 'show'; 01053 } 01054 else 01055 eZContentObjectTreeNode::hideSubTree( $curNode ); 01056 } 01057 01058 //call appropriate method from search engine 01059 eZSearch::updateNodeVisibility( $nodeID, $action ); 01060 01061 return array( 'status' => true ); 01062 } 01063 01064 /** 01065 * Swap a node with another one 01066 * 01067 * @param int $nodeID 01068 * @param int $selectedNodeID 01069 * @param array $nodeIdList 01070 * 01071 * @return array An array with operation status, always true 01072 */ 01073 static public function swapNode( $nodeID, $selectedNodeID, $nodeIdList = array() ) 01074 { 01075 $userClassIDArray = eZUser::contentClassIDs(); 01076 01077 $node = eZContentObjectTreeNode::fetch( $nodeID ); 01078 $selectedNode = eZContentObjectTreeNode::fetch( $selectedNodeID ); 01079 $object = $node->object(); 01080 $nodeParentNodeID = $node->attribute( 'parent_node_id' ); 01081 $nodeParent = $node->attribute( 'parent' ); 01082 01083 $objectID = $object->attribute( 'id' ); 01084 $objectVersion = $object->attribute( 'current_version' ); 01085 01086 $selectedObject = $selectedNode->object(); 01087 $selectedObjectID = $selectedObject->attribute( 'id' ); 01088 $selectedObjectVersion = $selectedObject->attribute( 'current_version' ); 01089 $selectedNodeParentNodeID = $selectedNode->attribute( 'parent_node_id' ); 01090 $selectedNodeParent = $selectedNode->attribute( 'parent' ); 01091 01092 $db = eZDB::instance(); 01093 $db->begin(); 01094 01095 $node->setAttribute( 'contentobject_id', $selectedObjectID ); 01096 $node->setAttribute( 'contentobject_version', $selectedObjectVersion ); 01097 01098 $selectedNode->setAttribute( 'contentobject_id', $objectID ); 01099 $selectedNode->setAttribute( 'contentobject_version', $objectVersion ); 01100 01101 // fix main node id 01102 if ( $node->isMain() && !$selectedNode->isMain() ) 01103 { 01104 $node->setAttribute( 'main_node_id', $selectedNode->attribute( 'main_node_id' ) ); 01105 $selectedNode->setAttribute( 'main_node_id', $selectedNode->attribute( 'node_id' ) ); 01106 } 01107 else if ( $selectedNode->isMain() && !$node->isMain() ) 01108 { 01109 $selectedNode->setAttribute( 'main_node_id', $node->attribute( 'main_node_id' ) ); 01110 $node->setAttribute( 'main_node_id', $node->attribute( 'node_id' ) ); 01111 } 01112 01113 $node->store(); 01114 $selectedNode->store(); 01115 01116 // clear user policy cache if this was a user object 01117 if ( in_array( $object->attribute( 'contentclass_id' ), $userClassIDArray ) ) 01118 { 01119 eZUser::purgeUserCacheByUserId( $object->attribute( 'id' ) ); 01120 } 01121 01122 if ( in_array( $selectedObject->attribute( 'contentclass_id' ), $userClassIDArray ) ) 01123 { 01124 eZUser::purgeUserCacheByUserId( $selectedObject->attribute( 'id' ) ); 01125 } 01126 01127 // modify path string 01128 $changedOriginalNode = eZContentObjectTreeNode::fetch( $nodeID ); 01129 $changedOriginalNode->updateSubTreePath(); 01130 $changedTargetNode = eZContentObjectTreeNode::fetch( $selectedNodeID ); 01131 $changedTargetNode->updateSubTreePath(); 01132 01133 // modify section 01134 if ( $changedOriginalNode->isMain() ) 01135 { 01136 $changedOriginalObject = $changedOriginalNode->object(); 01137 $parentObject = $nodeParent->object(); 01138 if ( $changedOriginalObject->attribute( 'section_id' ) != $parentObject->attribute( 'section_id' ) ) 01139 { 01140 01141 eZContentObjectTreeNode::assignSectionToSubTree( $changedOriginalNode->attribute( 'main_node_id' ), 01142 $parentObject->attribute( 'section_id' ), 01143 $changedOriginalObject->attribute( 'section_id' ) ); 01144 } 01145 } 01146 if ( $changedTargetNode->isMain() ) 01147 { 01148 $changedTargetObject = $changedTargetNode->object(); 01149 $selectedParentObject = $selectedNodeParent->object(); 01150 if ( $changedTargetObject->attribute( 'section_id' ) != $selectedParentObject->attribute( 'section_id' ) ) 01151 { 01152 01153 eZContentObjectTreeNode::assignSectionToSubTree( $changedTargetNode->attribute( 'main_node_id' ), 01154 $selectedParentObject->attribute( 'section_id' ), 01155 $changedTargetObject->attribute( 'section_id' ) ); 01156 } 01157 } 01158 01159 eZContentObject::fixReverseRelations( $objectID, 'swap' ); 01160 eZContentObject::fixReverseRelations( $selectedObjectID, 'swap' ); 01161 01162 $db->commit(); 01163 01164 // clear cache for new placement. 01165 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01166 01167 eZSearch::swapNode( $nodeID, $selectedNodeID, $nodeIdList = array() ); 01168 01169 return array( 'status' => true ); 01170 } 01171 01172 /** 01173 * Assigns a node to a section 01174 * 01175 * @param int $nodeID 01176 * @param int $selectedSectionID 01177 * 01178 * @return array An array with operation status, always true 01179 */ 01180 static public function updateSection( $nodeID, $selectedSectionID ) 01181 { 01182 eZContentObjectTreeNode::assignSectionToSubTree( $nodeID, $selectedSectionID ); 01183 } 01184 01185 /** 01186 * Changes the status of a translation 01187 * 01188 * @param int $objectID 01189 * @param int $status 01190 * 01191 * @return array An array with operation status, always true 01192 */ 01193 static public function changeTranslationAvailableStatus( $objectID, $status = false ) 01194 { 01195 $object = eZContentObject::fetch( $objectID ); 01196 if ( !$object->canEdit() ) 01197 { 01198 return array( 'status' => false ); 01199 } 01200 if ( $object->isAlwaysAvailable() & $status == false ) 01201 { 01202 $object->setAlwaysAvailableLanguageID( false ); 01203 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01204 } 01205 else if ( !$object->isAlwaysAvailable() & $status == true ) 01206 { 01207 $object->setAlwaysAvailableLanguageID( $object->attribute( 'initial_language_id' ) ); 01208 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01209 } 01210 return array( 'status' => true ); 01211 } 01212 01213 /** 01214 * Changes the sort order for a node 01215 * 01216 * @param int $nodeID 01217 * @param string $sortingField 01218 * @param bool $sortingOrder 01219 * 01220 * @return array An array with operation status, always true 01221 */ 01222 static public function changeSortOrder( $nodeID, $sortingField, $sortingOrder = false ) 01223 { 01224 $curNode = eZContentObjectTreeNode::fetch( $nodeID ); 01225 if ( is_object( $curNode ) ) 01226 { 01227 $db = eZDB::instance(); 01228 $db->begin(); 01229 $curNode->setAttribute( 'sort_field', $sortingField ); 01230 $curNode->setAttribute( 'sort_order', $sortingOrder ); 01231 $curNode->store(); 01232 $db->commit(); 01233 $object = $curNode->object(); 01234 eZContentCacheManager::clearContentCache( $object->attribute( 'id' ) ); 01235 } 01236 return array( 'status' => true ); 01237 } 01238 01239 /** 01240 * Updates the priority of a node 01241 * 01242 * @param int $parentNodeID 01243 * @param array $priorityArray 01244 * @param array $priorityArray 01245 * 01246 * @return array An array with operation status, always true 01247 */ 01248 static public function updatePriority( $parentNodeID, $priorityArray = array(), $priorityIDArray = array() ) 01249 { 01250 $curNode = eZContentObjectTreeNode::fetch( $parentNodeID ); 01251 if ( $curNode instanceof eZContentObjectTreeNode ) 01252 { 01253 $db = eZDB::instance(); 01254 $db->begin(); 01255 for ( $i = 0, $l = count( $priorityArray ); $i < $l; $i++ ) 01256 { 01257 $priority = (int) $priorityArray[$i]; 01258 $nodeID = (int) $priorityIDArray[$i]; 01259 $db->query( "UPDATE 01260 ezcontentobject_tree 01261 SET 01262 priority={$priority} 01263 WHERE 01264 node_id={$nodeID} AND parent_node_id={$parentNodeID}" ); 01265 } 01266 $curNode->updateAndStoreModified(); 01267 $db->commit(); 01268 } 01269 return array( 'status' => true ); 01270 } 01271 01272 /** 01273 * Update a node's main assignment 01274 * 01275 * @param int $mainAssignmentID 01276 * @param int $objectID 01277 * @param int $mainAssignmentParentID 01278 * 01279 * @return array An array with operation status, always true 01280 */ 01281 static public function updateMainAssignment( $mainAssignmentID, $ObjectID, $mainAssignmentParentID ) 01282 { 01283 eZContentObjectTreeNode::updateMainNodeID( $mainAssignmentID, $ObjectID, false, $mainAssignmentParentID ); 01284 eZContentCacheManager::clearContentCacheIfNeeded( $ObjectID ); 01285 return array( 'status' => true ); 01286 } 01287 01288 /** 01289 * Updates an contentobject's initial language 01290 * 01291 * @param int $objectID 01292 * @param int $newInitialLanguageID 01293 * 01294 * @return array An array with operation status, always true 01295 */ 01296 static public function updateInitialLanguage( $objectID, $newInitialLanguageID ) 01297 { 01298 $object = eZContentObject::fetch( $objectID ); 01299 $language = eZContentLanguage::fetch( $newInitialLanguageID ); 01300 if ( $language and !$language->attribute( 'disabled' ) ) 01301 { 01302 $object->setAttribute( 'initial_language_id', $newInitialLanguageID ); 01303 $objectName = $object->name( false, $language->attribute( 'locale' ) ); 01304 $object->setAttribute( 'name', $objectName ); 01305 $object->store(); 01306 01307 if ( $object->isAlwaysAvailable() ) 01308 { 01309 $object->setAlwaysAvailableLanguageID( $newInitialLanguageID ); 01310 } 01311 01312 $nodes = $object->assignedNodes(); 01313 foreach ( $nodes as $node ) 01314 { 01315 $node->updateSubTreePath(); 01316 } 01317 } 01318 01319 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01320 01321 return array( 'status' => true ); 01322 } 01323 01324 /** 01325 * Set the always available flag for a content object 01326 * 01327 * @param int $objectID 01328 * @param int $newAlwaysAvailable 01329 * @return array An array with operation status, always true 01330 */ 01331 static public function updateAlwaysAvailable( $objectID, $newAlwaysAvailable ) 01332 { 01333 $object = eZContentObject::fetch( $objectID ); 01334 01335 if ( $object->isAlwaysAvailable() & $newAlwaysAvailable == false ) 01336 { 01337 $object->setAlwaysAvailableLanguageID( false ); 01338 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01339 } 01340 else if ( !$object->isAlwaysAvailable() & $newAlwaysAvailable == true ) 01341 { 01342 $object->setAlwaysAvailableLanguageID( $object->attribute( 'initial_language_id' ) ); 01343 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01344 } 01345 01346 return array( 'status' => true ); 01347 } 01348 01349 /** 01350 * Removes a translation for a contentobject 01351 * 01352 * @param int $objectID 01353 * @param array 01354 * @return array An array with operation status, always true 01355 */ 01356 static public function removeTranslation( $objectID, $languageIDArray ) 01357 { 01358 $object = eZContentObject::fetch( $objectID ); 01359 01360 foreach( $languageIDArray as $languageID ) 01361 { 01362 if ( !$object->removeTranslation( $languageID ) ) 01363 { 01364 eZDebug::writeError( "Object with id $objectID: cannot remove the translation with language id $languageID!", 01365 __METHOD__ ); 01366 } 01367 } 01368 01369 eZContentOperationCollection::registerSearchObject( $objectID ); 01370 01371 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01372 01373 return array( 'status' => true ); 01374 } 01375 01376 /** 01377 * Update a contentobject's state 01378 * 01379 * @param int $objectID 01380 * @param int $selectedStateIDList 01381 * 01382 * @return array An array with operation status, always true 01383 */ 01384 static public function updateObjectState( $objectID, $selectedStateIDList ) 01385 { 01386 $object = eZContentObject::fetch( $objectID ); 01387 01388 // we don't need to re-assign states the object currently already has assigned 01389 $currentStateIDArray = $object->attribute( 'state_id_array' ); 01390 $selectedStateIDList = array_diff( $selectedStateIDList, $currentStateIDArray ); 01391 01392 // filter out any states the current user is not allowed to assign 01393 $canAssignStateIDList = $object->attribute( 'allowed_assign_state_id_list' ); 01394 $selectedStateIDList = array_intersect( $selectedStateIDList, $canAssignStateIDList ); 01395 01396 foreach ( $selectedStateIDList as $selectedStateID ) 01397 { 01398 $state = eZContentObjectState::fetchById( $selectedStateID ); 01399 $object->assignState( $state ); 01400 } 01401 //call appropriate method from search engine 01402 eZSearch::updateObjectState($objectID, $selectedStateIDList); 01403 01404 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01405 01406 return array( 'status' => true ); 01407 } 01408 01409 /** 01410 * Executes the pre-publish trigger for this object, and handles 01411 * specific return statuses from the workflow 01412 * 01413 * @param int $objectID Object ID 01414 * @param int $version Version number 01415 * 01416 * @since 4.2 01417 */ 01418 static public function executePrePublishTrigger( $objectID, $version ) 01419 { 01420 01421 } 01422 01423 /** 01424 * Creates a RSS/ATOM Feed export for a node 01425 * 01426 * @param int $nodeID Node ID 01427 * 01428 * @since 4.3 01429 */ 01430 static public function createFeedForNode( $nodeID ) 01431 { 01432 $hasExport = eZRSSFunctionCollection::hasExportByNode( $nodeID ); 01433 if ( isset( $hasExport['result'] ) && $hasExport['result'] ) 01434 { 01435 eZDebug::writeError( 'There is already a rss/atom export feed for this node: ' . $nodeID, __METHOD__ ); 01436 return array( 'status' => false ); 01437 } 01438 01439 $node = eZContentObjectTreeNode::fetch( $nodeID ); 01440 $currentClassIdentifier = $node->attribute( 'class_identifier' ); 01441 01442 $config = eZINI::instance( 'site.ini' ); 01443 $feedItemClasses = $config->variable( 'RSSSettings', 'DefaultFeedItemClasses' ); 01444 01445 if ( !$feedItemClasses || !isset( $feedItemClasses[ $currentClassIdentifier ] ) ) 01446 { 01447 eZDebug::writeError( "EnableRSS: content class $currentClassIdentifier is not defined in site.ini[RSSSettings]DefaultFeedItemClasses[<class_id>].", __METHOD__ ); 01448 return array( 'status' => false ); 01449 } 01450 01451 $object = $node->object(); 01452 $objectID = $object->attribute('id'); 01453 $currentUserID = eZUser::currentUserID(); 01454 $rssExportItems = array(); 01455 01456 $db = eZDB::instance(); 01457 $db->begin(); 01458 01459 $rssExport = eZRSSExport::create( $currentUserID ); 01460 $rssExport->setAttribute( 'access_url', 'rss_feed_' . $nodeID ); 01461 $rssExport->setAttribute( 'node_id', $nodeID ); 01462 $rssExport->setAttribute( 'main_node_only', '1' ); 01463 $rssExport->setAttribute( 'number_of_objects', $config->variable( 'RSSSettings', 'NumberOfObjectsDefault' ) ); 01464 $rssExport->setAttribute( 'rss_version', $config->variable( 'RSSSettings', 'DefaultVersion' ) ); 01465 $rssExport->setAttribute( 'status', eZRSSExport::STATUS_VALID ); 01466 $rssExport->setAttribute( 'title', $object->name() ); 01467 $rssExport->store(); 01468 01469 $rssExportID = $rssExport->attribute( 'id' ); 01470 01471 foreach( explode( ';', $feedItemClasses[$currentClassIdentifier] ) as $classIdentifier ) 01472 { 01473 $iniSection = 'RSSSettings_' . $classIdentifier; 01474 if ( $config->hasVariable( $iniSection, 'FeedObjectAttributeMap' ) ) 01475 { 01476 $feedObjectAttributeMap = $config->variable( $iniSection, 'FeedObjectAttributeMap' ); 01477 $subNodesMap = $config->hasVariable( $iniSection, 'Subnodes' ) ? $config->variable( $iniSection, 'Subnodes' ) : array(); 01478 01479 $rssExportItem = eZRSSExportItem::create( $rssExportID ); 01480 $rssExportItem->setAttribute( 'class_id', eZContentObjectTreeNode::classIDByIdentifier( $classIdentifier ) ); 01481 $rssExportItem->setAttribute( 'title', $feedObjectAttributeMap['title'] ); 01482 if ( isset( $feedObjectAttributeMap['description'] ) ) 01483 $rssExportItem->setAttribute( 'description', $feedObjectAttributeMap['description'] ); 01484 01485 if ( isset( $feedObjectAttributeMap['category'] ) ) 01486 $rssExportItem->setAttribute( 'category', $feedObjectAttributeMap['category'] ); 01487 01488 if ( isset( $feedObjectAttributeMap['enclosure'] ) ) 01489 $rssExportItem->setAttribute( 'enclosure', $feedObjectAttributeMap['enclosure'] ); 01490 01491 $rssExportItem->setAttribute( 'source_node_id', $nodeID ); 01492 $rssExportItem->setAttribute( 'status', eZRSSExport::STATUS_VALID ); 01493 $rssExportItem->setAttribute( 'subnodes', isset( $subNodesMap[$currentClassIdentifier] ) && $subNodesMap[$currentClassIdentifier] === 'true' ); 01494 $rssExportItem->store(); 01495 } 01496 else 01497 { 01498 eZDebug::writeError( "site.ini[$iniSection]Source[] setting is not defined.", __METHOD__ ); 01499 } 01500 } 01501 01502 $db->commit(); 01503 01504 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01505 01506 return array( 'status' => true ); 01507 } 01508 01509 /** 01510 * Removes a RSS/ATOM Feed export for a node 01511 * 01512 * @param int $nodeID Node ID 01513 * 01514 * @since 4.3 01515 */ 01516 static public function removeFeedForNode( $nodeID ) 01517 { 01518 $rssExport = eZPersistentObject::fetchObject( eZRSSExport::definition(), 01519 null, 01520 array( 'node_id' => $nodeID, 01521 'status' => eZRSSExport::STATUS_VALID ), 01522 true ); 01523 if ( !$rssExport instanceof eZRSSExport ) 01524 { 01525 eZDebug::writeError( 'DisableRSS: There is no rss/atom feeds left to delete for this node: '. $nodeID, __METHOD__ ); 01526 return array( 'status' => false ); 01527 } 01528 01529 $node = eZContentObjectTreeNode::fetch( $nodeID ); 01530 if ( !$node instanceof eZContentObjectTreeNode ) 01531 { 01532 eZDebug::writeError( 'DisableRSS: Could not fetch node: '. $nodeID, __METHOD__ ); 01533 return array( 'status' => false ); 01534 } 01535 01536 $objectID = $node->attribute('contentobject_id'); 01537 $rssExport->removeThis(); 01538 01539 eZContentCacheManager::clearContentCacheIfNeeded( $objectID ); 01540 01541 return array( 'status' => true ); 01542 } 01543 01544 /** 01545 * Sends the published object/version for publishing to the queue 01546 * Used by the content/publish operation 01547 * @param int $objectId 01548 * @param int $version 01549 * 01550 * @return array( status => int ) 01551 * @since 4.5 01552 */ 01553 public static function sendToPublishingQueue( $objectId, $version ) 01554 { 01555 $behaviour = ezpContentPublishingBehaviour::getBehaviour(); 01556 if ( $behaviour->disableAsynchronousPublishing ) 01557 $asyncEnabled = false; 01558 else 01559 $asyncEnabled = ( eZINI::instance( 'content.ini' )->variable( 'PublishingSettings', 'AsynchronousPublishing' ) == 'enabled' ); 01560 01561 $accepted = true; 01562 01563 if ( $asyncEnabled === true ) 01564 { 01565 // Filter handlers 01566 $ini = eZINI::instance( 'content.ini' ); 01567 $filterHandlerClasses = $ini->variable( 'PublishingSettings', 'AsynchronousPublishingFilters' ); 01568 01569 if ( count( $filterHandlerClasses ) ) 01570 { 01571 $versionObject = eZContentObjectVersion::fetchVersion( $version, $objectId ); 01572 foreach( $filterHandlerClasses as $filterHandlerClass ) 01573 { 01574 if ( !class_exists( $filterHandlerClass ) ) 01575 { 01576 eZDebug::writeError( "Unknown asynchronous publishing filter handler class '$filterHandlerClass'", __METHOD__ ); 01577 continue; 01578 } 01579 01580 $handler = new $filterHandlerClass( $versionObject ); 01581 if ( !( $handler instanceof ezpAsynchronousPublishingFilterInterface ) ) 01582 { 01583 eZDebug::writeError( "Asynchronous publishing filter handler class '$filterHandlerClass' does not implement ezpAsynchronousPublishingFilterInterface", __METHOD__ ); 01584 continue; 01585 } 01586 01587 $accepted = $handler->accept(); 01588 01589 if ( !$accepted ) 01590 { 01591 eZDebugSetting::writeDebug( "Object #{$objectId}/{$version} was excluded from asynchronous publishing by $filterHandlerClass", __METHOD__ ); 01592 break; 01593 } 01594 } 01595 } 01596 unset( $filterHandlerClasses, $handler ); 01597 } 01598 01599 if ( $asyncEnabled && $accepted ) 01600 { 01601 // if the object is already in the process queue, we move ahead 01602 // this test should NOT be necessary since http://issues.ez.no/17840 was fixed 01603 if ( ezpContentPublishingQueue::isQueued( $objectId, $version ) ) 01604 { 01605 return array( 'status' => eZModuleOperationInfo::STATUS_CONTINUE ); 01606 } 01607 // the object isn't in the process queue, this means this is the first time we execute this method 01608 // the object must be queued 01609 else 01610 { 01611 ezpContentPublishingQueue::add( $objectId, $version ); 01612 return array( 'status' => eZModuleOperationInfo::STATUS_HALTED, 'redirect_url' => "content/queued/{$objectId}/{$version}" ); 01613 } 01614 } 01615 else 01616 { 01617 return array( 'status' => eZModuleOperationInfo::STATUS_CONTINUE ); 01618 } 01619 } 01620 } 01621 ?>