eZ Publish  [trunk]
ezcontentoperationcollection.php
Go to the documentation of this file.
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 ?>