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