eZ Publish  [trunk]
ezcontentobjectversion.php
Go to the documentation of this file.
00001 <?php
00002 /**
00003  * File containing the eZContentObjectVersion 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 eZContentObjectVersion ezcontentobjectversion.php
00013   \brief The class eZContentObjectVersion handles different versions of an content object
00014   \ingroup eZKernel
00015 
00016 */
00017 
00018 class eZContentObjectVersion extends eZPersistentObject
00019 {
00020     const STATUS_DRAFT = 0;
00021     const STATUS_PUBLISHED = 1;
00022     const STATUS_PENDING = 2;
00023     const STATUS_ARCHIVED = 3;
00024     const STATUS_REJECTED = 4;
00025     const STATUS_INTERNAL_DRAFT = 5;
00026     // used when a workflow event returns FETCH_TEMPLATE_REPEAT to allow editing again
00027     const STATUS_REPEAT = 6;
00028     const STATUS_QUEUED = 7;
00029 
00030     function eZContentObjectVersion( $row=array() )
00031     {
00032         $this->ContentObjectAttributeArray = false;
00033         $this->DataMap = false;
00034         $this->TempNode = null;
00035         $this->VersionName = null;
00036         $this->VersionNameCache = array();
00037         $this->eZPersistentObject( $row );
00038     }
00039 
00040     static function definition()
00041     {
00042         static $definition = array( "fields" => array( 'id' =>  array( 'name' => 'ID',
00043                                                          'datatype' => 'integer',
00044                                                          'default' => 0,
00045                                                          'required' => true ),
00046                                          'contentobject_id' =>  array( 'name' => 'ContentObjectID',
00047                                                                        'datatype' => 'integer',
00048                                                                        'default' => 0,
00049                                                                        'required' => true,
00050                                                                        'foreign_class' => 'eZContentObject',
00051                                                                        'foreign_attribute' => 'id',
00052                                                                        'multiplicity' => '1..*' ),
00053                                          'creator_id' =>  array( 'name' => 'CreatorID',
00054                                                                  'datatype' => 'integer',
00055                                                                  'default' => 0,
00056                                                                  'required' => true,
00057                                                                  'foreign_class' => 'eZUser',
00058                                                                  'foreign_attribute' => 'id',
00059                                                                  'multiplicity' => '1..*' ),
00060                                          'version' =>  array( 'name' => 'Version',
00061                                                               'datatype' => 'integer',
00062                                                               'default' => 0,
00063                                                               'required' => true ),
00064                                          'status' =>  array( 'name' => 'Status',
00065                                                              'datatype' => 'integer',
00066                                                              'default' => 0,
00067                                                              'required' => true ),
00068                                          'created' =>  array( 'name' => 'Created',
00069                                                               'datatype' => 'integer',
00070                                                               'default' => 0,
00071                                                               'required' => true ),
00072                                          'modified' =>  array( 'name' => 'Modified',
00073                                                                'datatype' => 'integer',
00074                                                                'default' => 0,
00075                                                                'required' => true ),
00076                                          'workflow_event_pos' =>  array( 'name' => 'WorkflowEventPos',
00077                                                                          'datatype' => 'integer',
00078                                                                          'default' => 0,
00079                                                                          'required' => true ),
00080                                          'user_id' =>  array( 'name' => 'UserID',
00081                                                               'datatype' => 'integer',
00082                                                               'default' => 0,
00083                                                               'required' => true,
00084                                                               'foreign_class' => 'eZUser',
00085                                                               'foreign_attribute' => 'contentobject_id',
00086                                                               'multiplicity' => '1..*' ),
00087                                          'language_mask' => array( 'name' => 'LanguageMask',
00088                                                                    'datatype' => 'integer',
00089                                                                    'default' => 0,
00090                                                                    'required' => true ),
00091                                          'initial_language_id' => array( 'name' => 'InitialLanguageID',
00092                                                                          'datatype' => 'integer',
00093                                                                          'default' => 0,
00094                                                                          'required' => true,
00095                                                                          'foreign_class' => 'eZContentLanguage',
00096                                                                          'foreign_attribute' => 'id',
00097                                                                          'multiplicity' => '1..*' ) ),
00098                       'keys' => array( 'id' ),
00099                       'function_attributes' => array( // 'data' => 'fetchData',
00100                                                       'creator' => 'creator',
00101                                                       "name" => "name",
00102                                                       "version_name" => "versionName",
00103                                                       'main_parent_node_id' => 'mainParentNodeID',
00104                                                       "contentobject_attributes" => "contentObjectAttributes",
00105                                                       "related_contentobject_array" => "relatedContentObjectArray",
00106                                                       'reverse_related_object_list' => "reverseRelatedObjectList",
00107                                                       'parent_nodes' => 'parentNodes',
00108                                                       "can_read" => "canVersionRead",
00109                                                       'can_remove' => 'canVersionRemove',
00110                                                       "data_map" => "dataMap",
00111                                                       'node_assignments' => 'nodeAssignments',
00112                                                       'contentobject' => 'contentObject',
00113                                                       'initial_language' => 'initialLanguage',
00114                                                       'language_list' => 'translations',
00115                                                       'translation' => 'translation',
00116                                                       'translation_list' => 'defaultTranslationList',
00117                                                       'complete_translation_list' => 'translationList',
00118                                                       'temp_main_node' => 'tempMainNode' ),
00119                       'class_name' => "eZContentObjectVersion",
00120                       "increment_key" => "id",
00121                       'sort' => array( 'version' => 'asc' ),
00122                       'name' => 'ezcontentobject_version' );
00123         return $definition;
00124     }
00125 
00126     static function statusList( $limit = false )
00127     {
00128         if ( $limit == 'remove' )
00129         {
00130             $versions = array( array( 'name' => 'Draft', 'id' =>  eZContentObjectVersion::STATUS_DRAFT ),
00131                                array( 'name' => 'Pending', 'id' =>  eZContentObjectVersion::STATUS_PENDING ),
00132                                array( 'name' => 'Archived', 'id' =>  eZContentObjectVersion::STATUS_ARCHIVED ),
00133                                array( 'name' => 'Rejected', 'id' =>  eZContentObjectVersion::STATUS_REJECTED ) );
00134         }
00135         else
00136         {
00137             $versions = array( array( 'name' => 'Draft', 'id' =>  eZContentObjectVersion::STATUS_DRAFT ),
00138                                array( 'name' => 'Published', 'id' =>  eZContentObjectVersion::STATUS_PUBLISHED ),
00139                                array( 'name' => 'Pending', 'id' =>  eZContentObjectVersion::STATUS_PENDING ),
00140                                array( 'name' => 'Archived', 'id' =>  eZContentObjectVersion::STATUS_ARCHIVED ),
00141                                array( 'name' => 'Rejected', 'id' =>  eZContentObjectVersion::STATUS_REJECTED ) );
00142         }
00143         return $versions;
00144     }
00145     /*!
00146      \return true if the requested attribute exists in object.
00147     */
00148 
00149     static function fetch( $id, $asObject = true )
00150     {
00151         return eZPersistentObject::fetchObject( eZContentObjectVersion::definition(),
00152                                                 null,
00153                                                 array( 'id' => $id ),
00154                                                 $asObject );
00155     }
00156 
00157     static function fetchVersion( $version, $contentObjectID, $asObject = true )
00158     {
00159         $ret = eZPersistentObject::fetchObjectList( eZContentObjectVersion::definition(),
00160                                                     null, array( "version" => $version,
00161                                                                  "contentobject_id" => $contentObjectID
00162                                                                  ),
00163                                                     null, null,
00164                                                     $asObject );
00165         return isset( $ret[0] ) ? $ret[0] : false;
00166     }
00167 
00168     static function fetchUserDraft( $objectID, $userID )
00169     {
00170         $versions = eZPersistentObject::fetchObjectList( eZContentObjectVersion::definition(),
00171                                                           null, array( 'creator_id' => $userID,
00172                                                                        'contentobject_id' => $objectID,
00173                                                                        'status' => array( array( eZContentObjectVersion::STATUS_DRAFT, eZContentObjectVersion::STATUS_INTERNAL_DRAFT ) ) ),
00174                                                           array( 'version' => 'asc' ), null,
00175                                                           true );
00176         if ( $versions === null or
00177              count( $versions ) == 0 )
00178             return null;
00179         return $versions[0];
00180     }
00181 
00182     /**
00183      * Fetch the latest draft by user id
00184      *
00185      * @since 4.7
00186      * @param int $objectID
00187      * @param int $userID
00188      * @param int $languageID
00189      * @param int $modified
00190      * @return eZContentObjectVersion|null
00191      */
00192     public static function fetchLatestUserDraft( $objectID, $userID, $languageID, $modified = 0 )
00193     {
00194         $versions = eZPersistentObject::fetchObjectList(
00195             eZContentObjectVersion::definition(),
00196             null,
00197             array(
00198                 'creator_id' => $userID,
00199                 'contentobject_id' => $objectID,
00200                 'initial_language_id' => $languageID,
00201                 'modified' => array( '>', $modified ),
00202                 'status' => array(
00203                     array(
00204                         eZContentObjectVersion::STATUS_DRAFT,
00205                         eZContentObjectVersion::STATUS_INTERNAL_DRAFT
00206                     )
00207                 )
00208             ),
00209             array( 'modified' => 'desc' ),
00210             array( 'offset' => 0, 'length' => 1 ),
00211             true
00212         );
00213 
00214         if ( empty( $versions ) )
00215             return null;
00216         return $versions[0];
00217     }
00218 
00219     static function fetchForUser( $userID, $status = eZContentObjectVersion::STATUS_DRAFT )
00220     {
00221         return eZPersistentObject::fetchObjectList( eZContentObjectVersion::definition(),
00222                                                     null, array( 'creator_id' => $userID,
00223                                                                  'status' => $status
00224                                                                  ),
00225                                                     null, null,
00226                                                     true );
00227     }
00228 
00229     static function fetchFiltered( $filters, $offset, $limit )
00230     {
00231         $limits = null;
00232         if ( $offset or $limit )
00233             $limits = array( 'offset' => $offset,
00234                              'length' => $limit );
00235         return eZPersistentObject::fetchObjectList( eZContentObjectVersion::definition(),
00236                                                     null, $filters,
00237                                                     null, $limits,
00238                                                     true );
00239     }
00240 
00241     /*!
00242      \return an eZContentObjectTreeNode object which doesn't really exist in the DB,
00243              this can be passed to a node view template.
00244     */
00245     function tempMainNode()
00246     {
00247         if ( $this->TempNode !== null )
00248             return $this->TempNode;
00249         $object = $this->contentObject();
00250         if ( $object->attribute( 'status' ) == eZContentObject::STATUS_DRAFT )
00251         {
00252             $nodeAssignments = $this->nodeAssignments();
00253             $mainNodeAssignment = null;
00254             foreach( $nodeAssignments as $nodeAssignment )
00255             {
00256                 if ( $nodeAssignment->attribute( 'is_main' ) )
00257                 {
00258                     $mainNodeAssignment = $nodeAssignment;
00259                     break;
00260                 }
00261             }
00262             if ( $mainNodeAssignment === null and
00263                  count( $nodeAssignments ) > 0 )
00264             {
00265                 $mainNodeAssignment = $nodeAssignments[0];
00266             }
00267             if ( $mainNodeAssignment )
00268             {
00269                 $this->TempNode = $mainNodeAssignment->tempNode();
00270             }
00271         }
00272         else if ( $object->attribute( 'status' ) == eZContentObject::STATUS_PUBLISHED )
00273         {
00274             $mainNode = $object->mainNode();
00275             if ( is_object( $mainNode ) )
00276             {
00277                 $this->TempNode = eZContentObjectTreeNode::create( $mainNode->attribute( 'parent_node_id' ),
00278                                                                    $mainNode->attribute( 'contentobject_id' ),
00279                                                                    $this->attribute( 'version' ),
00280                                                                    $mainNode->attribute( 'sort_field' ),
00281                                                                    $mainNode->attribute( 'sort_order' ) );
00282                 $this->TempNode->setName( $mainNode->Name );
00283             }
00284         }
00285         return $this->TempNode;
00286     }
00287 
00288     /*!
00289      \return the name of the current version, optionally in the specific language \a $lang
00290     */
00291     function name( $lang = false )
00292     {
00293         if ( $this->VersionName !== null )
00294             return $this->VersionName;
00295         $this->VersionName = $this->attribute( 'contentobject' )->versionLanguageName( $this->attribute( 'version' ),
00296                                                                                        $lang );
00297         if ( $lang !== false )
00298         {
00299             $contentObject = $this->contentObject();
00300             if ( $contentObject )
00301             {
00302                 return $contentObject->name( false, $lang );
00303             }
00304         }
00305         if ( $this->VersionName === false )
00306         {
00307             $contentObject = $this->contentObject();
00308             if ( $contentObject )
00309             {
00310                 $this->VersionName = $contentObject->name( false, $lang );
00311             }
00312         }
00313         return $this->VersionName;
00314     }
00315 
00316     /*!
00317      \return the name of the current version, optionally in the specific language \a $lang
00318     */
00319     function versionName( $lang = false )
00320     {
00321         if ( !$lang )
00322         {
00323             $lang = $this->initialLanguageCode();
00324         }
00325 
00326         if ( isset( $this->VersionNameCache[$lang] ) )
00327             return $this->VersionNameCache[$lang];
00328 
00329         $object = $this->attribute( 'contentobject' );
00330         if ( !$object )
00331         {
00332             $retValue = false;
00333             return $retValue;
00334         }
00335 
00336         $class = $object->attribute( 'content_class' );
00337         if ( !$class )
00338         {
00339             $retValue = false;
00340             return $retValue;
00341         }
00342 
00343         $this->VersionNameCache[$lang] = $class->contentObjectName( $object,
00344                                                                     $this->attribute( 'version' ),
00345                                                                     $lang );
00346         return $this->VersionNameCache[$lang];
00347     }
00348 
00349     /*!
00350      \return \c true if the current user can read this version of the object.
00351     */
00352     function canVersionRead( )
00353     {
00354         if ( !isset( $this->Permissions["can_versionread"] ) )
00355         {
00356             $this->Permissions["can_versionread"] = $this->checkAccess( 'versionread' );
00357         }
00358         return ( $this->Permissions["can_versionread"] == 1 );
00359     }
00360 
00361     /*!
00362      \return \c true if the current user can remove this version of the object.
00363     */
00364     function canVersionRemove( )
00365     {
00366         if ( !isset( $this->Permissions['can_versionremove'] ) )
00367         {
00368             $this->Permissions['can_versionremove'] = $this->checkAccess( 'versionremove' );
00369         }
00370         return ( $this->Permissions['can_versionremove'] == 1 );
00371     }
00372 
00373     function checkAccess( $functionName, $originalClassID = false, $parentClassID = false, $returnAccessList = false, $language = false )
00374     {
00375         $classID = $originalClassID;
00376         $user = eZUser::currentUser();
00377         $userID = $user->attribute( 'contentobject_id' );
00378         $accessResult =  $user->hasAccessTo( 'content' , $functionName );
00379         $accessWord = $accessResult['accessWord'];
00380         $object = $this->attribute( 'contentobject' );
00381         $objectClassID = $object->attribute( 'contentclass_id' );
00382         if ( ! $classID )
00383         {
00384             $classID = $objectClassID;
00385         }
00386 
00387         // Fetch the ID of the language if we get a string with a language code
00388         // e.g. 'eng-GB'
00389         $originalLanguage = $language;
00390         if ( is_string( $language ) && strlen( $language ) > 0 )
00391         {
00392             $language = eZContentLanguage::idByLocale( $language );
00393         }
00394         else
00395         {
00396             $language = false;
00397         }
00398 
00399         // This will be filled in with the available languages of the object
00400         // if a Language check is performed.
00401         $languageList = false;
00402 
00403         // 'create' is not allowed on versions
00404         if ( $functionName == 'create' )
00405         {
00406             return false;
00407         }
00408 
00409         if ( $functionName == 'edit' )
00410         {
00411             // Extra checking for status and ownership
00412             if ( !in_array( $this->attribute( 'status' ),
00413                             array( eZContentObjectVersion::STATUS_DRAFT,
00414                                    eZContentObjectVersion::STATUS_INTERNAL_DRAFT,
00415                                    eZContentObjectVersion::STATUS_PENDING ) ) ||
00416                  $this->attribute( 'creator_id' ) != $userID )
00417             {
00418                 return false;
00419             }
00420             return true;
00421         }
00422 
00423         if ( $functionName == 'versionremove' and $this->attribute( 'status' ) == eZContentObjectVersion::STATUS_PUBLISHED )
00424         {
00425             return 0;
00426         }
00427 
00428         if ( $accessWord == 'yes' )
00429         {
00430             return 1;
00431         }
00432         elseif ( $accessWord == 'no' )
00433         {
00434             if ( $functionName == 'edit' )
00435             {
00436                 // Check if we have 'create' access under the main parent
00437                 if ( $object && $object->attribute( 'current_version' ) == 1 && !$object->attribute( 'status' ) )
00438                 {
00439                     $mainNode = eZNodeAssignment::fetchForObject( $object->attribute( 'id' ), $object->attribute( 'current_version' ) );
00440                     $parentObj = $mainNode[0]->attribute( 'parent_contentobject' );
00441                     $result = $parentObj->checkAccess( 'create', $object->attribute( 'contentclass_id' ),
00442                                                        $parentObj->attribute( 'contentclass_id' ), false, $originalLanguage );
00443                     return $result;
00444                 }
00445                 else
00446                 {
00447                     return 0;
00448                 }
00449             }
00450 
00451             return 0;
00452         }
00453         else
00454         {
00455             $limitationList = $accessResult['policies'];
00456 
00457             if ( count( $limitationList ) > 0 )
00458             {
00459                 $access = 'denied';
00460                 foreach ( $limitationList as $limitationArray  )
00461                 {
00462                     if ( $access == 'allowed' )
00463                     {
00464                         break;
00465                     }
00466 
00467                     if ( isset( $limitationArray['Subtree' ] ) )
00468                     {
00469                         $checkedSubtree = false;
00470                     }
00471                     else
00472                     {
00473                         $checkedSubtree = true;
00474                         $accessSubtree = false;
00475                     }
00476                     if ( isset( $limitationArray['Node'] ) )
00477                     {
00478                         $checkedNode = false;
00479                     }
00480                     else
00481                     {
00482                         $checkedNode = true;
00483                         $accessNode = false;
00484                     }
00485                     foreach ( $limitationArray as $key => $limitation )
00486                     {
00487                         $access = 'denied';
00488 
00489                         if ( $key == 'Class' )
00490                         {
00491                             if ( $functionName == 'create' and !$originalClassID )
00492                                 $access = 'allowed';
00493                             else if ( $functionName == 'create' and in_array( $classID, $limitation ) )
00494                                 $access = 'allowed';
00495                             elseif ( in_array( $objectClassID, $limitation ) )
00496                                 $access = 'allowed';
00497                             else
00498                             {
00499                                 $access = 'denied';
00500                                 break;
00501                             }
00502                         }
00503                         elseif ( $key == 'Status' )
00504                         {
00505                             if (  in_array( $this->attribute( 'status' ), $limitation ) )
00506                                 $access = 'allowed';
00507                             else
00508                             {
00509                                 $access = 'denied';
00510                                 break;
00511                             }
00512                         }
00513                         elseif ( $key == 'Section' || $key == 'User_Section' )
00514                         {
00515                             if (  in_array( $object->attribute( 'section_id' ), $limitation ) )
00516                                 $access = 'allowed';
00517                             else
00518                             {
00519                                 $access = 'denied';
00520                                 break;
00521                             }
00522                         }
00523                         elseif (  $key == 'Language' )
00524                         {
00525                             $languageMask = 0;
00526                             // If we don't have a language list yet we need to fetch it
00527                             // and optionally filter out based on $language.
00528                             if ( $functionName == 'create' )
00529                             {
00530                                 // If the function is 'create' we do not use the language_mask for matching.
00531                                 if ( $language !== false )
00532                                 {
00533                                     $languageMask = $language;
00534                                 }
00535                                 else
00536                                 {
00537                                     // If the create is used and no language specified then
00538                                     // we need to match against all possible languages (which
00539                                     // is all bits set, ie. -1).
00540                                     $languageMask = -1;
00541                                 }
00542                             }
00543                             else
00544                             {
00545                                 if ( $language !== false )
00546                                 {
00547                                     if ( $languageList === false )
00548                                     {
00549                                         $languageMask = $this->attribute( 'initial_language_id' );
00550                                         // We are restricting language check to just one language
00551                                         // If the specified language is not the one in the version
00552                                         // it will become 0.
00553                                         $languageMask &= $language;
00554                                     }
00555                                 }
00556                                 else
00557                                 {
00558                                     $languageMask = $this->attribute( 'initial_language_id' );
00559                                 }
00560                             }
00561                             // Fetch limit mask for limitation list
00562                             $limitMask = eZContentLanguage::maskByLocale( $limitationArray[$key] );
00563                             if ( ( $languageMask & $limitMask ) != 0 )
00564                             {
00565                                 $access = 'allowed';
00566                             }
00567                             else
00568                             {
00569                                 $access = 'denied';
00570                             }
00571                         }
00572                         elseif ( $key == 'Owner' )
00573                         {
00574                             if ( $this->attribute( 'creator_id' ) == $userID )
00575                                 $access = 'allowed';
00576                             else
00577                             {
00578                                 $access = 'denied';
00579                                 break;
00580                             }
00581                         }
00582                         elseif ( $key == 'Node' )
00583                         {
00584                             $accessNode = false;
00585                             $contentObjectID = $this->attribute( 'contentobject_id' );
00586                             foreach ( $limitation as $nodeID )
00587                             {
00588                                 $node = eZContentObjectTreeNode::fetch( $nodeID, false, false );
00589                                 $limitationObjectID = $node['contentobject_id'];
00590                                 if ( $contentObjectID == $limitationObjectID )
00591                                 {
00592                                     $access = 'allowed';
00593                                     $accessNode = true;
00594                                     break;
00595                                 }
00596                             }
00597                             if ( $access == 'denied' && $checkedSubtree && !$accessSubtree )
00598                             {
00599                                 break;
00600                             }
00601                             else
00602                             {
00603                                 $access = 'allowed';
00604                             }
00605                             $checkedNode = true;
00606                         }
00607                         elseif ( $key == 'Subtree' )
00608                         {
00609                             $accessSubtree = false;
00610                             $contentObject = $this->attribute( 'contentobject' );
00611                             foreach ( $contentObject->attribute( 'assigned_nodes' ) as  $assignedNode )
00612                             {
00613                                 $path = $assignedNode->attribute( 'path_string' );
00614                                 $subtreeArray = $limitation;
00615                                 foreach ( $subtreeArray as $subtreeString )
00616                                 {
00617                                     if ( strstr( $path, $subtreeString ) )
00618                                     {
00619                                         $access = 'allowed';
00620                                         $accessSubtree = true;
00621                                         break;
00622                                     }
00623                                 }
00624                                 if ( $access == 'allowed' )
00625                                 {
00626                                     break;
00627                                 }
00628                             }
00629                             if ( $access != 'allowed' )
00630                             {
00631                                 foreach( $this->attribute( 'node_assignments' ) as $nodeAssignment )
00632                                 {
00633                                     $parentNode = $nodeAssignment->attribute( 'parent_node_obj' );
00634                                     $path = $parentNode->attribute( 'path_string' );
00635                                     $subtreeArray = $limitation;
00636                                     foreach ( $subtreeArray as $subtreeString )
00637                                     {
00638                                         if ( strstr( $path, $subtreeString ) )
00639                                         {
00640                                             $access = 'allowed';
00641                                             $accessSubtree = true;
00642                                             break;
00643                                         }
00644                                     }
00645                                     if ( $access == 'allowed' )
00646                                     {
00647                                         break;
00648                                     }
00649                                 }
00650                             }
00651                             if ( $access == 'denied' && $checkedNode && !$accessNode )
00652                             {
00653                                 break;
00654                             }
00655                             else
00656                             {
00657                                 $access = 'allowed';
00658                             }
00659                             $checkedSubtree = true;
00660                         }
00661                         elseif ( $key == 'User_Subtree' )
00662                         {
00663                             $contentObject = $this->attribute( 'contentobject' );
00664                             foreach ( $contentObject->attribute( 'assigned_nodes' ) as  $assignedNode )
00665                             {
00666                                 $path = $assignedNode->attribute( 'path_string' );
00667                                 $subtreeArray = $limitation;
00668                                 foreach ( $subtreeArray as $subtreeString )
00669                                 {
00670                                     if ( strstr( $path, $subtreeString ) )
00671                                     {
00672                                         $access = 'allowed';
00673                                         $accessSubtree = true;
00674                                         break;
00675                                     }
00676                                 }
00677                                 if ( $access == 'allowed' )
00678                                 {
00679                                     break;
00680                                 }
00681                             }
00682                             if ( $access != 'allowed' )
00683                             {
00684                                 foreach( $this->attribute( 'node_assignments' ) as $nodeAssignment )
00685                                 {
00686                                     $parentNode = $nodeAssignment->attribute( 'parent_node_obj' );
00687                                     $path = $parentNode->attribute( 'path_string' );
00688                                     $subtreeArray = $limitation;
00689                                     foreach ( $subtreeArray as $subtreeString )
00690                                     {
00691                                         if ( strstr( $path, $subtreeString ) )
00692                                         {
00693                                             $access = 'allowed';
00694                                             break;
00695                                         }
00696                                     }
00697                                     if ( $access == 'allowed' )
00698                                     {
00699                                         break;
00700                                     }
00701                                 }
00702                             }
00703                             if ( $access == 'denied' )
00704                             {
00705                                 break;
00706                             }
00707                         }
00708                     }
00709                 }
00710 
00711                 if ( $access == 'denied' )
00712                 {
00713                     return 0;
00714                 }
00715                 else
00716                 {
00717                     return 1;
00718                 }
00719             }
00720         }
00721     }
00722 
00723     function contentObject()
00724     {
00725         if( !isset( $this->ContentObject ) )
00726         {
00727             $this->ContentObject = eZContentObject::fetch( $this->attribute( 'contentobject_id' ) );
00728         }
00729         return $this->ContentObject;
00730     }
00731 
00732     function mainParentNodeID()
00733     {
00734         $temp = eZNodeAssignment::fetchForObject( $this->attribute( 'contentobject_id' ), $this->attribute( 'version' ), 1 );
00735         if ( $temp == null )
00736         {
00737             return 1;
00738         }
00739         else
00740         {
00741             return $temp[0]->attribute( 'parent_node' );
00742         }
00743     }
00744 
00745     function parentNodes( )
00746     {
00747         $retNodes = array();
00748         $nodeAssignmentList = eZNodeAssignment::fetchForObject( $this->attribute( 'contentobject_id' ), $this->attribute( 'version' ) );
00749         foreach ( array_keys( $nodeAssignmentList ) as $key )
00750         {
00751             $nodeAssignment = $nodeAssignmentList[$key];
00752             $retNodes[] = $nodeAssignment;
00753         }
00754         return $retNodes;
00755     }
00756     function nodeAssignments()
00757     {
00758         return eZNodeAssignment::fetchForObject( $this->attribute( 'contentobject_id' ), $this->attribute( 'version' ) );
00759     }
00760 
00761     function assignToNode( $nodeID, $main = 0, $fromNodeID = 0, $sortField = null, $sortOrder = null, $remoteID = 0 )
00762     {
00763         if ( $fromNodeID == 0 && ( $this->attribute( 'status' ) == eZContentObjectVersion::STATUS_DRAFT ||
00764                                    $this->attribute( 'status' ) == eZContentObjectVersion::STATUS_INTERNAL_DRAFT ) )
00765             $fromNodeID = -1;
00766         $nodeRow = array( 'contentobject_id' => $this->attribute( 'contentobject_id' ),
00767                           'contentobject_version' => $this->attribute( 'version' ),
00768                           'parent_node' => $nodeID,
00769                           'is_main' => $main,
00770                           'remote_id' => $remoteID,
00771                           'from_node_id' => $fromNodeID );
00772         if ( $sortField !== null )
00773             $nodeRow['sort_field'] = $sortField;
00774         if ( $sortOrder !== null )
00775             $nodeRow['sort_order'] = ( $sortOrder ? eZContentObjectTreeNode::SORT_ORDER_ASC : eZContentObjectTreeNode::SORT_ORDER_DESC );
00776 
00777         $nodeAssignment = eZNodeAssignment::create( $nodeRow );
00778         $nodeAssignment->store();
00779         return $nodeAssignment;
00780     }
00781 
00782     /*!
00783      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
00784      the calls within a db transaction; thus within db->begin and db->commit.
00785      */
00786     function removeAssignment( $nodeID )
00787     {
00788         $nodeAssignmentList = $this->attribute( 'node_assignments' );
00789         $db = eZDB::instance();
00790         $db->begin();
00791 
00792         foreach ( $nodeAssignmentList as $nodeAssignment )
00793         {
00794             if ( $nodeAssignment->attribute( 'parent_node' ) == $nodeID )
00795             {
00796                 $nodeAssignment->remove();
00797             }
00798         }
00799         $db->commit();
00800     }
00801 
00802     /*!
00803      \return the content object attribute
00804     */
00805     function dataMap()
00806     {
00807         if ( $this->ContentObjectAttributeArray === false )
00808         {
00809             $data = $this->contentObjectAttributes();
00810             // Store the attributes for later use
00811             $this->ContentObjectAttributeArray = $data;
00812         }
00813         else
00814         {
00815             $data = $this->ContentObjectAttributeArray;
00816         }
00817 
00818         if ( $this->DataMap == false )
00819         {
00820             $ret = array();
00821             foreach( $data as $item )
00822             {
00823                 $ret[$item->contentClassAttributeIdentifier()] = $item;
00824             }
00825             $this->DataMap = $ret;
00826         }
00827         else
00828         {
00829             $ret = $this->DataMap;
00830         }
00831         return $ret;
00832     }
00833 
00834     function resetDataMap()
00835     {
00836         $this->ContentObjectAttributeArray = false;
00837         $this->DataMap = false;
00838         return $this->DataMap;
00839     }
00840 
00841     /*!
00842      Returns the related objects.
00843     */
00844     function relatedContentObjectArray()
00845     {
00846         $object = $this->attribute( 'contentobject' );
00847         return $object->relatedContentObjectArray( $this->Version );
00848     }
00849 
00850     static function create( $contentobjectID, $userID = false, $version = 1, $initialLanguageCode = false )
00851     {
00852         if ( $userID === false )
00853         {
00854             $user = eZUser::currentUser();
00855             $userID = $user->attribute( 'contentobject_id' );
00856         }
00857         $time = time();
00858 
00859         if ( $initialLanguageCode == false )
00860         {
00861             $initialLanguageCode = eZContentObject::defaultLanguage();
00862         }
00863 
00864         $initialLanguageID = eZContentLanguage::idByLocale( $initialLanguageCode );
00865 
00866         $row = array(
00867             "contentobject_id" => $contentobjectID,
00868             'initial_language_id' => $initialLanguageID,
00869             'language_mask' => $initialLanguageID,
00870             "version" => $version,
00871             "created" => $time,
00872             "modified" => $time,
00873             'creator_id' => $userID );
00874         return new eZContentObjectVersion( $row );
00875     }
00876 
00877     function reverseRelatedObjectList()
00878     {
00879         return $this->attribute( 'contentobject' )->reverseRelatedObjectList( $this->Version );
00880     }
00881 
00882     /*!
00883      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
00884      the calls within a db transaction; thus within db->begin and db->commit.
00885      */
00886     function removeThis()
00887     {
00888         $contentobjectID = $this->attribute( 'contentobject_id' );
00889         $versionNum = $this->attribute( 'version' );
00890 
00891         $contentObjectTranslations = $this->translations();
00892 
00893         foreach ( $contentObjectTranslations as $contentObjectTranslation )
00894         {
00895             foreach ( $contentObjectTranslation->objectAttributes() as $attribute )
00896             {
00897                 $attribute->removeThis( $attribute->attribute( 'id' ), $versionNum );
00898             }
00899         }
00900         $db = eZDB::instance();
00901         $db->begin();
00902         $db->query( "DELETE FROM ezcontentobject_link
00903                          WHERE from_contentobject_id=$contentobjectID AND from_contentobject_version=$versionNum" );
00904         $db->query( "DELETE FROM eznode_assignment
00905                          WHERE contentobject_id=$contentobjectID AND contentobject_version=$versionNum" );
00906 
00907         $db->query( 'DELETE FROM ezcontentobject_version
00908                          WHERE id=' . $this->attribute( 'id' ) );
00909 
00910         $contentobject = $this->attribute( 'contentobject' );
00911         if ( is_object( $contentobject ) )
00912         {
00913             if ( !$contentobject->hasRemainingVersions() )
00914             {
00915                 $contentobject->purge();
00916             }
00917             else
00918             {
00919                 $version = $contentobject->CurrentVersion;
00920                 if ( $contentobject->CurrentVersion == $versionNum ) //will assign another current_version in contentObject.
00921                 {
00922                    //search for version that will be current after removing of this one.
00923                    $candidateToBeCurrent = $db->arrayQuery( "SELECT version
00924                                                      FROM ezcontentobject_version
00925                                                      WHERE contentobject_id={$contentobject->ID} AND
00926                                                            version!={$contentobject->CurrentVersion}
00927                                                      ORDER BY modified DESC",
00928                                                  array( 'offset' => 0, 'limit' => 1 ) );
00929 
00930                    if ( isset($candidateToBeCurrent[0]['version']) && is_numeric($candidateToBeCurrent[0]['version']) )
00931                    {
00932                        $contentobject->CurrentVersion = $candidateToBeCurrent[0]['version'];
00933                        $contentobject->store();
00934                    }
00935                }
00936             }
00937         }
00938         $db->query( "DELETE FROM ezcontentobject_name
00939                          WHERE contentobject_id=$contentobjectID AND content_version=$versionNum" );
00940 
00941         $db->commit();
00942     }
00943 
00944     /*!
00945      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
00946      the calls within a db transaction; thus within db->begin and db->commit.
00947      */
00948     function removeTranslation( $languageCode )
00949     {
00950 
00951         $versionNum = $this->attribute( 'version' );
00952 
00953         $contentObjectAttributes = $this->contentObjectAttributes( $languageCode );
00954 
00955         $db = eZDB::instance();
00956         $db->begin();
00957         foreach ( $contentObjectAttributes as $attribute )
00958         {
00959             $attribute->removeThis( $attribute->attribute( 'id' ), $versionNum );
00960         }
00961         $db->commit();
00962 
00963         $this->updateLanguageMask();
00964     }
00965 
00966     /*!
00967      \static
00968      Will remove all version that match the status set in \a $versionStatus.
00969      \param $versionStatus can either be a single value or an array with values,
00970                            if \c false the function will remove all status except published.
00971      \param $limit limits count of versions which should be removed.
00972      \param $expiryTime if not false then method will remove only versions which have modified time less than specified expiry time.
00973      \param $fetchPortionSize portion size for single fetch() call to avoid memory overflow erros (default 50).
00974      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
00975      the calls within a db transaction; thus within db->begin and db->commit.
00976     */
00977     static function removeVersions( $versionStatus = false, $limit = false, $expiryTime = false, $fetchPortionSize = 50 )
00978     {
00979         $statuses = array( eZContentObjectVersion::STATUS_DRAFT,
00980                            eZContentObjectVersion::STATUS_PENDING,
00981                            eZContentObjectVersion::STATUS_REJECTED,
00982                            eZContentObjectVersion::STATUS_ARCHIVED,
00983                            eZContentObjectVersion::STATUS_INTERNAL_DRAFT );
00984         if ( $versionStatus === false )
00985         {
00986             $versionStatus = $statuses;
00987         }
00988         else if ( !is_array( $versionStatus ) )
00989         {
00990             $versionStatus = array( $versionStatus );
00991         }
00992 
00993         $versionStatus = array_unique( $versionStatus );
00994         $checkIntersect = array_intersect( $versionStatus, $statuses );
00995         if ( count( $checkIntersect ) != count( $versionStatus ) )
00996         {
00997             eZDebug::writeError( 'Invalid version status was passed in.', __METHOD__ );
00998             return false;
00999         }
01000 
01001         if ( $limit !== false and ( !is_numeric( $limit ) or $limit < 0 ) )
01002         {
01003             eZDebug::writeError( '$limit must be either false or positive numeric value.', __METHOD__ );
01004             return false;
01005         }
01006 
01007         if ( !is_numeric( $fetchPortionSize ) or $fetchPortionSize < 1 )
01008             $fetchPortionSize = 50;
01009 
01010         $filters = array();
01011         $filters['status'] = array( $versionStatus );
01012         if ( $expiryTime !== false )
01013             $filters['modified'] = array( '<', $expiryTime );
01014 
01015         $processedCount = 0;
01016         while ( $processedCount < $limit or !$limit )
01017         {
01018             // fetch by versions by preset portion at a time to avoid memory overflow
01019             $tmpLimit = ( !$limit or ( $limit - $processedCount ) > $fetchPortionSize ) ?
01020                             $fetchPortionSize : $limit - $processedCount;
01021             $versions = eZContentObjectVersion::fetchFiltered( $filters, 0, $tmpLimit );
01022             if ( count( $versions ) < 1 )
01023                 break;
01024 
01025             $db = eZDB::instance();
01026             $db->begin();
01027             foreach ( $versions as $version )
01028             {
01029                 $version->removeThis();
01030             }
01031             $db->commit();
01032             $processedCount += count( $versions );
01033         }
01034         return $processedCount;
01035     }
01036 
01037     /*!
01038      Clones the version with new version \a $newVersionNumber and creator \a $userID
01039      \note The cloned version is not stored.
01040     */
01041     function cloneVersion( $newVersionNumber, $userID, $contentObjectID = false, $status = eZContentObjectVersion::STATUS_DRAFT )
01042     {
01043         $time = time();
01044         $clonedVersion = clone $this;
01045         $clonedVersion->setAttribute( 'id', null );
01046         if ( $contentObjectID !== false )
01047             $clonedVersion->setAttribute( 'contentobject_id', $contentObjectID );
01048         $clonedVersion->setAttribute( 'version', $newVersionNumber );
01049         $clonedVersion->setAttribute( 'created', $time );
01050         $clonedVersion->setAttribute( 'modified', $time );
01051         $clonedVersion->setAttribute( 'creator_id', $userID );
01052         if ( $status !== false )
01053             $clonedVersion->setAttribute( 'status', $status );
01054         return $clonedVersion;
01055     }
01056 
01057     /*!
01058      \return An array with all the translations for the current version.
01059     */
01060     function translations( $asObject = true )
01061     {
01062         return $this->translationList( false, $asObject );
01063     }
01064 
01065     /*!
01066      \return An array with all the translations for the current version.
01067      \deprecated
01068     */
01069     function translation( $asObject = true )
01070     {
01071         return false;
01072     }
01073 
01074     /*!
01075      \return An array with all the translations for the current version.
01076 
01077      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
01078            the calls within a db transaction; thus within db->begin and db->commit.
01079     */
01080     function translationList( $language = false, $asObject = true )
01081     {
01082         $db = eZDB::instance();
01083 
01084         $languageSQL = '';
01085         if ( $language !== false )
01086         {
01087             $language = $db->escapeString( $language );
01088             $languageSQL = "AND language_code!='$language'";
01089         }
01090 
01091         $query = "SELECT DISTINCT language_code
01092                   FROM ezcontentobject_attribute
01093                   WHERE contentobject_id='$this->ContentObjectID' AND version='$this->Version'
01094                   $languageSQL
01095                   ORDER BY language_code";
01096 
01097         $languageCodes = $db->arrayQuery( $query );
01098 
01099         $translations = array();
01100         if ( $asObject )
01101         {
01102             foreach ( $languageCodes as $languageCode )
01103             {
01104                 $translations[] = new eZContentObjectTranslation( $this->ContentObjectID, $this->Version, $languageCode["language_code"] );
01105             }
01106         }
01107         else
01108         {
01109             foreach ( $languageCodes as $languageCode )
01110             {
01111                 $translations[] = $languageCode["language_code"];
01112             }
01113         }
01114 
01115         return $translations;
01116     }
01117 
01118     /*!
01119      \return An array with all translations except default language for the this version.
01120 
01121      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
01122            the calls within a db transaction; thus within db->begin and db->commit.
01123     */
01124     function defaultTranslationList()
01125     {
01126         return $this->translationList();
01127     }
01128 
01129     /*!
01130      Returns the attributes for the current content object version.
01131      If \a $language is not specified it will use the initial language of the version.
01132     */
01133     function contentObjectAttributes( $languageCode = false, $asObject = true )
01134     {
01135         if ( $languageCode == false )
01136         {
01137             if ( $this->Status == eZContentObjectVersion::STATUS_DRAFT || $this->Status == eZContentObjectVersion::STATUS_INTERNAL_DRAFT || $this->Status == eZContentObjectVersion::STATUS_PENDING )
01138             {
01139                 $languageCode = $this->initialLanguageCode();
01140             }
01141             else if ( $this->CurrentLanguage )
01142             {
01143                 $languageCode = $this->CurrentLanguage;
01144             }
01145         }
01146 
01147         return eZContentObjectVersion::fetchAttributes( $this->Version, $this->ContentObjectID, $languageCode, $asObject );
01148     }
01149 
01150     /*!
01151      Returns the attributes for the content object version \a $version and content object \a $contentObjectID.
01152      \a $language defines the language to fetch.
01153      \static
01154      \sa attributes
01155      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
01156      the calls within a db transaction; thus within db->begin and db->commit.
01157     */
01158     static function fetchAttributes( $version, $contentObjectID, $language = false, $asObject = true )
01159     {
01160         $db = eZDB::instance();
01161         $language = $db->escapeString( $language );
01162         $contentObjectID = (int) $contentObjectID;
01163         $version =(int) $version;
01164         $query = "SELECT ezcontentobject_attribute.*, ezcontentclass_attribute.identifier as classattribute_identifier,
01165                         ezcontentclass_attribute.can_translate, ezcontentclass_attribute.serialized_name_list as attribute_serialized_name_list
01166                   FROM  ezcontentobject_attribute, ezcontentclass_attribute, ezcontentobject_version
01167                   WHERE
01168                     ezcontentclass_attribute.version = '0' AND
01169                     ezcontentclass_attribute.id = ezcontentobject_attribute.contentclassattribute_id AND
01170                     ezcontentobject_attribute.version = '$version' AND
01171                     ezcontentobject_attribute.contentobject_id = '$contentObjectID' AND
01172                     ezcontentobject_version.contentobject_id = '$contentObjectID' AND
01173                     ezcontentobject_version.version = '$version' AND ".
01174                     ( ( $language )? "ezcontentobject_attribute.language_code = '$language'": eZContentLanguage::sqlFilter( 'ezcontentobject_attribute', 'ezcontentobject_version' ) ).
01175                   " ORDER by
01176                     ezcontentclass_attribute.placement ASC";
01177 
01178         $attributeArray = $db->arrayQuery( $query );
01179 
01180         $returnAttributeArray = array();
01181         foreach ( $attributeArray as $attribute )
01182         {
01183             $attr = new eZContentObjectAttribute( $attribute );
01184 
01185             $attr->setContentClassAttributeIdentifier( $attribute['classattribute_identifier'] );
01186 
01187             $dataType = $attr->dataType();
01188 
01189             if ( is_object( $dataType ) &&
01190                  $dataType->Attributes["properties"]["translation_allowed"] &&
01191                  $attribute['can_translate'] )
01192                 $attr->setContentClassAttributeCanTranslate( 1 );
01193             else
01194                 $attr->setContentClassAttributeCanTranslate( 0 );
01195 
01196             $attr->setContentClassAttributeName( eZContentClassAttribute::nameFromSerializedString( $attribute['attribute_serialized_name_list'] ) );
01197 
01198             $returnAttributeArray[] = $attr;
01199         }
01200         return $returnAttributeArray;
01201     }
01202 
01203     /*!
01204      \private
01205      Maps input lange to another one if defined in $options['language_map'].
01206      If it cannot map it returns the original language.
01207      \returns string
01208      */
01209     static function mapLanguage( $language, $options )
01210     {
01211         if ( isset( $options['language_map'][$language] ) )
01212         {
01213             return $options['language_map'][$language];
01214         }
01215         return $language;
01216     }
01217 
01218     /*!
01219      \static
01220      Unserialize xml structure. Create object from xml input.
01221 
01222      \param domNode XML DOM Node
01223      \param contentObject contentobject
01224      \param ownerID owner ID
01225      \param sectionID section ID
01226      \param activeVersion new object, true if first version of new object
01227      \param options
01228      \param package
01229 
01230      \returns created object, false if could not create object/xml invalid
01231      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
01232      the calls within a db transaction; thus within db->begin and db->commit.
01233     */
01234     static function unserialize( $domNode, $contentObject, $ownerID, $sectionID, $activeVersion, $firstVersion, &$nodeList, &$options, $package, $handlerType = 'ezcontentobject' )
01235     {
01236 
01237         $oldVersion = $domNode->getAttributeNS( 'http://ez.no/ezobject', 'version' );
01238         $status = $domNode->getAttributeNS( 'http://ez.no/ezobject', 'status' );
01239         $languageNodeArray = $domNode->getElementsByTagName( 'object-translation' );
01240 
01241         $initialLanguage   = false;
01242         $importedLanguages = $options['language_array'];
01243         $currentLanguages  = array();
01244         foreach( $languageNodeArray as $languageNode )
01245         {
01246             $language = eZContentObjectVersion::mapLanguage( $languageNode->getAttribute( 'language' ), $options );
01247             if ( in_array( $language, $importedLanguages ) )
01248             {
01249                 $currentLanguages[] = $language;
01250             }
01251         }
01252         foreach ( eZContentLanguage::prioritizedLanguages() as $language )
01253         {
01254             if ( in_array( $language->attribute( 'locale' ), $currentLanguages ) )
01255             {
01256                 $initialLanguage = $language->attribute( 'locale' );
01257                 break;
01258             }
01259         }
01260         if ( !$initialLanguage )
01261         {
01262             $initialLanguage = $currentLanguages[0];
01263         }
01264 
01265         if ( $firstVersion )
01266         {
01267             $contentObjectVersion = $contentObject->version( 1 );
01268         }
01269         else
01270         {
01271             // Create new version in specific language but with empty data.
01272             $contentObjectVersion = $contentObject->createNewVersionIn( $initialLanguage );
01273         }
01274 
01275         $created = eZDateUtils::textToDate( $domNode->getAttributeNS( 'http://ez.no/ezobject', 'created' ) );
01276         $modified = eZDateUtils::textToDate( $domNode->getAttributeNS( 'http://ez.no/ezobject', 'modified' ) );
01277         $contentObjectVersion->setAttribute( 'created', $created );
01278         $contentObjectVersion->setAttribute( 'modified', $modified );
01279 
01280         $contentObjectVersion->setAttribute( 'status', eZContentObjectVersion::STATUS_DRAFT );
01281         $contentObjectVersion->store();
01282 
01283         $db = eZDB::instance();
01284         $db->begin();
01285         foreach( $languageNodeArray as $languageNode )
01286         {
01287             $language = eZContentObjectVersion::mapLanguage( $languageNode->getAttribute( 'language' ), $options );
01288             // Only import allowed languages.
01289             if ( !in_array( $language, $importedLanguages ) )
01290             {
01291                 continue;
01292             }
01293 
01294             $attributeArray = $contentObjectVersion->contentObjectAttributes( $language );
01295             if ( count( $attributeArray ) == 0)
01296             {
01297                 $hasTranslation = eZContentLanguage::fetchByLocale( $language );
01298 
01299                 if ( !$hasTranslation )
01300                 {
01301                     // if there is no needed translation in system then add it
01302                     $locale = eZLocale::instance( $language );
01303 
01304                     if ( $locale->isValid() )
01305                     {
01306                         eZContentLanguage::addLanguage( $locale->localeCode(), $locale->internationalLanguageName() );
01307                         $hasTranslation = true;
01308                     }
01309                     else
01310                         $hasTranslation = false;
01311                 }
01312 
01313                 if ( $hasTranslation )
01314                 {
01315                     // Add translated attributes for the translation
01316                     $originalContentAttributes = $contentObjectVersion->contentObjectAttributes( $initialLanguage );
01317                     foreach ( $originalContentAttributes as $originalContentAttribute )
01318                     {
01319                         $contentAttribute = $originalContentAttribute->translateTo( $language );
01320                         $contentAttribute->sync();
01321                         $attributeArray[] = $contentAttribute;
01322                     }
01323                 }
01324 
01325                 // unserialize object name in current version-translation
01326                 $objectName = $languageNode->getAttribute( 'object_name' );
01327                 if ( $objectName )
01328                     $contentObject->setName( $objectName, $contentObjectVersion->attribute( 'version' ), $language );
01329             }
01330 
01331             $xpath = new DOMXPath( $domNode->ownerDocument );
01332             $xpath->registerNamespace( 'ezobject', 'http://ez.no/object/' );
01333             $xpath->registerNamespace( 'ezremote', 'http://ez.no/ezobject' );
01334 
01335             foreach( $attributeArray as $attribute )
01336             {
01337                 $attributeIdentifier = $attribute->attribute( 'contentclass_attribute_identifier' );
01338                 $xpathQuery = "ezobject:attribute[@ezremote:identifier='$attributeIdentifier']";
01339                 $attributeDomNodes = $xpath->query( $xpathQuery, $languageNode );
01340                 $attributeDomNode = $attributeDomNodes->item( 0 );
01341                 if ( !$attributeDomNode )
01342                 {
01343                     continue;
01344                 }
01345                 $attribute->unserialize( $package, $attributeDomNode );
01346                 $attribute->store();
01347             }
01348         }
01349 
01350         $objectRelationList = $domNode->getElementsByTagName( 'object-relation-list' )->item( 0 );
01351         if ( $objectRelationList )
01352         {
01353             $objectRelationArray = $objectRelationList->getElementsByTagName( 'related-object-remote-id' );
01354             foreach( $objectRelationArray as $objectRelation )
01355             {
01356                 $relatedObjectRemoteID = $objectRelation->textContent;
01357                 if ( $relatedObjectRemoteID )
01358                 {
01359                     $object = eZContentObject::fetchByRemoteID( $relatedObjectRemoteID );
01360                     $relatedObjectID = ( $object !== null ) ? $object->attribute( 'id' ) : null;
01361 
01362                     if ( $relatedObjectID )
01363                     {
01364                         $contentObject->addContentObjectRelation( $relatedObjectID, $contentObjectVersion->attribute( 'version' ) );
01365                     }
01366                     else
01367                     {
01368                         if ( !isset( $options['suspended-relations'] ) )
01369                         {
01370                             $options['suspended-relations'] = array();
01371                         }
01372 
01373                         $options['suspended-relations'][] = array( 'related-object-remote-id' => $relatedObjectRemoteID,
01374                                                                    'contentobject-id'         => $contentObject->attribute( 'id' ),
01375                                                                    'contentobject-version'    => $contentObjectVersion->attribute( 'version' ) );
01376                     }
01377                 }
01378             }
01379         }
01380 
01381         $nodeAssignmentNodeList = $domNode->getElementsByTagName( 'node-assignment-list' )->item( 0 );
01382         $nodeAssignmentNodeArray = $nodeAssignmentNodeList->getElementsByTagName( 'node-assignment' );
01383         foreach( $nodeAssignmentNodeArray as $nodeAssignmentNode )
01384         {
01385             $result = eZContentObjectTreeNode::unserialize( $nodeAssignmentNode,
01386                                                             $contentObject,
01387                                                             $contentObjectVersion->attribute( 'version' ),
01388                                                             ( $oldVersion == $activeVersion ? 1 : 0 ),
01389                                                             $nodeList,
01390                                                             $options,
01391                                                             $handlerType );
01392             if ( $result === false )
01393             {
01394                 $db->commit();
01395                 $retValue = false;
01396                 return $retValue;
01397             }
01398         }
01399 
01400         $contentObjectVersion->store();
01401         $db->commit();
01402 
01403         return $contentObjectVersion;
01404     }
01405 
01406     function postUnserialize( $package )
01407     {
01408         foreach( $this->translations( false ) as $language )
01409         {
01410             foreach( $this->contentObjectAttributes( $language ) as $attribute )
01411             {
01412                 $attribute->postUnserialize( $package );
01413             }
01414         }
01415     }
01416 
01417     /*!
01418      \return a DOM structure of the content object version, it's translations and attributes.
01419 
01420      \param package
01421      \param options package options ( optional )
01422      \param contentNodeIDArray array of allowed nodes ( optional )
01423      \param topNodeIDArray array of top nodes in current package export (optional )
01424      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
01425      the calls within a db transaction; thus within db->begin and db->commit.
01426     */
01427     function serialize( $package, $options = false, $contentNodeIDArray = false, $topNodeIDArray = false )
01428     {
01429         $dom = new DOMDocument( '1.0', 'utf-8' );
01430 
01431         $versionNode = $dom->createElementNS( 'http://ez.no/object/', 'ezobject:version' );
01432         $dom->appendChild( $versionNode );
01433 
01434         $versionNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:version', $this->Version );
01435         $versionNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:status', $this->Status );
01436         $versionNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:created', eZDateUtils::rfc1123Date( $this->attribute( 'created' ) ) );
01437         $versionNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:modified', eZDateUtils::rfc1123Date( $this->attribute( 'modified' ) ) );
01438 
01439         $translationList = $this->translationList( false, false );
01440         $contentObject   = $this->attribute( 'contentobject' );
01441 
01442         $db = eZDB::instance();
01443         $db->begin();
01444         $allowedLanguages = $options['language_array'];
01445         if ( $options['only_initial_language'] )
01446         {
01447             $initialLanguageCode = $this->initialLanguageCode();
01448             if ( !in_array( $initialLanguageCode, $allowedLanguages ) )
01449             {
01450                 // We can only export initial language but is not in the allowed
01451                 // language list so we return false, ie. no export of this version.
01452                 return false;
01453             }
01454             // Make sure only the initial language is exported
01455             $allowedLanguages = array( $initialLanguageCode );
01456         }
01457         $exportedLanguages = array();
01458         foreach ( $translationList as $translationItem )
01459         {
01460             $language = $translationItem;
01461             if ( !in_array( $language, $allowedLanguages ) )
01462             {
01463                 continue;
01464             }
01465 
01466             $translationNode = $dom->createElementNS( 'http://ez.no/object/', 'ezobject:object-translation' );
01467             $translationNode->setAttribute( 'language', $language );
01468 
01469             // serialize object name in current version-translation
01470             $objectName = $contentObject->name( $this->Version, $language );
01471             if ( $objectName )
01472             {
01473                 $translationNode->setAttribute( 'object_name', $objectName );
01474             }
01475             else
01476             {
01477                 eZDebug::writeWarning( sprintf( "Name for object %s of version %s in translation %s not found",
01478                                                 $contentObject->attribute( 'id' ),
01479                                                 $this->Version,
01480                                                 $language ) );
01481             }
01482 
01483             $attributes = $this->contentObjectAttributes( $language );
01484             foreach ( $attributes as $attribute )
01485             {
01486                 $serializedAttributeNode = $attribute->serialize( $package );
01487                 $importedSerializedAttributeNode = $dom->importNode( $serializedAttributeNode, true );
01488                 $translationNode->appendChild( $importedSerializedAttributeNode );
01489             }
01490 
01491             $versionNode->appendChild( $translationNode );
01492             $exportedLanguages[] = $language;
01493         }
01494 
01495         $nodeAssignmentListNode = $dom->createElementNS( 'http://ez.no/object/', 'ezobject:node-assignment-list' );
01496         $versionNode->appendChild( $nodeAssignmentListNode );
01497 
01498         $contentNodeArray = eZContentObjectTreeNode::fetchByContentObjectID( $this->ContentObjectID, true, $this->Version );
01499         foreach( $contentNodeArray as $contentNode )
01500         {
01501             $contentNodeDOMNode = $contentNode->serialize( $options, $contentNodeIDArray, $topNodeIDArray );
01502             if ( $contentNodeDOMNode !== false )
01503             {
01504                 $importedContentDOMNode = $dom->importNode( $contentNodeDOMNode, true );
01505                 $nodeAssignmentListNode->appendChild( $importedContentDOMNode );
01506             }
01507         }
01508         $initialLanguage = $this->attribute( 'initial_language' );
01509         $initialLanguageCode = $initialLanguage->attribute( 'locale' );
01510         if ( in_array( $initialLanguageCode, $exportedLanguages ) )
01511         {
01512             $versionNode->setAttribute( 'initial_language', $initialLanguageCode );
01513         }
01514 
01515         if ( $options['related_objects'] === 'selected' )
01516         {
01517             $relatedObjectArray = $contentObject->relatedContentObjectList( $this->Version, $contentObject->ID, 0, false,
01518                                                                              array( 'AllRelations' => eZContentObject::RELATION_COMMON ) );
01519             if ( count( $relatedObjectArray ) )
01520             {
01521                 $relationListNode = $dom->createElementNS( 'http://ez.no/object/', 'ezobject:object-relation-list' );
01522 
01523                 foreach( $relatedObjectArray as $relatedObject )
01524                 {
01525                     $relatedObjectRemoteID = $relatedObject->attribute( 'remote_id' );
01526 
01527                     $relationNode = $dom->createElement( 'related-object-remote-id' );
01528                     $relationNode->appendChild( $dom->createTextNode( $relatedObjectRemoteID ) );
01529 
01530                     $relationListNode->appendChild( $relationNode );
01531                 }
01532                 $versionNode->appendChild( $relationListNode );
01533             }
01534         }
01535 
01536         $db->commit();
01537         return $versionNode;
01538     }
01539 
01540     /*!
01541      \return the creator of the current version.
01542     */
01543     function creator()
01544     {
01545         if ( isset( $this->CreatorID ) and $this->CreatorID )
01546         {
01547             return eZContentObject::fetch( $this->CreatorID );
01548         }
01549         return null;
01550     }
01551 
01552     /*!
01553      \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
01554      the calls within a db transaction; thus within db->begin and db->commit.
01555      */
01556     function unpublish()
01557     {
01558         if ( $this->attribute( 'status' ) == eZContentObjectVersion::STATUS_PUBLISHED )
01559         {
01560             $this->setAttribute( 'status', eZContentObjectVersion::STATUS_ARCHIVED );
01561             $parentNodeList = $this->attribute( 'parent_nodes' );
01562             $parentNodeIDList = array();
01563             foreach( $parentNodeList as $parentNode )
01564             {
01565                 $parentNodeIDList[] = $parentNode->attribute( 'parent_node' );
01566             }
01567             if ( count( $parentNodeIDList ) == 0 )
01568             {
01569                 eZDebug::writeWarning( $this, "unable to get parent nodes for version" );
01570                 return;
01571             }
01572             $parentNodeIDString = implode( ',' , $parentNodeIDList );
01573             $contentObjectID = $this->attribute( 'contentobject_id' );
01574             $version = $this->attribute( 'version' );
01575             $db = eZDB::instance();
01576             $query = "update ezcontentobject_tree
01577                       set contentobject_is_published = '0'
01578                       where parent_node_id in ( $parentNodeIDString ) and
01579                             contentobject_id = $contentObjectID and
01580                             contentobject_version = $version" ;
01581             $db->query( $query );
01582         }
01583         else
01584         {
01585             eZDebug::writeWarning( $this, "trying to unpublish non published version" );
01586         }
01587 
01588     }
01589 
01590     /*!
01591      \returns an array with locale objects, these objects represents the languages the content objects are allowed to be translated into.
01592               The array will not include locales that has been translated in this version.
01593     */
01594     function nonTranslationList()
01595     {
01596         $translationList = eZContentObject::translationList();
01597         if ( $translationList === null )
01598         {
01599             $retValue = null;
01600             return $retValue;
01601         }
01602 
01603         $translations = $this->translations( false );
01604         $nonTranslationList = array();
01605         foreach ( $translationList as $translationItem )
01606         {
01607             $locale = $translationItem->attribute( 'locale_code' );
01608             if ( !in_array( $locale, $translations ) )
01609                 $nonTranslationList[] = $translationItem;
01610         }
01611         return $nonTranslationList;
01612     }
01613 
01614     function languageMask()
01615     {
01616         return (int)$this->attribute( 'language_mask' );
01617     }
01618 
01619     function updateLanguageMask( $mask = false, $forceStore = true )
01620     {
01621         if ( $mask == false )
01622         {
01623             $mask = eZContentLanguage::maskByLocale( $this->translationList( false, false ), true );
01624         }
01625 
01626         $this->setAttribute( 'language_mask', $mask );
01627 
01628         if ( $forceStore )
01629         {
01630             $this->store();
01631         }
01632     }
01633 
01634     function initialLanguage()
01635     {
01636         return eZContentLanguage::fetch( $this->InitialLanguageID );
01637     }
01638 
01639     function initialLanguageCode()
01640     {
01641         $initialLanguage = $this->initialLanguage();
01642 
01643         $initialLanguageCode = $initialLanguage !== false ?  $initialLanguage->attribute( 'locale' ) : false;
01644 
01645         return $initialLanguageCode;
01646     }
01647 
01648     function nonTranslatableAttributesToUpdate( )
01649     {
01650         $object = $this->contentObject();
01651         $version = $this->attribute( 'version' );
01652         $objectID = $object->attribute( 'id' );
01653         $initialLanguageID = $object->attribute( 'initial_language_id' );
01654         $db = eZDB::instance();
01655 
01656         $attributeRows = $db->arrayQuery( "SELECT ezcontentobject_attribute.id, ezcontentobject_attribute.version
01657             FROM ezcontentobject_version,
01658                  ezcontentobject_attribute,
01659                 ezcontentclass_attribute
01660             WHERE
01661                     ezcontentobject_version.contentobject_id='$objectID'
01662                 AND ( ezcontentobject_version.status in ( " .
01663                       eZContentObjectVersion::STATUS_DRAFT . ", " . eZContentObjectVersion::STATUS_PENDING . ", " . eZContentObjectVersion::STATUS_INTERNAL_DRAFT .
01664                       " ) OR ( ezcontentobject_version.status = '" . self::STATUS_PUBLISHED . "' AND ezcontentobject_version.version = '$version' ) )
01665                 AND ezcontentobject_attribute.contentobject_id=ezcontentobject_version.contentobject_id
01666                 AND ezcontentobject_attribute.version=ezcontentobject_version.version
01667                 AND ezcontentobject_attribute.language_id!='$initialLanguageID'
01668                 AND ezcontentobject_attribute.contentclassattribute_id=ezcontentclass_attribute.id
01669                 AND ezcontentclass_attribute.can_translate=0" );
01670 
01671         $attributes = array();
01672         foreach( $attributeRows as $row )
01673         {
01674             $attributes[] = eZContentObjectAttribute::fetch( $row['id'], $row['version'] );
01675         }
01676         return $attributes;
01677     }
01678 
01679     function setAlwaysAvailableLanguageID( $languageID )
01680     {
01681         $db = eZDB::instance();
01682         $db->begin();
01683 
01684         $objectID = $this->attribute( 'contentobject_id' );
01685         $version = $this->attribute( 'version' );
01686 
01687         // reset 'always available' flag
01688         $sql = "UPDATE ezcontentobject_attribute SET language_id=";
01689         if ( $db->databaseName() == 'oracle' )
01690         {
01691             $sql .= "bitand( language_id, -2 )";
01692         }
01693         else
01694         {
01695             $sql .= "language_id & ~1";
01696         }
01697         $sql .= " WHERE contentobject_id = '$objectID' AND version = '$version'";
01698         $db->query( $sql );
01699 
01700         if ( $languageID != false )
01701         {
01702             $newLanguageID = $languageID | 1;
01703 
01704             $sql = "UPDATE ezcontentobject_attribute
01705                     SET language_id='$newLanguageID'
01706                 WHERE language_id='$languageID' AND contentobject_id = '$objectID' AND version = '$version'";
01707             $db->query( $sql );
01708         }
01709 
01710         $db->commit();
01711     }
01712 
01713     function clearAlwaysAvailableLanguageID()
01714     {
01715         $this->setAlwaysAvailableLanguageID( false );
01716     }
01717 
01718     // Checks if there is another version (published or archived status) which has higher modification time than the
01719     // current version creation time.
01720     // Typically this function can be used before object's publishing to prevent conflicts.
01721     //
01722     // \return  array of version objects that caused conflict or false.
01723     function hasConflicts( $editLanguage = false )
01724     {
01725         $object = $this->contentObject();
01726         if ( !$editLanguage )
01727             $editLanguage = $this->initialLanguageCode();
01728 
01729         // Get versions (with published or archived status)
01730         $versions = $object->versions( true, array( 'conditions' => array( 'status' => array( array( eZContentObjectVersion::STATUS_PUBLISHED, eZContentObjectVersion::STATUS_ARCHIVED ) ),
01731                                                                            'language_code' => $editLanguage ) ) );
01732 
01733         $conflictVersions = array();
01734         foreach ( array_keys( $versions ) as $key )
01735         {
01736             $version =& $versions[$key];
01737             if ( $version->attribute( 'modified' ) > $this->attribute( 'created' ) )
01738             {
01739                 $conflictVersions[] = $version;
01740             }
01741         }
01742         if ( !count( $conflictVersions ) )
01743         {
01744             return false;
01745         }
01746 
01747         return $conflictVersions;
01748     }
01749 
01750     public function store( $fieldFilters = null )
01751     {
01752         eZContentObject::clearCache( $this->attribute( 'contentobject_id' ) );
01753         parent::store( $fieldFilters );
01754     }
01755 
01756     public $CurrentLanguage = false;
01757 }
01758 
01759 ?>