|
eZ Publish
[trunk]
|
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 ?>