|
eZ Publish
[4.0]
|
00001 <?php 00002 // 00003 // Definition of eZContentObject class 00004 // 00005 // Created on: <17-Apr-2002 09:15:27 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 eZContentObject ezcontentobject.php 00033 \ingroup eZKernel 00034 \brief Handles eZ Publish content objects 00035 00036 It encapsulates the data for an object and provides lots of functions 00037 for dealing with versions, translations and attributes. 00038 00039 \sa eZContentClass 00040 */ 00041 00042 //include_once( "lib/ezdb/classes/ezdb.php" ); 00043 //include_once( 'lib/ezlocale/classes/ezlocale.php' ); 00044 //include_once( "kernel/classes/ezpersistentobject.php" ); 00045 //include_once( "kernel/classes/ezcontentobjectversion.php" ); 00046 //include_once( "kernel/classes/ezcontentobjectattribute.php" ); 00047 //include_once( "kernel/classes/ezcontentclass.php" ); 00048 //include_once( "kernel/classes/ezcontentobjecttreenode.php" ); 00049 //include_once( 'kernel/classes/ezcontentlanguage.php' ); 00050 //include_once( "kernel/classes/datatypes/ezuser/ezuser.php" ); 00051 00052 class eZContentObject extends eZPersistentObject 00053 { 00054 const STATUS_DRAFT = 0; 00055 const STATUS_PUBLISHED = 1; 00056 const STATUS_ARCHIVED = 2; 00057 00058 const PACKAGE_ERROR_NO_CLASS = 1; 00059 const PACKAGE_ERROR_EXISTS = 2; 00060 const PACKAGE_ERROR_NODE_EXISTS = 3; 00061 const PACKAGE_ERROR_MODIFIED = 101; 00062 const PACKAGE_ERROR_HAS_CHILDREN = 102; 00063 00064 const PACKAGE_REPLACE = 1; 00065 const PACKAGE_SKIP = 2; 00066 const PACKAGE_NEW = 3; 00067 const PACKAGE_DELETE = 4; 00068 const PACKAGE_KEEP = 5; 00069 00070 const RELATION_COMMON = 1; 00071 const RELATION_EMBED = 2; 00072 const RELATION_LINK = 4; 00073 const RELATION_ATTRIBUTE = 8; 00074 00075 function eZContentObject( $row ) 00076 { 00077 $this->eZPersistentObject( $row ); 00078 $this->ClassIdentifier = false; 00079 if ( isset( $row['contentclass_identifier'] ) ) 00080 $this->ClassIdentifier = $row['contentclass_identifier']; 00081 $this->ClassName = false; 00082 if ( isset( $row['contentclass_name'] ) ) 00083 $this->ClassName = $row['contentclass_name']; 00084 if ( isset( $row['serialized_name_list'] ) ) 00085 $this->ClassName = eZContentClass::nameFromSerializedString( $row['serialized_name_list'] ); 00086 00087 $this->CurrentLanguage = false; 00088 if ( isset( $row['content_translation'] ) ) 00089 { 00090 $this->CurrentLanguage = $row['content_translation']; 00091 } 00092 else if ( isset( $row['real_translation'] ) ) 00093 { 00094 $this->CurrentLanguage = $row['real_translation']; 00095 } 00096 else if ( isset( $row['language_mask'] ) ) 00097 { 00098 $topPriorityLanguage = eZContentLanguage::topPriorityLanguageByMask( $row['language_mask'] ); 00099 if ( $topPriorityLanguage ) 00100 { 00101 $this->CurrentLanguage = $topPriorityLanguage->attribute( 'locale' ); 00102 } 00103 } 00104 } 00105 00106 static function definition() 00107 { 00108 return array( "fields" => array( "id" => array( 'name' => 'ID', 00109 'datatype' => 'integer', 00110 'default' => 0, 00111 'required' => true ), 00112 "section_id" => array( 'name' => "SectionID", 00113 'datatype' => 'integer', 00114 'default' => 0, 00115 'required' => true, 00116 'foreign_class' => 'eZSection', 00117 'foreign_attribute' => 'id', 00118 'multiplicity' => '1..*' ), 00119 "owner_id" => array( 'name' => "OwnerID", 00120 'datatype' => 'integer', 00121 'default' => 0, 00122 'required' => true, 00123 'foreign_class' => 'eZUser', 00124 'foreign_attribute' => 'contentobject_id', 00125 'multiplicity' => '1..*'), 00126 "contentclass_id" => array( 'name' => "ClassID", 00127 'datatype' => 'integer', 00128 'default' => 0, 00129 'required' => true, 00130 'foreign_class' => 'eZContentClass', 00131 'foreign_attribute' => 'id', 00132 'multiplicity' => '1..*' ), 00133 "name" => array( 'name' => "Name", 00134 'datatype' => 'string', 00135 'default' => '', 00136 'required' => true ), 00137 "is_published" => array( 'name' => "IsPublished", 00138 'datatype' => 'integer', 00139 'default' => 0, 00140 'required' => true ), 00141 "published" => array( 'name' => "Published", 00142 'datatype' => 'integer', 00143 'default' => 0, 00144 'required' => true ), 00145 "modified" => array( 'name' => "Modified", 00146 'datatype' => 'integer', 00147 'default' => 0, 00148 'required' => true ), 00149 "current_version" => array( 'name' => "CurrentVersion", 00150 'datatype' => 'integer', 00151 'default' => 0, 00152 'required' => true ), 00153 "status" => array( 'name' => "Status", 00154 'datatype' => 'integer', 00155 'default' => 0, 00156 'required' => true ), 00157 'remote_id' => array( 'name' => "RemoteID", 00158 'datatype' => 'string', 00159 'default' => '', 00160 'required' => true ), 00161 'language_mask' => array( 'name' => 'LanguageMask', 00162 'datatype' => 'integer', 00163 'default' => 0, 00164 'required' => true ), 00165 'initial_language_id' => array( 'name' => 'InitialLanguageID', 00166 'datatype' => 'integer', 00167 'default' => 0, 00168 'required' => true, 00169 'foreign_class' => 'eZContentLanguage', 00170 'foreign_attribute' => 'id', 00171 'multiplicity' => '1..*' ) ), 00172 "keys" => array( "id" ), 00173 "function_attributes" => array( "current" => "currentVersion", 00174 'versions' => 'versions', 00175 'author_array' => 'authorArray', 00176 "class_name" => "className", 00177 "content_class" => "contentClass", 00178 "contentobject_attributes" => "contentObjectAttributes", 00179 "owner" => "owner", 00180 "related_contentobject_array" => "relatedContentObjectList", 00181 "related_contentobject_count" => "relatedContentObjectCount", 00182 'reverse_related_contentobject_array' => 'reverseRelatedObjectList', 00183 'reverse_related_contentobject_count' => 'reverseRelatedObjectCount', 00184 "linked_contentobject_array" => "linkedContentObjectList", 00185 "linked_contentobject_count" => "linkedContentObjectCount", 00186 'reverse_linked_contentobject_array' => 'reverseLinkedObjectList', 00187 'reverse_linked_contentobject_count' => 'reverseLinkedObjectCount', 00188 "embedded_contentobject_array" => "embeddedContentObjectList", 00189 "embedded_contentobject_count" => "embeddedContentObjectCount", 00190 'reverse_embedded_contentobject_array' => 'reverseEmbeddedObjectList', 00191 'reverse_embedded_contentobject_count' => 'reverseEmbeddedObjectCount', 00192 "can_read" => "canRead", 00193 "can_pdf" => "canPdf", 00194 "can_diff" => "canDiff", 00195 "can_create" => "canCreate", 00196 "can_create_class_list" => "canCreateClassList", 00197 "can_edit" => "canEdit", 00198 "can_translate" => "canTranslate", 00199 "can_remove" => "canRemove", 00200 "can_move" => "canMoveFrom", 00201 "can_move_from" => "canMoveFrom", 00202 'can_view_embed' => 'canViewEmbed', 00203 "data_map" => "dataMap", 00204 "main_parent_node_id" => "mainParentNodeID", 00205 "assigned_nodes" => "assignedNodes", 00206 "parent_nodes" => "parentNodeIDArray", 00207 "main_node_id" => "mainNodeID", 00208 "main_node" => "mainNode", 00209 "default_language" => "defaultLanguage", 00210 "content_action_list" => "contentActionList", 00211 "class_identifier" => "contentClassIdentifier", 00212 'class_group_id_list' => 'contentClassGroupIDList', 00213 'name' => 'name', 00214 'match_ingroup_id_list' => 'matchIngroupIDList', 00215 'remote_id' => 'remoteID', 00216 'current_language' => 'currentLanguage', 00217 'current_language_object' => 'currentLanguageObject', 00218 'initial_language' => 'initialLanguage', 00219 'initial_language_code' => 'initialLanguageCode', 00220 'available_languages' => 'availableLanguages', 00221 'language_codes' => 'availableLanguages', 00222 'language_js_array' => 'availableLanguagesJsArray', 00223 'languages' => 'languages', 00224 'all_languages' => 'allLanguages', 00225 'can_edit_languages' => 'canEditLanguages', 00226 'can_create_languages' => 'canCreateLanguages', 00227 'always_available' => 'isAlwaysAvailable', 00228 'allowed_assign_section_list' => 'allowedAssignSectionList' ), 00229 "increment_key" => "id", 00230 "class_name" => "eZContentObject", 00231 "sort" => array( "id" => "asc" ), 00232 "name" => "ezcontentobject" ); 00233 } 00234 00235 /*! 00236 Get class groups this object's class belongs to if match for class groups is enabled. 00237 00238 \return array of class group ids. False if match is disabled. 00239 \note The reference for the return value is required to workaround 00240 a bug with PHP references. 00241 */ 00242 function matchIngroupIDList() 00243 { 00244 //include_once( 'lib/ezutils/classes/ezini.php' ); 00245 $contentINI = eZINI::instance( 'content.ini' ); 00246 $inList = false; 00247 if( $contentINI->variable( 'ContentOverrideSettings', 'EnableClassGroupOverride' ) == 'true' ) 00248 { 00249 $contentClass = $this->contentClass(); 00250 $inList = $contentClass->attribute( 'ingroup_id_list' ); 00251 } 00252 return $inList; 00253 } 00254 00255 /*! 00256 Store the object 00257 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00258 the calls within a db transaction; thus within db->begin and db->commit. 00259 */ 00260 function store( $fieldFilters = null ) 00261 { 00262 // Unset the cache 00263 global $eZContentObjectContentObjectCache; 00264 unset( $eZContentObjectContentObjectCache[$this->ID] ); 00265 global $eZContentObjectDataMapCache; 00266 unset( $eZContentObjectDataMapCache[$this->ID] ); 00267 global $eZContentObjectVersionCache; 00268 unset( $eZContentObjectVersionCache[$this->ID] ); 00269 00270 $db = eZDB::instance(); 00271 $db->begin(); 00272 $this->storeNodeModified(); 00273 eZPersistentObject::store( $fieldFilters ); 00274 $db->commit(); 00275 } 00276 00277 /*! 00278 Clear in-memory caches. 00279 \param $idArray objects to clear caches for. 00280 00281 If the parameter is ommitted the caches are cleared for all objects. 00282 */ 00283 00284 static function clearCache( $idArray = array() ) 00285 { 00286 if ( is_numeric( $idArray ) ) 00287 $idArray = array( $idArray ); 00288 00289 // clear in-memory cache for all objects 00290 if ( count( $idArray ) == 0 ) 00291 { 00292 unset( $GLOBALS['eZContentObjectContentObjectCache'] ); 00293 unset( $GLOBALS['eZContentObjectDataMapCache'] ); 00294 unset( $GLOBALS['eZContentObjectVersionCache'] ); 00295 00296 return; 00297 } 00298 00299 // clear in-memory cache for specified object(s) 00300 global $eZContentObjectContentObjectCache; 00301 global $eZContentObjectDataMapCache; 00302 global $eZContentObjectVersionCache; 00303 foreach ( $idArray as $objectID ) 00304 { 00305 unset( $eZContentObjectContentObjectCache[$objectID] ); 00306 unset( $eZContentObjectDataMapCache[$objectID] ); 00307 unset( $eZContentObjectVersionCache[$objectID] ); 00308 } 00309 } 00310 00311 /*! 00312 Update all nodes to set modified_subnode value 00313 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00314 the calls within a db transaction; thus within db->begin and db->commit. 00315 */ 00316 function storeNodeModified() 00317 { 00318 if ( is_numeric( $this->ID ) ) 00319 { 00320 $nodeArray = $this->assignedNodes(); 00321 00322 $db = eZDB::instance(); 00323 $db->begin(); 00324 foreach ( array_keys( $nodeArray ) as $key ) 00325 { 00326 $nodeArray[$key]->updateAndStoreModified(); 00327 } 00328 $db->commit(); 00329 } 00330 } 00331 00332 function name( $version = false , $lang = false ) 00333 { 00334 // if the object id is null, we can't read data from the database 00335 // and return the locally known name 00336 if ( is_null( $this->attribute( 'id' ) ) ) 00337 { 00338 return $this->Name; 00339 } 00340 if ( !$version ) 00341 { 00342 $version = $this->attribute( 'current_version' ); 00343 } 00344 if ( !$lang && $this->CurrentLanguage ) 00345 { 00346 $lang = $this->CurrentLanguage; 00347 } 00348 00349 return $this->versionLanguageName( $version, $lang ); 00350 } 00351 00352 function names() 00353 { 00354 $version = $this->attribute( 'current_version' ); 00355 $id = $this->attribute( 'id' ); 00356 00357 $db = eZDB::instance(); 00358 $rows = $db->arrayQuery( "SELECT name, real_translation FROM ezcontentobject_name WHERE contentobject_id = '$id' AND content_version='$version'" ); 00359 $names = array(); 00360 foreach ( $rows as $row ) 00361 { 00362 $names[$row['real_translation']] = $row['name']; 00363 } 00364 00365 return $names; 00366 } 00367 00368 function versionLanguageName( $version, $lang = false ) 00369 { 00370 $name = false; 00371 if ( !$version > 0 ) 00372 { 00373 eZDebug::writeNotice( "There is no object name for version($version) of the content object ($contentObjectID) in language($lang)", 00374 'eZContentObject::versionLanguageName' ); 00375 return $name; 00376 } 00377 $db = eZDb::instance(); 00378 $contentObjectID = $this->attribute( 'id' ); 00379 if ( !$lang ) 00380 { 00381 // If $lang not given we will use the initial language of the object 00382 $query = "SELECT initial_language_id FROM ezcontentobject WHERE id='$contentObjectID'"; 00383 $rows = $db->arrayQuery( $query ); 00384 if ( $rows ) 00385 { 00386 $languageID = $rows[0]['initial_language_id']; 00387 $language = eZContentLanguage::fetch( $languageID ); 00388 if ( $language ) 00389 { 00390 $lang = $language->attribute( 'locale' ); 00391 } 00392 else 00393 { 00394 return $name; 00395 } 00396 } 00397 else 00398 { 00399 return $name; 00400 } 00401 } 00402 $lang = $db->escapeString( $lang ); 00403 $version = (int) $version; 00404 00405 $initialLanguage = $this->attribute( 'initial_language_id' ); 00406 00407 $query= "SELECT name, content_translation 00408 FROM ezcontentobject_name 00409 WHERE contentobject_id = '$contentObjectID' 00410 AND content_version = '$version' 00411 AND ( content_translation = '$lang' OR language_id = '$initialLanguage' )"; 00412 $result = $db->arrayQuery( $query ); 00413 00414 $resCount = count( $result ); 00415 if( $resCount < 1 ) 00416 { 00417 eZDebug::writeNotice( "There is no object name for version($version) of the content object ($contentObjectID) in language($lang)", 00418 'eZContentObject::versionLanguageName' ); 00419 } 00420 else if( $resCount > 1 ) 00421 { 00422 // we have name in requested language => find and return it 00423 foreach( $result as $row ) 00424 { 00425 if( $row['content_translation'] == $lang ) 00426 { 00427 $name = $row['name']; 00428 break; 00429 } 00430 } 00431 } 00432 else 00433 { 00434 // we don't have name in requested language(or requested language is the same as initial language) => use name in initial language 00435 $name = $result[0]['name']; 00436 } 00437 00438 return $name; 00439 } 00440 00441 /*! 00442 Sets the name of the object, in memory only. Use setName() to change it. 00443 */ 00444 function setCachedName( $name ) 00445 { 00446 $this->Name = $name; 00447 } 00448 00449 /*! 00450 Sets the name of the object in all translations. 00451 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00452 the calls within a db transaction; thus within db->begin and db->commit. 00453 */ 00454 function setName( $objectName, $versionNum = false, $languageCode = false ) 00455 { 00456 $initialLanguageCode = false; 00457 if ( $initialLanguage = $this->initialLanguage() ) 00458 { 00459 $initialLanguageCode = $initialLanguage->attribute( 'locale' ); 00460 } 00461 $db = eZDB::instance(); 00462 00463 if ( $languageCode == false ) 00464 { 00465 $languageCode = $initialLanguageCode; 00466 } 00467 $languageCode = $db->escapeString( $languageCode ); 00468 if ( $languageCode == $initialLanguageCode ) 00469 { 00470 $this->Name = $objectName; 00471 } 00472 00473 if ( !$versionNum ) 00474 { 00475 $versionNum = $this->attribute( 'current_version' ); 00476 } 00477 $objectID =(int) $this->attribute( 'id' ); 00478 $versionNum =(int) $versionNum; 00479 00480 $languageID =(int) eZContentLanguage::idByLocale( $languageCode ); 00481 00482 $objectName = $db->escapeString( $objectName ); 00483 00484 $db->begin(); 00485 00486 // Check if name is already set before setting/changing it. 00487 // This helps to avoid deadlocks in mysql: a pair of DELETE/INSERT might cause deadlock here 00488 // in case of concurrent execution. 00489 $rows = $db->arrayQuery( "SELECT COUNT(*) AS count FROM ezcontentobject_name WHERE contentobject_id = '$objectID' 00490 AND content_version = '$versionNum' AND content_translation ='$languageCode'" ); 00491 if ( $rows[0]['count'] ) 00492 { 00493 $db->query( "UPDATE ezcontentobject_name SET name='$objectName' 00494 WHERE 00495 contentobject_id = '$objectID' AND 00496 content_version = '$versionNum' AND 00497 content_translation ='$languageCode'" ); 00498 } 00499 else 00500 { 00501 $db->query( "INSERT INTO ezcontentobject_name( contentobject_id, 00502 name, 00503 content_version, 00504 content_translation, 00505 real_translation, 00506 language_id ) 00507 VALUES( '$objectID', 00508 '$objectName', 00509 '$versionNum', 00510 '$languageCode', 00511 '$languageCode', 00512 '$languageID' )" ); 00513 } 00514 00515 $db->commit(); 00516 } 00517 00518 /*! 00519 \return a map with all the content object attributes where the keys are the 00520 attribute identifiers. 00521 */ 00522 function dataMap() 00523 { 00524 return $this->fetchDataMap(); 00525 } 00526 00527 /*! 00528 \return a map with all the content object attributes where the keys are the 00529 attribute identifiers. 00530 \sa eZContentObjectTreeNode::dataMap 00531 */ 00532 function fetchDataMap( $version = false, $language = false ) 00533 { 00534 // Global variable to cache datamaps 00535 global $eZContentObjectDataMapCache; 00536 00537 if ( $version == false ) 00538 $version = $this->attribute( 'current_version' ); 00539 00540 if ( $language == false ) 00541 { 00542 $language = $this->CurrentLanguage; 00543 } 00544 00545 if ( !$language || !isset( $eZContentObjectDataMapCache[$this->ID][$version][$language] ) ) 00546 { 00547 $data = $this->contentObjectAttributes( true, $version, $language ); 00548 00549 if ( !$language ) 00550 { 00551 $language = $this->CurrentLanguage; 00552 } 00553 00554 // Store the attributes for later use 00555 $this->ContentObjectAttributeArray[$version][$language] = $data; 00556 $eZContentObjectDataMapCache[$this->ID][$version][$language] = $data; 00557 } 00558 else 00559 { 00560 $data = $eZContentObjectDataMapCache[$this->ID][$version][$language]; 00561 } 00562 00563 if ( !isset( $this->DataMap[$version][$language] ) ) 00564 { 00565 $ret = array(); 00566 foreach( $data as $key => $item ) 00567 { 00568 $identifier = $item->contentClassAttributeIdentifier(); 00569 $ret[$identifier] = $data[$key]; 00570 } 00571 $this->DataMap[$version][$language] = $ret; 00572 } 00573 else 00574 { 00575 $ret = $this->DataMap[$version][$language]; 00576 } 00577 return $ret; 00578 } 00579 00580 function resetDataMap() 00581 { 00582 $this->ContentObjectAttributeArray = array(); 00583 $this->ContentObjectAttributes = array(); 00584 $this->DataMap = array(); 00585 return $this->DataMap; 00586 } 00587 00588 /*! 00589 Fetch a set of content object attributes by their class identifiers. 00590 */ 00591 function fetchAttributesByIdentifier( $identifierArray, $version = false, $languageArray = false, $asObject = true ) 00592 { 00593 if ( count( $identifierArray ) === 0 ) 00594 { 00595 return null; 00596 } 00597 00598 $db = eZDB::instance(); 00599 00600 $identifierQuotedString = array(); 00601 foreach ( $identifierArray as $identifier ) 00602 { 00603 $identifierQuotedString[] = "'$identifier'"; 00604 } 00605 00606 if ( !$version or !is_numeric( $version ) ) 00607 { 00608 $version = $this->CurrentVersion; 00609 } 00610 00611 if ( is_array( $languageArray ) ) 00612 { 00613 $langCodeQuotedString = array(); 00614 foreach ( $languageArray as $langCode ) 00615 { 00616 if ( is_string( $langCode ) ) 00617 $langCodeQuotedString[] = "'$langCode'"; 00618 } 00619 00620 if ( !empty( $langCodeQuotedString ) ) 00621 { 00622 $languageText = "AND\n\t\t"; 00623 $languageText .= $db->generateSQLINStatement( $langCodeQuotedString, 'ezcontentobject_attribute.language_code' ); 00624 } 00625 } 00626 // Adding support for the old language parameter <= 4.0.1 here, where only one string for locale code was provided. 00627 else if ( is_string( $languageArray ) ) 00628 { 00629 $languageText = "AND\n\t\t\t ezcontentobject_attribute.language_code = '$languageArray'"; 00630 } 00631 00632 if ( !isset( $languageText ) ) 00633 { 00634 $languageText = "AND\n\t\t\t" . eZContentLanguage::sqlFilter( 'ezcontentobject_attribute', 'ezcontentobject_version' ); 00635 } 00636 00637 $versionText = "AND\n\t\t ezcontentobject_attribute.version = '$version'"; 00638 00639 $query = "SELECT\t ezcontentobject_attribute.*, ezcontentclass_attribute.identifier as identifier 00640 FROM\t ezcontentobject_attribute, ezcontentclass_attribute, ezcontentobject_version 00641 WHERE 00642 ezcontentclass_attribute.version = ". eZContentClass::VERSION_STATUS_DEFINED . " AND 00643 ezcontentclass_attribute.id = ezcontentobject_attribute.contentclassattribute_id AND 00644 ezcontentobject_version.contentobject_id = {$this->ID} AND 00645 ezcontentobject_version.version = {$version} AND 00646 ezcontentobject_attribute.contentobject_id = {$this->ID} 00647 00648 {$languageText} 00649 00650 {$versionText} 00651 00652 AND 00653 "; 00654 00655 $query .= $db->generateSQLINStatement( $identifierQuotedString, 'identifier' ); 00656 00657 $rows = $db->arrayQuery( $query ); 00658 00659 if ( count( $rows ) > 0 ) 00660 { 00661 if ( $asObject ) 00662 { 00663 $returnArray = array(); 00664 foreach( $rows as $row ) 00665 { 00666 $returnArray[$row['id']] = new eZContentObjectAttribute( $row ); 00667 } 00668 return $returnArray; 00669 } 00670 else 00671 { 00672 return $rows; 00673 } 00674 } 00675 return null; 00676 } 00677 00678 /*! 00679 Returns the owner of the object as a content object. 00680 */ 00681 function owner() 00682 { 00683 if ( $this->OwnerID != 0 ) 00684 { 00685 return eZContentObject::fetch( $this->OwnerID ); 00686 } 00687 return null; 00688 } 00689 00690 /*! 00691 \return the content class group identifiers for the current content object 00692 */ 00693 function contentClassGroupIDList() 00694 { 00695 $contentClass = $this->contentClass(); 00696 return $contentClass->attribute( 'ingroup_id_list' ); 00697 } 00698 00699 /*! 00700 \return the content class identifer for the current content object 00701 00702 \note The object will cache the class name information so multiple calls will be fast. 00703 */ 00704 function contentClassIdentifier() 00705 { 00706 if ( !is_numeric( $this->ClassID ) ) 00707 { 00708 $retValue = null; 00709 return $retValue; 00710 } 00711 00712 if ( $this->ClassIdentifier !== false ) 00713 return $this->ClassIdentifier; 00714 00715 $db = eZDB::instance(); 00716 $id = (int)$this->ClassID; 00717 $sql = "SELECT identifier FROM ezcontentclass WHERE id=$id and version=0"; 00718 $rows = $db->arrayQuery( $sql ); 00719 if ( count( $rows ) > 0 ) 00720 { 00721 $this->ClassIdentifier = $rows[0]['identifier']; 00722 } 00723 return $this->ClassIdentifier; 00724 } 00725 00726 /*! 00727 \return the content class for the current content object 00728 */ 00729 function contentClass() 00730 { 00731 if ( !is_numeric( $this->ClassID ) ) 00732 { 00733 $retValue = null; 00734 return $retValue; 00735 } 00736 00737 return eZContentClass::fetch( $this->ClassID ); 00738 } 00739 00740 /*! 00741 Get remote id of content node 00742 */ 00743 function remoteID() 00744 { 00745 $remoteID = eZPersistentObject::attribute( 'remote_id', true ); 00746 00747 // Ensures that we provide the correct remote_id if we have one in the database 00748 if ( $remoteID === null and $this->attribute( 'id' ) ) 00749 { 00750 $db = eZDB::instance(); 00751 $resultArray = $db->arrayQuery( "SELECT remote_id FROM ezcontentobject WHERE id = '" . $this->attribute( 'id' ) . "'" ); 00752 if ( count( $resultArray ) == 1 ) 00753 { 00754 $remoteID = $resultArray[0]['remote_id']; 00755 $this->setAttribute( 'remote_id', $remoteID ); 00756 } 00757 } 00758 00759 if ( !$remoteID ) 00760 { 00761 $this->setAttribute( 'remote_id', md5( (string)mt_rand() . (string)time() ) ); 00762 if ( $this->attribute( 'id' ) !== null ) 00763 $this->sync( array( 'remote_id' ) ); 00764 $remoteID = eZPersistentObject::attribute( 'remote_id', true ); 00765 } 00766 00767 return $remoteID; 00768 } 00769 00770 function mainParentNodeID() 00771 { 00772 return eZContentObjectTreeNode::getParentNodeId( $this->attribute( 'main_node_id' ) ); 00773 } 00774 00775 /*! 00776 Fetches contentobject by remote ID, returns null if none exist 00777 */ 00778 static function fetchByRemoteID( $remoteID, $asObject = true ) 00779 { 00780 $db = eZDB::instance(); 00781 $remoteID =$db->escapeString( $remoteID ); 00782 $resultArray = $db->arrayQuery( 'SELECT id FROM ezcontentobject WHERE remote_id=\'' . $remoteID . '\'' ); 00783 if ( count( $resultArray ) != 1 ) 00784 $object = null; 00785 else 00786 $object = eZContentObject::fetch( $resultArray[0]['id'], $asObject ); 00787 return $object; 00788 } 00789 00790 /** 00791 * Fetches a content object by ID 00792 * @param int $id ID of the content object to fetch 00793 * @param bool $asObject 00794 * Return the result as an object (true) or an assoc. array (false) 00795 * 00796 * @return eZContentObject 00797 **/ 00798 static function fetch( $id, $asObject = true ) 00799 { 00800 global $eZContentObjectContentObjectCache; 00801 00802 // If the object given by its id is not cached or should be returned as array 00803 // then we fetch it from the DB (objects are always cached as arrays). 00804 if ( !isset( $eZContentObjectContentObjectCache[$id] ) or $asObject === false ) 00805 { 00806 $db = eZDB::instance(); 00807 00808 $resArray = $db->arrayQuery( eZContentObject::createFetchSQLString( $id ) ); 00809 00810 $objectArray = array(); 00811 if ( count( $resArray ) == 1 && $resArray !== false ) 00812 { 00813 $objectArray = $resArray[0]; 00814 } 00815 else 00816 { 00817 eZDebug::writeError( "Object not found ($id)", 'eZContentObject::fetch()' ); 00818 $retValue = null; 00819 return $retValue; 00820 } 00821 00822 if ( $asObject ) 00823 { 00824 $obj = new eZContentObject( $objectArray ); 00825 $eZContentObjectContentObjectCache[$id] = $obj; 00826 } 00827 else 00828 { 00829 return $objectArray; 00830 } 00831 00832 return $obj; 00833 } 00834 else 00835 { 00836 return $eZContentObjectContentObjectCache[$id]; 00837 } 00838 } 00839 00840 /*! 00841 \static 00842 Tests for the existance of a content object by using the ID \a $id. 00843 \return \c true if the object exists, \c false otherwise. 00844 \note Uses the static function createFetchSQLString() to generate the SQL 00845 */ 00846 static function exists( $id ) 00847 { 00848 global $eZContentObjectContentObjectCache; 00849 00850 // Check the global cache 00851 if ( isset( $eZContentObjectContentObjectCache[$id] ) ) 00852 return true; 00853 00854 // If the object is not cached we need to check the DB 00855 $db = eZDB::instance(); 00856 00857 $resArray = $db->arrayQuery( eZContentObject::createFetchSQLString( $id ) ); 00858 00859 if ( $resArray !== false and count( $resArray ) == 1 ) 00860 { 00861 return true; 00862 } 00863 00864 return false; 00865 00866 } 00867 00868 /*! 00869 \static 00870 Creates the SQL for fetching the object with ID \a $id and returns the string. 00871 */ 00872 static function createFetchSQLString( $id ) 00873 { 00874 $id = (int) $id; 00875 00876 $fetchSQLString = "SELECT ezcontentobject.*, 00877 ezcontentclass.serialized_name_list as serialized_name_list, 00878 ezcontentclass.identifier as contentclass_identifier, 00879 ezcontentclass.is_container as is_container 00880 FROM 00881 ezcontentobject, 00882 ezcontentclass 00883 WHERE 00884 ezcontentobject.id='$id' AND 00885 ezcontentclass.id = ezcontentobject.contentclass_id AND 00886 ezcontentclass.version=0"; 00887 00888 return $fetchSQLString; 00889 } 00890 00891 /*! 00892 Fetches the contentobject which has a node with the ID \a $nodeID 00893 \param $asObject If \c true return the as a PHP object, if \c false return the raw database data. 00894 */ 00895 static function fetchByNodeID( $nodeID, $asObject = true ) 00896 { 00897 global $eZContentObjectContentObjectCache; 00898 $nodeID = (int)$nodeID; 00899 00900 $useVersionName = true; 00901 if ( $useVersionName ) 00902 { 00903 $versionNameTables = ', ezcontentobject_name '; 00904 $versionNameTargets = ', ezcontentobject_name.name as name, ezcontentobject_name.real_translation '; 00905 00906 $versionNameJoins = " and ezcontentobject.id = ezcontentobject_name.contentobject_id and 00907 ezcontentobject.current_version = ezcontentobject_name.content_version and ". 00908 eZContentLanguage::sqlFilter( 'ezcontentobject_name', 'ezcontentobject' ); 00909 } 00910 00911 $db = eZDB::instance(); 00912 00913 $query = "SELECT ezcontentobject.* $versionNameTargets 00914 FROM 00915 ezcontentobject, 00916 ezcontentobject_tree 00917 $versionNameTables 00918 WHERE 00919 ezcontentobject_tree.node_id=$nodeID AND 00920 ezcontentobject.id=ezcontentobject_tree.contentobject_id AND 00921 ezcontentobject.current_version=ezcontentobject_tree.contentobject_version 00922 $versionNameJoins"; 00923 00924 $resArray = $db->arrayQuery( $query ); 00925 00926 $objectArray = array(); 00927 if ( count( $resArray ) == 1 && $resArray !== false ) 00928 { 00929 $objectArray = $resArray[0]; 00930 } 00931 else 00932 { 00933 eZDebug::writeError( 'Object not found with node id ' . $nodeID, 'eZContentObject::fetchByNodeID()' ); 00934 $retValue = null; 00935 return $retValue; 00936 } 00937 00938 if ( $asObject ) 00939 { 00940 $obj = new eZContentObject( $objectArray ); 00941 $eZContentObjectContentObjectCache[$objectArray['id']] = $obj; 00942 } 00943 else 00944 { 00945 return $objectArray; 00946 } 00947 00948 return $obj; 00949 } 00950 00951 /** 00952 * Fetches a content object list based on an array of content object ids 00953 * 00954 * @param array $idArray array of content object ids 00955 * @param bool $asObject 00956 * Wether to get the result as an array of eZContentObject or an 00957 * array of associative arrays 00958 * 00959 * @return array(contentObjectID => eZContentObject|array) 00960 * array of eZContentObject (if $asObject = true) or array of 00961 * associative arrays (if $asObject = false) 00962 **/ 00963 static function fetchIDArray( $idArray, $asObject = true ) 00964 { 00965 global $eZContentObjectContentObjectCache; 00966 00967 $uniqueIDArray = array_unique( $idArray ); 00968 00969 $useVersionName = true; 00970 if ( $useVersionName ) 00971 { 00972 $versionNameTables = ', ezcontentobject_name '; 00973 $versionNameTargets = ', ezcontentobject_name.name as name, ezcontentobject_name.real_translation '; 00974 00975 $versionNameJoins = " and ezcontentobject.id = ezcontentobject_name.contentobject_id and 00976 ezcontentobject.current_version = ezcontentobject_name.content_version and ". 00977 eZContentLanguage::sqlFilter( 'ezcontentobject_name', 'ezcontentobject' ); 00978 } 00979 00980 $db = eZDB::instance(); 00981 // All elements from $uniqueIDArray should be casted to (int) 00982 $objectWhereINSQL = $db->generateSQLINStatement( $uniqueIDArray, 'ezcontentobject.id', false, false, 'int' ); 00983 $query = "SELECT ezcontentclass.serialized_name_list as class_serialized_name_list, ezcontentobject.* $versionNameTargets 00984 FROM 00985 ezcontentclass, 00986 ezcontentobject 00987 $versionNameTables 00988 WHERE 00989 ezcontentclass.id=ezcontentobject.contentclass_id AND 00990 $objectWhereINSQL 00991 $versionNameJoins"; 00992 00993 $resRowArray = $db->arrayQuery( $query ); 00994 00995 $objectRetArray = array(); 00996 foreach ( $resRowArray as $resRow ) 00997 { 00998 $objectID = $resRow['id']; 00999 $resRow['class_name'] = eZContentClass::nameFromSerializedString( $resRow['class_serialized_name_list'] ); 01000 if ( $asObject ) 01001 { 01002 $obj = new eZContentObject( $resRow ); 01003 $obj->ClassName = $resRow['class_name']; 01004 $eZContentObjectContentObjectCache[$objectID] = $obj; 01005 $objectRetArray[$objectID] = $obj; 01006 } 01007 else 01008 { 01009 $objectRetArray[$objectID] = $resRow; 01010 } 01011 } 01012 return $objectRetArray; 01013 } 01014 01015 /*! 01016 \return An array with content objects. 01017 \param $asObject Whether to return objects or not 01018 \param $conditions Optional conditions to limit the fetch, set to \c null to skip it. 01019 \param $offset Where to start fetch from, set to \c false to skip it. 01020 \param $limit Maximum number of objects to fetch, set \c false to skip it. 01021 \sa fetchListCount 01022 */ 01023 static function fetchList( $asObject = true, $conditions = null, $offset = false, $limit = false ) 01024 { 01025 $limitation = null; 01026 if ( $offset !== false or 01027 $limit !== false ) 01028 $limitation = array( 'offset' => $offset, 01029 'length' => $limit ); 01030 return eZPersistentObject::fetchObjectList( eZContentObject::definition(), 01031 null, 01032 $conditions, null, $limitation, 01033 $asObject ); 01034 } 01035 01036 static function fetchFilteredList( $conditions = null, $offset = false, $limit = false, $asObject = true ) 01037 { 01038 $limits = null; 01039 if ( $offset or $limit ) 01040 $limits = array( 'offset' => $offset, 01041 'length' => $limit ); 01042 return eZPersistentObject::fetchObjectList( eZContentObject::definition(), 01043 null, 01044 $conditions, null, $limits, 01045 $asObject ); 01046 } 01047 01048 /*! 01049 \return The number of objects in the database. Optionally \a $conditions can be used to limit the list count. 01050 \sa fetchList 01051 */ 01052 static function fetchListCount( $conditions = null ) 01053 { 01054 $rows = eZPersistentObject::fetchObjectList( eZContentObject::definition(), 01055 array(), 01056 $conditions, 01057 false/* we don't want any sorting when counting. Sorting leads to error on postgresql 8.x */, 01058 null, 01059 false, false, 01060 array( array( 'operation' => 'count( * )', 01061 'name' => 'count' ) ) ); 01062 return $rows[0]['count']; 01063 } 01064 01065 static function fetchSameClassList( $contentClassID, $asObject = true, $offset = false, $limit = false ) 01066 { 01067 $conditions = array( 'contentclass_id' => $contentClassID ); 01068 return eZContentObject::fetchFilteredList( $conditions, $offset, $limit, $asObject ); 01069 } 01070 01071 static function fetchSameClassListCount( $contentClassID ) 01072 { 01073 $result = eZPersistentObject::fetchObjectList( eZContentObject::definition(), 01074 array(), 01075 array( "contentclass_id" => $contentClassID ), 01076 false, null, 01077 false, false, 01078 array( array( 'operation' => 'count( * )', 01079 'name' => 'count' ) ) ); 01080 return $result[0]['count']; 01081 } 01082 01083 /*! 01084 Returns the current version of this document. 01085 */ 01086 function currentVersion( $asObject = true ) 01087 { 01088 return eZContentObjectVersion::fetchVersion( $this->attribute( "current_version" ), $this->ID, $asObject ); 01089 } 01090 01091 /*! 01092 Returns the given object version. False is returned if the versions does not exist. 01093 */ 01094 function version( $version, $asObject = true ) 01095 { 01096 if ( $asObject ) 01097 { 01098 global $eZContentObjectVersionCache; 01099 01100 if ( !isset( $eZContentObjectVersionCache ) ) // prevent PHP warning below 01101 $eZContentObjectVersionCache = array(); 01102 01103 if ( array_key_exists( $this->ID, $eZContentObjectVersionCache ) && 01104 array_key_exists( $version, $eZContentObjectVersionCache[$this->ID] ) ) 01105 { 01106 return $eZContentObjectVersionCache[$this->ID][$version]; 01107 } 01108 else 01109 { 01110 $eZContentObjectVersionCache[$this->ID][$version] = eZContentObjectVersion::fetchVersion( $version, $this->ID, $asObject ); 01111 return $eZContentObjectVersionCache[$this->ID][$version]; 01112 } 01113 } 01114 else 01115 { 01116 return eZContentObjectVersion::fetchVersion( $version, $this->ID, $asObject ); 01117 } 01118 } 01119 01120 /*! 01121 \return an array of versions for the current object. 01122 \note The reference for the return value is required to workaround 01123 a bug with PHP references. 01124 */ 01125 function versions( $asObject = true, $parameters = array() ) 01126 { 01127 $conditions = array( "contentobject_id" => $this->ID ); 01128 if ( isset( $parameters['conditions'] ) ) 01129 { 01130 if ( isset( $parameters['conditions']['status'] ) ) 01131 $conditions['status'] = $parameters['conditions']['status']; 01132 if ( isset( $parameters['conditions']['creator_id'] ) ) 01133 $conditions['creator_id'] = $parameters['conditions']['creator_id']; 01134 if ( isset( $parameters['conditions']['language_code'] ) ) 01135 { 01136 $conditions['initial_language_id'] = eZContentLanguage::idByLocale( $parameters['conditions']['language_code'] ); 01137 } 01138 if ( isset( $parameters['conditions']['initial_language_id'] ) ) 01139 { 01140 $conditions['initial_language_id'] = $parameters['conditions']['initial_language_id']; 01141 } 01142 } 01143 01144 return eZPersistentObject::fetchObjectList( eZContentObjectVersion::definition(), 01145 null, $conditions, 01146 null, null, 01147 $asObject ); 01148 } 01149 01150 /*! 01151 \return \c true if the object has any versions remaining. 01152 */ 01153 function hasRemainingVersions() 01154 { 01155 $remainingVersions = $this->versions( false ); 01156 if ( !is_array( $remainingVersions ) or 01157 count( $remainingVersions ) == 0 ) 01158 { 01159 return false; 01160 } 01161 return true; 01162 } 01163 01164 function createInitialVersion( $userID, $initialLanguageCode = false ) 01165 { 01166 return eZContentObjectVersion::create( $this->attribute( "id" ), $userID, 1, $initialLanguageCode ); 01167 } 01168 01169 function createNewVersionIn( $languageCode, $copyFromLanguageCode = false, $copyFromVersion = false, $versionCheck = true, $status = eZContentObjectVersion::STATUS_DRAFT ) 01170 { 01171 return $this->createNewVersion( $copyFromVersion, $versionCheck, $languageCode, $copyFromLanguageCode, $status ); 01172 } 01173 01174 /*! 01175 Creates a new version and returns it as an eZContentObjectVersion object. 01176 If version number is given as argument that version is used to create a copy. 01177 \param $versionCheck If \c true it will check if there are too many version and 01178 remove some of them to make room for a new. 01179 01180 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 01181 the calls within a db transaction; thus within db->begin and db->commit. 01182 */ 01183 function createNewVersion( $copyFromVersion = false, $versionCheck = true, $languageCode = false, $copyFromLanguageCode = false, $status = eZContentObjectVersion::STATUS_DRAFT ) 01184 { 01185 $db = eZDB::instance(); 01186 $db->begin(); 01187 // Check if we have enough space in version list 01188 if ( $versionCheck ) 01189 { 01190 $contentINI = eZINI::instance( 'content.ini' ); 01191 $versionlimit = $contentINI->variable( 'VersionManagement', 'DefaultVersionHistoryLimit' ); 01192 $limitList = $contentINI->variable( 'VersionManagement', 'VersionHistoryClass' ); 01193 $classID = $this->attribute( 'contentclass_id' ); 01194 foreach ( array_keys ( $limitList ) as $key ) 01195 { 01196 if ( $classID == $key ) 01197 { 01198 $versionlimit = $limitList[$key]; 01199 } 01200 } 01201 if ( $versionlimit < 2 ) 01202 { 01203 $versionlimit = 2; 01204 } 01205 $versionCount = $this->getVersionCount(); 01206 if ( $versionCount >= $versionlimit ) 01207 { 01208 // Remove oldest archived version 01209 $params = array( 'conditions'=> array( 'status' => 3 ) ); 01210 $versions = $this->versions( true, $params ); 01211 if ( count( $versions ) > 0 ) 01212 { 01213 $modified = $versions[0]->attribute( 'modified' ); 01214 $removeVersion = $versions[0]; 01215 foreach ( $versions as $version ) 01216 { 01217 $currentModified = $version->attribute( 'modified' ); 01218 if ( $currentModified < $modified ) 01219 { 01220 $modified = $currentModified; 01221 $removeVersion = $version; 01222 } 01223 } 01224 $removeVersion->removeThis(); 01225 } 01226 } 01227 } 01228 01229 // get the next available version number 01230 $nextVersionNumber = $this->nextVersion(); 01231 01232 if ( $copyFromVersion == false ) 01233 { 01234 $version = $this->currentVersion(); 01235 } 01236 else 01237 { 01238 $version = $this->version( $copyFromVersion ); 01239 } 01240 01241 if ( !$languageCode ) 01242 { 01243 $initialLanguage = $version->initialLanguage(); 01244 if ( !$initialLanguage ) 01245 { 01246 $initialLanguage = $this->initialLanguage(); 01247 } 01248 01249 if ( $initialLanguage ) 01250 { 01251 $languageCode = $initialLanguage->attribute( 'locale' ); 01252 } 01253 } 01254 01255 $copiedVersion = $this->copyVersion( $this, $version, $nextVersionNumber, false, $status, $languageCode, $copyFromLanguageCode ); 01256 01257 // We need to make sure the copied version contains node-assignment for the existing nodes. 01258 // This is required for BC since scripts might traverse the node-assignments and mark 01259 // some of them for removal. 01260 $parentMap = array(); 01261 $copiedNodeAssignmentList = $copiedVersion->attribute( 'node_assignments' ); 01262 foreach ( $copiedNodeAssignmentList as $copiedNodeAssignment ) 01263 { 01264 $parentMap[$copiedNodeAssignment->attribute( 'parent_node' )] = $copiedNodeAssignment; 01265 } 01266 $nodes = $this->assignedNodes(); 01267 foreach ( $nodes as $node ) 01268 { 01269 $remoteID = 0; 01270 // Remove assignments which conflicts with existing nodes, but keep remote_id 01271 if ( isset( $parentMap[$node->attribute( 'parent_node_id' )] ) ) 01272 { 01273 $copiedNodeAssignment = $parentMap[$node->attribute( 'parent_node_id' )]; 01274 $remoteID = $copiedNodeAssignment->attribute( 'remote_id' ); 01275 $copiedNodeAssignment->purge(); 01276 } 01277 $newNodeAssignment = $copiedVersion->assignToNode( $node->attribute( 'parent_node_id' ), $node->attribute( 'is_main' ), 0, 01278 $node->attribute( 'sort_field' ), $node->attribute( 'sort_order' ), 01279 $remoteID ); 01280 // Reset execution bit 01281 $newNodeAssignment->setAttribute( 'op_code', $newNodeAssignment->attribute( 'op_code' ) & ~1 ); 01282 $newNodeAssignment->store(); 01283 } 01284 01285 $db->commit(); 01286 return $copiedVersion; 01287 } 01288 01289 /*! 01290 Creates a new version and returns it as an eZContentObjectVersion object. 01291 If version number is given as argument that version is used to create a copy. 01292 \param $languageCode If \c false all languages will be copied, otherwise 01293 only specified by the locale code string or an array 01294 of the locale code strings. 01295 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 01296 the calls within a db transaction; thus within db->begin and db->commit. 01297 */ 01298 function copyVersion( &$newObject, &$version, $newVersionNumber, $contentObjectID = false, $status = eZContentObjectVersion::STATUS_DRAFT, $languageCode = false, $copyFromLanguageCode = false ) 01299 { 01300 $user = eZUser::currentUser(); 01301 $userID = $user->attribute( 'contentobject_id' ); 01302 01303 $nodeAssignmentList = $version->attribute( 'node_assignments' ); 01304 01305 $db = eZDB::instance(); 01306 $db->begin(); 01307 01308 // This is part of the new 3.8 code. 01309 foreach ( array_keys( $nodeAssignmentList ) as $key ) 01310 { 01311 $nodeAssignment = $nodeAssignmentList[$key]; 01312 // Only copy assignments which has a remote_id since it will be used in template code. 01313 if ( $nodeAssignment->attribute( 'remote_id' ) == 0 ) 01314 { 01315 continue; 01316 } 01317 $clonedAssignment = $nodeAssignment->cloneNodeAssignment( $newVersionNumber, $contentObjectID ); 01318 $clonedAssignment->setAttribute( 'op_code', eZNodeAssignment::OP_CODE_SET ); // Make sure op_code is marked to 'set' the data. 01319 $clonedAssignment->store(); 01320 } 01321 01322 $currentVersionNumber = $version->attribute( "version" ); 01323 $contentObjectTranslations = $version->translations(); 01324 01325 $clonedVersion = $version->cloneVersion( $newVersionNumber, $userID, $contentObjectID, $status ); 01326 01327 if ( $contentObjectID != false ) 01328 { 01329 if ( $clonedVersion->attribute( 'status' ) == eZContentObjectVersion::STATUS_PUBLISHED ) 01330 $clonedVersion->setAttribute( 'status', eZContentObjectVersion::STATUS_DRAFT ); 01331 } 01332 01333 $clonedVersion->store(); 01334 01335 // We copy related objects before the attributes, this means that the related objects 01336 // are available once the datatype code is run. 01337 $this->copyContentObjectRelations( $currentVersionNumber, $newVersionNumber, $contentObjectID ); 01338 01339 $languageCodeToCopy = false; 01340 if ( $languageCode && in_array( $languageCode, $this->availableLanguages() ) ) 01341 { 01342 $languageCodeToCopy = $languageCode; 01343 } 01344 if ( $copyFromLanguageCode && in_array( $copyFromLanguageCode, $this->availableLanguages() ) ) 01345 { 01346 $languageCodeToCopy = $copyFromLanguageCode; 01347 } 01348 01349 $haveCopied = false; 01350 if ( !$languageCode || $languageCodeToCopy ) 01351 { 01352 foreach ( $contentObjectTranslations as $contentObjectTranslation ) 01353 { 01354 if ( $languageCode != false && $contentObjectTranslation->attribute( 'language_code' ) != $languageCodeToCopy ) 01355 { 01356 continue; 01357 } 01358 01359 $contentObjectAttributes = $contentObjectTranslation->objectAttributes(); 01360 01361 foreach ( $contentObjectAttributes as $attribute ) 01362 { 01363 $clonedAttribute = $attribute->cloneContentObjectAttribute( $newVersionNumber, $currentVersionNumber, $contentObjectID, $languageCode ); 01364 $clonedAttribute->sync(); 01365 eZDebugSetting::writeDebug( 'kernel-content-object-copy', $clonedAttribute, 'copyVersion:cloned attribute' ); 01366 } 01367 01368 $haveCopied = true; 01369 } 01370 } 01371 01372 if ( !$haveCopied && $languageCode ) 01373 { 01374 $class = $this->contentClass(); 01375 $classAttributes = $class->fetchAttributes(); 01376 foreach ( $classAttributes as $classAttribute ) 01377 { 01378 if ( $classAttribute->attribute( 'can_translate' ) == 1 ) 01379 { 01380 $classAttribute->instantiate( $contentObjectID? $contentObjectID: $this->attribute( 'id' ), $languageCode, $newVersionNumber ); 01381 } 01382 else 01383 { 01384 // If attribute is NOT Translatable we should check isAlwaysAvailable(), 01385 // For example, 01386 // if initial_language_id is 4 and the attribute is always available 01387 // language_id will be 5 in ezcontentobject_version/ezcontentobject_attribute, 01388 // this means it uses language ID 4 but also has the bit 0 set to 1 (a reservered bit), 01389 // You can read about this in the document in doc/features/3.8/. 01390 $initialLangID = !$this->isAlwaysAvailable() ? $this->attribute( 'initial_language_id' ) : $this->attribute( 'initial_language_id' ) | 1; 01391 $contentAttribute = eZContentObjectAttribute::fetchByClassAttributeID( $classAttribute->attribute( 'id' ), 01392 $this->attribute( 'id' ), 01393 $this->attribute( 'current_version' ), 01394 $initialLangID ); 01395 if ( $contentAttribute ) 01396 { 01397 $newAttribute = $contentAttribute->cloneContentObjectAttribute( $newVersionNumber, $currentVersionNumber, $contentObjectID, $languageCode ); 01398 $newAttribute->sync(); 01399 } 01400 else 01401 { 01402 $classAttribute->instantiate( $contentObjectID? $contentObjectID: $this->attribute( 'id' ), $languageCode, $newVersionNumber ); 01403 } 01404 } 01405 } 01406 } 01407 01408 if ( $languageCode ) 01409 { 01410 $clonedVersion->setAttribute( 'initial_language_id', eZContentLanguage::idByLocale( $languageCode ) ); 01411 $clonedVersion->updateLanguageMask(); 01412 } 01413 01414 $db->commit(); 01415 01416 return $clonedVersion; 01417 } 01418 01419 /*! 01420 Creates a new content object instance and stores it. 01421 */ 01422 static function create( $name, $contentclassID, $userID, $sectionID = 1, $version = 1, $languageCode = false ) 01423 { 01424 if ( $languageCode == false ) 01425 { 01426 $languageCode = eZContentObject::defaultLanguage(); 01427 } 01428 01429 $languageID = eZContentLanguage::idByLocale( $languageCode ); 01430 01431 $row = array( 01432 "name" => $name, 01433 "current_version" => $version, 01434 'initial_language_id' => $languageID, 01435 'language_mask' => $languageID, 01436 "contentclass_id" => $contentclassID, 01437 "permission_id" => 1, 01438 "parent_id" => 0, 01439 "main_node_id" => 0, 01440 "owner_id" => $userID, 01441 "section_id" => $sectionID, 01442 'remote_id' => md5( (string)mt_rand() . (string)time() ) ); 01443 01444 return new eZContentObject( $row ); 01445 } 01446 01447 function __clone() 01448 { 01449 $this->setAttribute( 'id', null ); 01450 $this->setAttribute( 'published', time() ); 01451 $this->setAttribute( 'modified', time() ); 01452 $this->resetDataMap(); 01453 } 01454 01455 /*! 01456 Makes a copy of the object which is stored and then returns it. 01457 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 01458 the calls within a db transaction; thus within db->begin and db->commit. 01459 */ 01460 function copy( $allVersions = true ) 01461 { 01462 eZDebugSetting::writeDebug( 'kernel-content-object-copy', 'Copy start, all versions=' . ( $allVersions ? 'true' : 'false' ), 'copy' ); 01463 $user = eZUser::currentUser(); 01464 $userID = $user->attribute( 'contentobject_id' ); 01465 01466 $contentObject = clone $this; 01467 $contentObject->setAttribute( 'current_version', 1 ); 01468 $contentObject->setAttribute( 'owner_id', $userID ); 01469 01470 // Set new unique remote_id 01471 $newRemoteID = md5( (string)mt_rand() . (string)time() ); 01472 $contentObject->setAttribute( 'remote_id', $newRemoteID ); 01473 01474 $db = eZDB::instance(); 01475 $db->begin(); 01476 $contentObject->store(); 01477 01478 $contentObject->setName( $this->attribute('name') ); 01479 eZDebugSetting::writeDebug( 'kernel-content-object-copy', $contentObject, 'contentObject' ); 01480 01481 01482 $versionList = array(); 01483 if ( $allVersions ) 01484 { 01485 $versions = $this->versions(); 01486 foreach( $versions as $version ) 01487 { 01488 $versionList[$version->attribute( 'version' )] = $version; 01489 } 01490 } 01491 else 01492 { 01493 $versionList[1] = $this->currentVersion(); 01494 } 01495 01496 foreach ( $versionList as $versionNumber => $currentContentObjectVersion ) 01497 { 01498 $currentVersionNumber = $currentContentObjectVersion->attribute( 'version' ); 01499 $contentObject->setName( $currentContentObjectVersion->name(), $versionNumber ); 01500 foreach( $contentObject->translationStringList() as $languageCode ) 01501 { 01502 $contentObject->setName( $currentContentObjectVersion->name( false, $languageCode ), $versionNumber, $languageCode ); 01503 } 01504 01505 $contentObjectVersion = $this->copyVersion( $contentObject, $currentContentObjectVersion, 01506 $versionNumber, $contentObject->attribute( 'id' ), 01507 false ); 01508 01509 if ( $currentVersionNumber == $this->attribute( 'current_version' ) ) 01510 { 01511 $parentMap = array(); 01512 $copiedNodeAssignmentList = $contentObjectVersion->attribute( 'node_assignments' ); 01513 foreach ( $copiedNodeAssignmentList as $copiedNodeAssignment ) 01514 { 01515 $parentMap[$copiedNodeAssignment->attribute( 'parent_node' )] = $copiedNodeAssignment; 01516 } 01517 // Create node-assignment from all current published nodes 01518 $nodes = $this->assignedNodes(); 01519 foreach( $nodes as $node ) 01520 { 01521 $remoteID = 0; 01522 // Remove assignments which conflicts with existing nodes, but keep remote_id 01523 if ( isset( $parentMap[$node->attribute( 'parent_node_id' )] ) ) 01524 { 01525 $copiedNodeAssignment = $parentMap[$node->attribute( 'parent_node_id' )]; 01526 unset( $parentMap[$node->attribute( 'parent_node_id' )] ); 01527 $remoteID = $copiedNodeAssignment->attribute( 'remote_id' ); 01528 $copiedNodeAssignment->purge(); 01529 } 01530 $newNodeAssignment = $contentObjectVersion->assignToNode( $node->attribute( 'parent_node_id' ), $node->attribute( 'is_main' ), 0, 01531 $node->attribute( 'sort_field' ), $node->attribute( 'sort_order' ), 01532 $remoteID ); 01533 } 01534 } 01535 01536 eZDebugSetting::writeDebug( 'kernel-content-object-copy', $contentObjectVersion, 'Copied version' ); 01537 } 01538 01539 // Set version number 01540 if ( $allVersions ) 01541 $contentObject->setAttribute( 'current_version', $this->attribute( 'current_version' ) ); 01542 01543 $contentObject->setAttribute( 'status', eZContentObject::STATUS_DRAFT ); 01544 01545 $contentObject->store(); 01546 01547 $db->commit(); 01548 01549 eZDebugSetting::writeDebug( 'kernel-content-object-copy', 'Copy done', 'copy' ); 01550 return $contentObject; 01551 } 01552 01553 /*! 01554 Reverts the object to the given version. All versions newer then the given version will 01555 be deleted. 01556 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 01557 the calls within a db transaction; thus within db->begin and db->commit. 01558 */ 01559 function revertTo( $version ) 01560 { 01561 $db = eZDB::instance(); 01562 $db->begin(); 01563 01564 // Delete stored attribute from other tables 01565 $contentobjectAttributes = $this->allContentObjectAttributes( $this->ID ); 01566 foreach ( $contentobjectAttributes as $contentobjectAttribute ) 01567 { 01568 $contentobjectAttributeVersion = $contentobjectAttribute->attribute("version"); 01569 if( $contentobjectAttributeVersion > $version ) 01570 { 01571 $classAttribute = $contentobjectAttribute->contentClassAttribute(); 01572 $dataType = $classAttribute->dataType(); 01573 $dataType->deleteStoredObjectAttribute( $contentobjectAttribute, $contentobjectAttributeVersion ); 01574 } 01575 } 01576 $version =(int) $version; 01577 $db->query( "DELETE FROM ezcontentobject_attribute 01578 WHERE contentobject_id='$this->ID' AND version>'$version'" ); 01579 01580 $db->query( "DELETE FROM ezcontentobject_version 01581 WHERE contentobject_id='$this->ID' AND version>'$version'" ); 01582 01583 $db->query( "DELETE FROM eznode_assignment 01584 WHERE contentobject_id='$this->ID' AND contentobject_version > '$version'" ); 01585 01586 $this->CurrentVersion = $version; 01587 $this->store(); 01588 $db->commit(); 01589 } 01590 01591 /*! 01592 Copies the given version of the object and creates a new current version. 01593 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 01594 the calls within a db transaction; thus within db->begin and db->commit. 01595 */ 01596 function copyRevertTo( $version, $language = false ) 01597 { 01598 $versionObject = $this->createNewVersionIn( $language, false, $version ); 01599 01600 return $versionObject->attribute( 'version' ); 01601 } 01602 01603 static function fixReverseRelations( $objectID, $mode = false ) 01604 { 01605 $db = eZDB::instance(); 01606 $objectID = (int) $objectID; 01607 01608 // Finds all the attributes that store relations to the given object. 01609 $result = $db->arrayQuery( "SELECT attr.* 01610 FROM ezcontentobject_link link, 01611 ezcontentobject_attribute attr 01612 WHERE link.from_contentobject_id=attr.contentobject_id AND 01613 link.from_contentobject_version=attr.version AND 01614 link.contentclassattribute_id=attr.contentclassattribute_id AND 01615 link.to_contentobject_id=$objectID" ); 01616 if ( count( $result ) > 0 ) 01617 { 01618 include_once( "kernel/classes/ezcontentcachemanager.php" ); 01619 foreach( $result as $row ) 01620 { 01621 $attr = new eZContentObjectAttribute( $row ); 01622 $dataType = $attr->dataType(); 01623 $dataType->fixRelatedObjectItem( $attr, $objectID, $mode ); 01624 eZContentCacheManager::clearObjectViewCache( $attr->attribute( 'contentobject_id' ), true ); 01625 } 01626 } 01627 } 01628 01629 function removeReverseRelations( $objectID ) 01630 { 01631 $db = eZDB::instance(); 01632 $objectID = (int) $objectID; 01633 // Get list of objects referring to this one. 01634 $relatingObjects = $this->reverseRelatedObjectList( false, 0, false, array( 'AllRelations' => true ) ); 01635 01636 // Finds all the attributes that store relations to the given object. 01637 01638 $result = $db->arrayQuery( "SELECT attr.* 01639 FROM ezcontentobject_link link, 01640 ezcontentobject_attribute attr 01641 WHERE link.from_contentobject_id=attr.contentobject_id AND 01642 link.from_contentobject_version=attr.version AND 01643 link.contentclassattribute_id=attr.contentclassattribute_id AND 01644 link.to_contentobject_id=$objectID" ); 01645 01646 // Remove references from XML. 01647 if ( count( $result ) > 0 ) 01648 { 01649 //include_once( "kernel/classes/ezcontentcachemanager.php" ); 01650 foreach( $result as $row ) 01651 { 01652 $attr = new eZContentObjectAttribute( $row ); 01653 $dataType = $attr->dataType(); 01654 $dataType->removeRelatedObjectItem( $attr, $objectID ); 01655 eZContentCacheManager::clearObjectViewCache( $attr->attribute( 'contentobject_id' ), true ); 01656 $attr->storeData(); 01657 } 01658 } 01659 01660 // Remove references in ezcontentobject_link. 01661 foreach ( $relatingObjects as $fromObject ) 01662 { 01663 $fromObject->removeContentObjectRelation( $this->attribute( 'id' ), false, false ); 01664 } 01665 } 01666 01667 /*! 01668 If nodeID is not given, this function will remove object from database. All versions and translations of this object will be lost. 01669 Otherwise, it will check node assignment and only delete the object from this node if it was assigned to other nodes as well. 01670 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 01671 the calls within a db transaction; thus within db->begin and db->commit. 01672 */ 01673 function purge() 01674 { 01675 $delID = $this->ID; 01676 // Who deletes which content should be logged. 01677 //include_once( "kernel/classes/ezaudit.php" ); 01678 eZAudit::writeAudit( 'content-delete', array( 'Object ID' => $delID, 'Content Name' => $this->attribute( 'name' ), 01679 'Comment' => 'Purged the current object: eZContentObject::purge()' ) ); 01680 01681 $db = eZDB::instance(); 01682 01683 $db->begin(); 01684 01685 $contentobjectAttributes = $this->allContentObjectAttributes( $delID ); 01686 01687 foreach ( $contentobjectAttributes as $contentobjectAttribute ) 01688 { 01689 $dataType = $contentobjectAttribute->dataType(); 01690 if ( !$dataType ) 01691 continue; 01692 $dataType->deleteStoredObjectAttribute( $contentobjectAttribute ); 01693 } 01694 01695 //include_once( 'kernel/classes/ezinformationcollection.php' ); 01696 eZInformationCollection::removeContentObject( $delID ); 01697 01698 //include_once( 'kernel/classes/ezcontentobjecttrashnode.php' ); 01699 eZContentObjectTrashNode::purgeForObject( $delID ); 01700 01701 $db->query( "DELETE FROM ezcontentobject_tree 01702 WHERE contentobject_id='$delID'" ); 01703 01704 $db->query( "DELETE FROM ezcontentobject_attribute 01705 WHERE contentobject_id='$delID'" ); 01706 01707 $db->query( "DELETE FROM ezcontentobject_version 01708 WHERE contentobject_id='$delID'" ); 01709 01710 $db->query( "DELETE FROM ezcontentobject_name 01711 WHERE contentobject_id='$delID'" ); 01712 01713 $db->query( "DELETE FROM ezcontentobject 01714 WHERE id='$delID'" ); 01715 01716 $db->query( "DELETE FROM eznode_assignment 01717 WHERE contentobject_id = '$delID'" ); 01718 01719 $db->query( "DELETE FROM ezuser_role 01720 WHERE contentobject_id = '$delID'" ); 01721 01722 $db->query( "DELETE FROM ezuser_discountrule 01723 WHERE contentobject_id = '$delID'" ); 01724 01725 eZContentObject::fixReverseRelations( $delID, 'remove' ); 01726 01727 //include_once( "kernel/classes/ezsearch.php" ); 01728 eZSearch::removeObject( $this ); 01729 01730 // Check if deleted object is in basket/wishlist 01731 $sql = 'SELECT DISTINCT ezproductcollection_item.productcollection_id 01732 FROM ezbasket, ezwishlist, ezproductcollection_item 01733 WHERE ( ezproductcollection_item.productcollection_id=ezbasket.productcollection_id OR 01734 ezproductcollection_item.productcollection_id=ezwishlist.productcollection_id ) AND 01735 ezproductcollection_item.contentobject_id=' . $delID; 01736 $rows = $db->arrayQuery( $sql ); 01737 if ( count( $rows ) > 0 ) 01738 { 01739 $countElements = 50; 01740 $deletedArray = array(); 01741 // Create array of productCollectionID will be removed from ezwishlist and ezproductcollection_item 01742 foreach ( $rows as $row ) 01743 { 01744 $deletedArray[] = $row['productcollection_id']; 01745 } 01746 // Split $deletedArray into several arrays with $countElements values 01747 $splitted = array_chunk( $deletedArray, $countElements ); 01748 //include_once( "kernel/classes/ezproductcollectionitem.php" ); 01749 //include_once( "kernel/classes/ezwishlist.php" ); 01750 // Remove eZProductCollectionItem and eZWishList 01751 foreach ( $splitted as $value ) 01752 { 01753 eZPersistentObject::removeObject( eZProductCollectionItem::definition(), array( 'productcollection_id' => array( $value, '' ) ) ); 01754 eZPersistentObject::removeObject( eZWishList::definition(), array( 'productcollection_id' => array( $value, '' ) ) ); 01755 } 01756 } 01757 $db->query( 'UPDATE ezproductcollection_item 01758 SET contentobject_id = 0 01759 WHERE contentobject_id = ' . $delID ); 01760 01761 // Cleanup relations in two steps to avoid locking table for to long 01762 $db->query( "DELETE FROM ezcontentobject_link 01763 WHERE from_contentobject_id = '$delID'" ); 01764 01765 $db->query( "DELETE FROM ezcontentobject_link 01766 WHERE to_contentobject_id = '$delID'" ); 01767 01768 // Cleanup properties: LastVisit, Creator, Owner 01769 $db->query( "DELETE FROM ezuservisit 01770 WHERE user_id = '$delID'" ); 01771 01772 $db->query( "UPDATE ezcontentobject_version 01773 SET creator_id = 0 01774 WHERE creator_id = '$delID'" ); 01775 01776 $db->query( "UPDATE ezcontentobject 01777 SET owner_id = 0 01778 WHERE owner_id = '$delID'" ); 01779 01780 //include_once( "kernel/classes/ezworkflowtype.php" ); 01781 if ( isset( $GLOBALS["eZWorkflowTypeObjects"] ) and is_array( $GLOBALS["eZWorkflowTypeObjects"] ) ) 01782 { 01783 $registeredTypes =& $GLOBALS["eZWorkflowTypeObjects"]; 01784 } 01785 else 01786 { 01787 $registeredTypes = eZWorkflowType::fetchRegisteredTypes(); 01788 } 01789 01790 // Cleanup ezworkflow_event etc... 01791 foreach ( array_keys( $registeredTypes ) as $registeredTypeKey ) 01792 { 01793 $registeredType = $registeredTypes[$registeredTypeKey]; 01794 $registeredType->cleanupAfterRemoving( array( 'DeleteContentObject' => $delID ) ); 01795 } 01796 01797 $db->commit(); 01798 } 01799 01800 /*! 01801 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 01802 the calls within a db transaction; thus within db->begin and db->commit. 01803 */ 01804 function removeThis( $nodeID = null ) 01805 { 01806 $delID = $this->ID; 01807 01808 // Who deletes which content should be logged. 01809 //include_once( "kernel/classes/ezaudit.php" ); 01810 eZAudit::writeAudit( 'content-delete', array( 'Object ID' => $delID, 'Content Name' => $this->attribute( 'name' ), 01811 'Comment' => 'Setted archived status for the current object: eZContentObject::remove()' ) ); 01812 01813 $nodes = $this->attribute( 'assigned_nodes' ); 01814 01815 //include_once( "kernel/classes/ezsearch.php" ); 01816 if ( $nodeID === null or count( $nodes ) <= 1 ) 01817 { 01818 $db = eZDB::instance(); 01819 $db->begin(); 01820 $mainNodeKey = false; 01821 foreach ( $nodes as $key => $node ) 01822 { 01823 if ( $node->attribute( 'main_node_id' ) == $node->attribute( 'node_id' ) ) 01824 { 01825 $mainNodeKey = $key; 01826 } 01827 else 01828 { 01829 $node->removeThis(); 01830 } 01831 } 01832 01833 if ( $mainNodeKey !== false ) 01834 { 01835 $nodes[$mainNodeKey]->removeNodeFromTree( true ); 01836 } 01837 01838 01839 $this->setAttribute( 'status', eZContentObject::STATUS_ARCHIVED ); 01840 eZSearch::removeObject( $this ); 01841 $this->store(); 01842 eZContentObject::fixReverseRelations( $delID, 'trash' ); 01843 // Delete stored attribute from other tables 01844 $db->commit(); 01845 01846 } 01847 else if ( $nodeID !== null ) 01848 { 01849 $node = eZContentObjectTreeNode::fetch( $nodeID , false ); 01850 if ( is_object( $node ) ) 01851 { 01852 if ( $node->attribute( 'main_node_id' ) == $nodeID ) 01853 { 01854 $db = eZDB::instance(); 01855 $db->begin(); 01856 foreach ( $additionalNodes as $additionalNode ) 01857 { 01858 if ( $additionalNode->attribute( 'node_id' ) != $node->attribute( 'main_node_id' ) ) 01859 { 01860 $additionalNode->remove(); 01861 } 01862 } 01863 01864 $node->removeNodeFromTree( true ); 01865 $this->setAttribute( 'status', eZContentObject::STATUS_ARCHIVED ); 01866 eZSearch::removeObject( $this ); 01867 $this->store(); 01868 eZContentObject::fixReverseRelations( $delID, 'trash' ); 01869 $db->commit(); 01870 } 01871 else 01872 { 01873 eZContentObjectTreeNode::removeNode( $nodeID ); 01874 } 01875 } 01876 } 01877 else 01878 { 01879 eZContentObjectTreeNode::removeNode( $nodeID ); 01880 } 01881 } 01882 01883 /*! 01884 Removes old internal drafts by the specified user associated with this content object. 01885 Only internal drafts older than 1 day will be considered. 01886 \param $userID The ID of the user to cleanup for, if \c false it will use the current user. 01887 */ 01888 function cleanupInternalDrafts( $userID = false, $timeDuration = 86400 ) // default time duration for internal drafts 60*60*24 seconds (1 day) 01889 { 01890 if ( !is_numeric( $timeDuration ) || 01891 $timeDuration < 0 ) 01892 { 01893 eZDebug::writeError( "The time duration must be a positive numeric value (timeDuration = $timeDuration)", 01894 'eZContentObject::cleanupInternalDrafts()' ); 01895 return; 01896 } 01897 01898 if ( $userID === false ) 01899 { 01900 $userID = eZUser::currentUserID(); 01901 } 01902 // Fetch all draft/temporary versions by specified user 01903 $parameters = array( 'conditions' => array( 'status' => eZContentObjectVersion::STATUS_INTERNAL_DRAFT, 01904 'creator_id' => $userID ) ); 01905 // Remove temporary drafts which are old. 01906 $expiryTime = time() - $timeDuration; // only remove drafts older than time duration (default is 1 day) 01907 foreach ( $this->versions( true, $parameters ) as $possibleVersion ) 01908 { 01909 if ( $possibleVersion->attribute( 'modified' ) < $expiryTime ) 01910 { 01911 $possibleVersion->removeThis(); 01912 } 01913 } 01914 } 01915 01916 /*! 01917 \static 01918 Removes all old internal drafts by the specified user. 01919 Only internal drafts older than 1 day will be considered. 01920 \param $userID The ID of the user to cleanup for, if \c false it will use the current user. 01921 */ 01922 static function cleanupAllInternalDrafts( $userID = false, $timeDuration = 86400 ) // default time duration for internal drafts 60*60*24 seconds (1 day) 01923 { 01924 if ( !is_numeric( $timeDuration ) || 01925 $timeDuration < 0 ) 01926 { 01927 eZDebug::writeError( "The time duration must be a positive numeric value (timeDuration = $timeDuration)", 01928 'eZContentObject::cleanupAllInternalDrafts()' ); 01929 return; 01930 } 01931 01932 01933 if ( $userID === false ) 01934 { 01935 $userID = eZUser::currentUserID(); 01936 } 01937 // Remove all internal drafts 01938 // include_once( 'kernel/classes/ezcontentobjectversion.php' ); 01939 $untouchedDrafts = eZContentObjectVersion::fetchForUser( $userID, eZContentObjectVersion::STATUS_INTERNAL_DRAFT ); 01940 01941 $expiryTime = time() - $timeDuration; // only remove drafts older than time duration (default is 1 day) 01942 foreach ( $untouchedDrafts as $untouchedDraft ) 01943 { 01944 if ( $untouchedDraft->attribute( 'modified' ) < $expiryTime ) 01945 { 01946 $untouchedDraft->removeThis(); 01947 } 01948 } 01949 } 01950 01951 /* 01952 Fetch all attributes of all versions belongs to a contentObject. 01953 */ 01954 function allContentObjectAttributes( $contentObjectID, $asObject = true ) 01955 { 01956 return eZPersistentObject::fetchObjectList( eZContentObjectAttribute::definition(), 01957 null, 01958 array("contentobject_id" => $contentObjectID ), 01959 null, 01960 null, 01961 $asObject ); 01962 } 01963 01964 /*! 01965 Fetches the attributes for the current published version of the object. 01966 TODO: fix using of $asObject parameter, 01967 fix condition for getting attribute from cache, 01968 probably need to move method to eZContentObjectVersion class 01969 */ 01970 function contentObjectAttributes( $asObject = true, $version = false, $language = false, $contentObjectAttributeID = false, $distinctItemsOnly = false ) 01971 { 01972 $db = eZDB::instance(); 01973 if ( $version == false ) 01974 { 01975 $version = $this->CurrentVersion; 01976 } 01977 else 01978 { 01979 $version = (int) $version; 01980 } 01981 01982 if ( $language === false ) 01983 { 01984 $language = $this->CurrentLanguage; 01985 } 01986 01987 if ( is_string( $language ) ) 01988 $language = $db->escapeString( $language ); 01989 01990 if ( $contentObjectAttributeID !== false ) 01991 $contentObjectAttributeID =(int) $contentObjectAttributeID; 01992 // print( "Attributes fetch $this->ID, $version" ); 01993 01994 if ( !$language || !isset( $this->ContentObjectAttributes[$version][$language] ) ) 01995 { 01996 // print( "uncached<br>" ); 01997 $versionText = "AND\n ezcontentobject_attribute.version = '$version'"; 01998 if ( $language ) 01999 { 02000 $languageText = "AND\n ezcontentobject_attribute.language_code = '$language'"; 02001 } 02002 else 02003 { 02004 $languageText = "AND\n ".eZContentLanguage::sqlFilter( 'ezcontentobject_attribute', 'ezcontentobject_version' ); 02005 } 02006 $attributeIDText = false; 02007 if ( $contentObjectAttributeID ) 02008 $attributeIDText = "AND\n ezcontentobject_attribute.id = '$contentObjectAttributeID'"; 02009 $distinctText = false; 02010 if ( $distinctItemsOnly ) 02011 $distinctText = "GROUP BY ezcontentobject_attribute.id"; 02012 $query = "SELECT ezcontentobject_attribute.*, ezcontentclass_attribute.identifier as identifier FROM 02013 ezcontentobject_attribute, ezcontentclass_attribute, ezcontentobject_version 02014 WHERE 02015 ezcontentclass_attribute.version = '0' AND 02016 ezcontentclass_attribute.id = ezcontentobject_attribute.contentclassattribute_id AND 02017 ezcontentobject_version.contentobject_id = '$this->ID' AND 02018 ezcontentobject_version.version = '$version' AND 02019 ezcontentobject_attribute.contentobject_id = '$this->ID' $versionText $languageText $attributeIDText 02020 $distinctText 02021 ORDER BY 02022 ezcontentclass_attribute.placement ASC, 02023 ezcontentobject_attribute.language_code ASC"; 02024 02025 $attributeArray = $db->arrayQuery( $query ); 02026 02027 if ( !$language && $attributeArray ) 02028 { 02029 $language = $attributeArray[0]['language_code']; 02030 $this->CurrentLanguage = $language; 02031 } 02032 02033 $returnAttributeArray = array(); 02034 foreach ( $attributeArray as $attribute ) 02035 { 02036 $attr = new eZContentObjectAttribute( $attribute ); 02037 $attr->setContentClassAttributeIdentifier( $attribute['identifier'] ); 02038 $returnAttributeArray[] = $attr; 02039 } 02040 02041 if ( $language !== null and $version !== null ) 02042 { 02043 $this->ContentObjectAttributes[$version][$language] = $returnAttributeArray; 02044 } 02045 } 02046 else 02047 { 02048 // print( "Cached<br>" ); 02049 $returnAttributeArray = $this->ContentObjectAttributes[$version][$language]; 02050 } 02051 02052 return $returnAttributeArray; 02053 } 02054 02055 /*! 02056 Initializes the cached copy of the content object attributes for the given version and language 02057 */ 02058 function setContentObjectAttributes( &$attributes, $version, $language ) 02059 { 02060 $this->ContentObjectAttributes[$version][$language] = $attributes; 02061 } 02062 02063 /*! 02064 \static 02065 Fetches the attributes for an array of objects. The objectList parameter 02066 contains an array of object id's , versions and language to fetch attributes from. 02067 */ 02068 static function fillNodeListAttributes( $nodeList, $asObject = true ) 02069 { 02070 $db = eZDB::instance(); 02071 02072 if ( count( $nodeList ) > 0 ) 02073 { 02074 $objectArray = array(); 02075 $tmpLanguageObjectList = array(); 02076 $whereSQL = ''; 02077 $count = count( $nodeList ); 02078 $i = 0; 02079 foreach ( $nodeList as $node ) 02080 { 02081 $object = $node->attribute( 'object' ); 02082 02083 $language = $object->currentLanguage(); 02084 $tmpLanguageObjectList[$object->attribute( 'id' )] = $language; 02085 $objectArray = array( 'id' => $object->attribute( 'id' ), 02086 'language' => $language, 02087 'version' => $node->attribute( 'contentobject_version' ) ); 02088 02089 $whereSQL .= "( ezcontentobject_attribute.version = '" . $node->attribute( 'contentobject_version' ) . "' AND 02090 ezcontentobject_attribute.contentobject_id = '" . $object->attribute( 'id' ) . "' AND 02091 ezcontentobject_attribute.language_code = '" . $language . "' ) "; 02092 02093 $i++; 02094 if ( $i < $count ) 02095 $whereSQL .= ' OR '; 02096 } 02097 02098 $query = "SELECT ezcontentobject_attribute.*, ezcontentclass_attribute.identifier as identifier FROM 02099 ezcontentobject_attribute, ezcontentclass_attribute 02100 WHERE 02101 ezcontentclass_attribute.version = '0' AND 02102 ezcontentclass_attribute.id = ezcontentobject_attribute.contentclassattribute_id AND 02103 ( $whereSQL ) 02104 ORDER BY 02105 ezcontentobject_attribute.contentobject_id, ezcontentclass_attribute.placement ASC"; 02106 02107 $attributeArray = $db->arrayQuery( $query ); 02108 02109 $tmpAttributeObjectList = array(); 02110 $returnAttributeArray = array(); 02111 foreach ( $attributeArray as $attribute ) 02112 { 02113 $attr = new eZContentObjectAttribute( $attribute ); 02114 $attr->setContentClassAttributeIdentifier( $attribute['identifier'] ); 02115 02116 $tmpAttributeObjectList[$attr->attribute( 'contentobject_id' )][] = $attr; 02117 } 02118 02119 foreach ( $nodeList as $node ) 02120 { 02121 $object = $node->attribute( 'object' ); 02122 $object->setContentObjectAttributes( $tmpAttributeObjectList[$object->attribute( 'id' )], 02123 $node->attribute( 'contentobject_version' ), 02124 $tmpLanguageObjectList[$object->attribute( 'id' )] ); 02125 $node->setContentObject( $object ); 02126 } 02127 } 02128 } 02129 02130 function resetInputRelationList() 02131 { 02132 $this->InputRelationList = array( eZContentObject::RELATION_EMBED => array(), 02133 eZContentObject::RELATION_LINK => array() ); 02134 } 02135 02136 function appendInputRelationList( $addingIDList, $relationType ) 02137 { 02138 if ( !is_array( $addingIDList ) ) 02139 { 02140 $addingIDList = array( ( int ) $addingIDList ); 02141 } 02142 elseif ( !count( $addingIDList ) ) 02143 { 02144 return; 02145 } 02146 $relationType = ( int ) $relationType; 02147 if ( !$this->InputRelationList ) 02148 { 02149 $this->resetInputRelationList(); 02150 } 02151 02152 foreach ( array_keys( $this->InputRelationList ) as $inputRelationType ) 02153 { 02154 if ( $inputRelationType & $relationType ) 02155 { 02156 $this->InputRelationList[$inputRelationType] = array_merge( $this->InputRelationList[$inputRelationType], $addingIDList ); 02157 } 02158 } 02159 } 02160 02161 function commitInputRelations( $editVersion ) 02162 { 02163 foreach ( $this->InputRelationList as $relationType => $relatedObjectIDArray ) 02164 { 02165 $oldRelatedObjectArray = $this->relatedObjects( $editVersion, false, 0, false, array( 'AllRelations' => $relationType ) ); 02166 02167 foreach ( $oldRelatedObjectArray as $oldRelatedObject ) 02168 { 02169 $oldRelatedObjectID = $oldRelatedObject->ID; 02170 if ( !in_array( $oldRelatedObjectID, $relatedObjectIDArray ) ) 02171 { 02172 $this->removeContentObjectRelation( $oldRelatedObjectID, $editVersion, 0, $relationType ); 02173 } 02174 $relatedObjectIDArray = array_diff( $relatedObjectIDArray, array( $oldRelatedObjectID ) ); 02175 } 02176 02177 foreach ( $relatedObjectIDArray as $relatedObjectID ) 02178 { 02179 $this->addContentObjectRelation( $relatedObjectID, $editVersion, 0, $relationType ); 02180 } 02181 } 02182 return true; 02183 } 02184 02185 function validateInput( $contentObjectAttributes, $attributeDataBaseName, 02186 $inputParameters = false, $parameters = array() ) 02187 { 02188 $result = array( 'unvalidated-attributes' => array(), 02189 'validated-attributes' => array(), 02190 'status-map' => array(), 02191 'require-fixup' => false, 02192 'input-validated' => true ); 02193 $parameters = array_merge( array( 'prefix-name' => false ), 02194 $parameters ); 02195 if ( $inputParameters ) 02196 { 02197 $result['unvalidated-attributes'] =& $inputParameters['unvalidated-attributes']; 02198 $result['validated-attributes'] =& $inputParameters['validated-attributes']; 02199 } 02200 $unvalidatedAttributes =& $result['unvalidated-attributes']; 02201 $validatedAttributes =& $result['validated-attributes']; 02202 $statusMap =& $result['status-map']; 02203 if ( !$inputParameters ) 02204 $inputParameters = array( 'unvalidated-attributes' => &$unvalidatedAttributes, 02205 'validated-attributes' => &$validatedAttributes ); 02206 $requireFixup =& $result['require-fixup']; 02207 $inputValidated =& $result['input-validated']; 02208 $http = eZHTTPTool::instance(); 02209 02210 $this->resetInputRelationList(); 02211 02212 $editVersion = null; 02213 $defaultLanguage = $this->initialLanguageCode(); 02214 foreach( $contentObjectAttributes as $contentObjectAttribute ) 02215 { 02216 $contentClassAttribute = $contentObjectAttribute->contentClassAttribute(); 02217 $editVersion = $contentObjectAttribute->attribute('version'); 02218 02219 // Check if this is a translation 02220 $currentLanguage = $contentObjectAttribute->attribute( 'language_code' ); 02221 02222 $isTranslation = false; 02223 if ( $currentLanguage != $defaultLanguage ) 02224 $isTranslation = true; 02225 02226 // If current attribute is a translation 02227 // Check if this attribute can be translated 02228 // If not do not validate, since the input will be copyed from the original 02229 $doNotValidate = false; 02230 if ( $isTranslation ) 02231 { 02232 if ( !$contentClassAttribute->attribute( 'can_translate' ) ) 02233 $doNotValidate = true; 02234 } 02235 02236 if ( $doNotValidate == true ) 02237 { 02238 $status = eZInputValidator::STATE_ACCEPTED; 02239 } 02240 else 02241 { 02242 $status = $contentObjectAttribute->validateInput( $http, $attributeDataBaseName, 02243 $inputParameters, $parameters ); 02244 } 02245 $statusMap[$contentObjectAttribute->attribute( 'id' )] = array( 'value' => $status, 02246 'attribute' => $contentObjectAttribute ); 02247 02248 if ( $status == eZInputValidator::STATE_INTERMEDIATE ) 02249 $requireFixup = true; 02250 else if ( $status == eZInputValidator::STATE_INVALID ) 02251 { 02252 $inputValidated = false; 02253 $dataType = $contentObjectAttribute->dataType(); 02254 $attributeName = $dataType->attribute( 'information' ); 02255 $attributeName = $attributeName['name']; 02256 $description = $contentObjectAttribute->attribute( 'validation_error' ); 02257 $validationNameArray[] = $contentClassAttribute->attribute( 'name' ); 02258 $validationName = implode( '->', $validationNameArray ); 02259 $hasValidationError = $contentObjectAttribute->attribute( 'has_validation_error' ); 02260 if ( $hasValidationError ) 02261 { 02262 if ( !$description ) 02263 $description = false; 02264 $validationNameArray = array(); 02265 if ( $parameters['prefix-name'] ) 02266 $validationNameArray = $parameters['prefix-name']; 02267 } 02268 else 02269 { 02270 if ( !$description ) 02271 $description = 'unknown error'; 02272 } 02273 $unvalidatedAttributes[] = array( 'id' => $contentObjectAttribute->attribute( 'id' ), 02274 'identifier' => $contentClassAttribute->attribute( 'identifier' ), 02275 'name' => $validationName, 02276 'description' => $description ); 02277 } 02278 else if ( $status == eZInputValidator::STATE_ACCEPTED ) 02279 { 02280 $dataType = $contentObjectAttribute->dataType(); 02281 $attributeName = $dataType->attribute( 'information' ); 02282 $attributeName = $attributeName['name']; 02283 if ( $contentObjectAttribute->attribute( 'validation_log' ) != null ) 02284 { 02285 $description = $contentObjectAttribute->attribute( 'validation_log' ); 02286 if ( !$description ) 02287 $description = false; 02288 $validationName = $contentClassAttribute->attribute( 'name' ); 02289 if ( $parameters['prefix-name'] ) 02290 $validationName = $parameters['prefix-name'] . '->' . $validationName; 02291 $validatedAttributes[] = array( 'id' => $contentObjectAttribute->attribute( 'id' ), 02292 'identifier' => $contentClassAttribute->attribute( 'identifier' ), 02293 'name' => $validationName, 02294 'description' => $description ); 02295 } 02296 } 02297 } 02298 02299 if ( $editVersion !== null ) 02300 { 02301 $this->commitInputRelations( $editVersion ); 02302 } 02303 $this->resetInputRelationList(); 02304 02305 return $result; 02306 } 02307 02308 function fixupInput( $contentObjectAttributes, $attributeDataBaseName ) 02309 { 02310 $http = eZHTTPTool::instance(); 02311 foreach ( $contentObjectAttributes as $contentObjectAttribute ) 02312 { 02313 $contentObjectAttribute->fixupInput( $http, $attributeDataBaseName ); 02314 } 02315 } 02316 02317 function fetchInput( $contentObjectAttributes, $attributeDataBaseName, 02318 $customActionAttributeArray, $customActionParameters ) 02319 { 02320 // Global variable to cache datamaps 02321 global $eZContentObjectDataMapCache; 02322 02323 $result = array( 'attribute-input-map' => array() ); 02324 $attributeInputMap =& $result['attribute-input-map']; 02325 $http = eZHTTPTool::instance(); 02326 02327 $defaultLanguage = $this->initialLanguageCode(); 02328 02329 $this->fetchDataMap(); 02330 foreach ( $contentObjectAttributes as $contentObjectAttribute ) 02331 { 02332 $contentClassAttribute = $contentObjectAttribute->contentClassAttribute(); 02333 02334 // Check if this is a translation 02335 $currentLanguage = $contentObjectAttribute->attribute( 'language_code' ); 02336 02337 $isTranslation = false; 02338 if ( $currentLanguage != $defaultLanguage ) 02339 $isTranslation = true; 02340 02341 // If current attribute is an un-translateable translation, input should not be fetched 02342 $fetchInput = true; 02343 if ( $isTranslation == true ) 02344 { 02345 if ( !$contentClassAttribute->attribute( 'can_translate' ) ) 02346 { 02347 $fetchInput = false; 02348 } 02349 } 02350 02351 // Do not handle input for non-translateable attributes. 02352 // Input will be copyed from the std. translation on storage 02353 if ( $fetchInput ) 02354 { 02355 if ( $contentObjectAttribute->fetchInput( $http, $attributeDataBaseName ) ) 02356 { 02357 $attributeInputMap[$contentObjectAttribute->attribute('id')] = true; 02358 02359 // we fill the internal data map cache for the current version here with the attributes of the new version 02360 // this will make the data map cache inconsistent, but this is required to make it possible to use $object.data_map 02361 // in content/edit templates 02362 $attributeIdentifier = $contentObjectAttribute->attribute( 'contentclass_attribute_identifier' ); 02363 $eZContentObjectDataMapCache[$this->ID][$this->CurrentVersion][$currentLanguage][$attributeIdentifier] = $contentObjectAttribute; 02364 $this->DataMap[$this->CurrentVersion][$currentLanguage][$attributeIdentifier] = $contentObjectAttribute; 02365 } 02366 02367 // Custom Action Code 02368 $this->handleCustomHTTPActions( $contentObjectAttribute, $attributeDataBaseName, 02369 $customActionAttributeArray, $customActionParameters ); 02370 } 02371 02372 } 02373 return $result; 02374 } 02375 02376 function handleCustomHTTPActions( $contentObjectAttribute, $attributeDataBaseName, 02377 $customActionAttributeArray, $customActionParameters ) 02378 { 02379 $http = eZHTTPTool::instance(); 02380 $customActionParameters['base_name'] = $attributeDataBaseName; 02381 if ( isset( $customActionAttributeArray[$contentObjectAttribute->attribute( 'id' )] ) ) 02382 { 02383 $customActionAttributeID = $customActionAttributeArray[$contentObjectAttribute->attribute( 'id' )]['id']; 02384 $customAction = $customActionAttributeArray[$contentObjectAttribute->attribute( 'id' )]['value']; 02385 $contentObjectAttribute->customHTTPAction( $http, $customAction, $customActionParameters ); 02386 } 02387 02388 $contentObjectAttribute->handleCustomHTTPActions( $http, $attributeDataBaseName, 02389 $customActionAttributeArray, $customActionParameters ); 02390 } 02391 02392 function handleAllCustomHTTPActions( $attributeDataBaseName, 02393 $customActionAttributeArray, $customActionParameters, 02394 $objectVersion = false ) 02395 { 02396 $http = eZHTTPTool::instance(); 02397 $contentObjectAttributes = $this->contentObjectAttributes( true, $objectVersion ); 02398 $oldAttributeDataBaseName = $customActionParameters['base_name']; 02399 $customActionParameters['base_name'] = $attributeDataBaseName; 02400 foreach( $contentObjectAttributes as $contentObjectAttribute ) 02401 { 02402 if ( isset( $customActionAttributeArray[$contentObjectAttribute->attribute( 'id' )] ) ) 02403 { 02404 $customActionAttributeID = $customActionAttributeArray[$contentObjectAttribute->attribute( 'id' )]['id']; 02405 $customAction = $customActionAttributeArray[$contentObjectAttribute->attribute( 'id' )]['value']; 02406 $contentObjectAttribute->customHTTPAction( $http, $customAction, $customActionParameters ); 02407 } 02408 02409 $contentObjectAttribute->handleCustomHTTPActions( $http, $attributeDataBaseName, 02410 $customActionAttributeArray, $customActionParameters ); 02411 } 02412 $customActionParameters['base_name'] = $oldAttributeDataBaseName; 02413 } 02414 02415 static function recursionProtectionStart() 02416 { 02417 $GLOBALS["ez_content_object_recursion_protect"] = array(); 02418 } 02419 02420 static function recursionProtect( $id ) 02421 { 02422 if ( isset( $GLOBALS["ez_content_object_recursion_protect"][$id] ) ) 02423 { 02424 return false; 02425 } 02426 else 02427 { 02428 $GLOBALS["ez_content_object_recursion_protect"][$id] = true; 02429 return true; 02430 } 02431 } 02432 02433 static function recursionProtectionEnd() 02434 { 02435 unset( $GLOBALS["ez_content_object_recursion_protect"] ); 02436 } 02437 02438 /*! 02439 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 02440 the calls within a db transaction; thus within db->begin and db->commit. 02441 */ 02442 function storeInput( $contentObjectAttributes, 02443 $attributeInputMap ) 02444 { 02445 $db = eZDB::instance(); 02446 $db->begin(); 02447 foreach ( $contentObjectAttributes as $contentObjectAttribute ) 02448 { 02449 if ( isset( $attributeInputMap[$contentObjectAttribute->attribute('id')] ) ) 02450 { 02451 $contentObjectAttribute->store(); 02452 } 02453 } 02454 $db->commit(); 02455 unset( $this->ContentObjectAttributes ); 02456 } 02457 02458 /*! 02459 Returns the next available version number for this object. 02460 */ 02461 function nextVersion() 02462 { 02463 $db = eZDB::instance(); 02464 $versions = $db->arrayQuery( "SELECT ( MAX( version ) + 1 ) AS next_id FROM ezcontentobject_version 02465 WHERE contentobject_id='$this->ID'" ); 02466 return $versions[0]["next_id"]; 02467 02468 } 02469 02470 /*! 02471 Returns the previous available version number for this object, if existing, false otherwise ( if the object has only one version ) 02472 */ 02473 function previousVersion() 02474 { 02475 $db = eZDB::instance(); 02476 $versions = $db->arrayQuery( "SELECT version FROM ezcontentobject_version 02477 WHERE contentobject_id='$this->ID' 02478 ORDER BY version DESC", array( 'limit' => 2 ) ); 02479 if ( count( $versions ) > 1 and isset( $versions[1]['version'] ) ) 02480 { 02481 return $versions[1]['version']; 02482 } 02483 else 02484 { 02485 return false; 02486 } 02487 } 02488 02489 /*! 02490 Returns number of exist versions. 02491 */ 02492 function getVersionCount() 02493 { 02494 $db = eZDB::instance(); 02495 $versionCount = $db->arrayQuery( "SELECT ( COUNT( version ) ) AS version_count FROM ezcontentobject_version 02496 WHERE contentobject_id='$this->ID'" ); 02497 return $versionCount[0]["version_count"]; 02498 02499 } 02500 02501 function currentLanguage() 02502 { 02503 return $this->CurrentLanguage; 02504 } 02505 02506 function currentLanguageObject() 02507 { 02508 if ( $this->CurrentLanguage ) 02509 { 02510 $language = eZContentLanguage::fetchByLocale( $this->CurrentLanguage ); 02511 } 02512 else 02513 { 02514 $language = false; 02515 } 02516 02517 return $language; 02518 } 02519 02520 function setCurrentLanguage( $lang ) 02521 { 02522 $this->CurrentLanguage = $lang; 02523 $this->Name = null; 02524 } 02525 02526 function initialLanguage() 02527 { 02528 return isset( $this->InitialLanguageID ) ? eZContentLanguage::fetch( $this->InitialLanguageID ) : false; 02529 } 02530 02531 function initialLanguageCode() 02532 { 02533 $initialLanguage = $this->initialLanguage(); 02534 // If current contentobject is "Top Level Nodes" than it doesn't have "initial Language" and "locale". 02535 return ( $initialLanguage !== false ) ? $initialLanguage->attribute( 'locale' ) : false; 02536 } 02537 02538 /*! 02539 Adds a new location (node) to the current object. 02540 \param $parenNodeID The id of the node to use as parent. 02541 \param $asObject If true it will return the new child-node as an object, if not it returns the ID. 02542 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 02543 the calls within a db transaction; thus within db->begin and db->commit. 02544 */ 02545 function addLocation( $parentNodeID, $asObject = false ) 02546 { 02547 $node = eZContentObjectTreeNode::addChildTo( $this->ID, $parentNodeID, true, $this->CurrentVersion ); 02548 02549 $data = array( 'contentobject_id' => $this->ID, 02550 'contentobject_version' => $this->attribute( 'current_version' ), 02551 'parent_node' => $parentNodeID, 02552 'is_main' => 0 ); 02553 $nodeAssignment = eZNodeAssignment::create( $data ); 02554 $nodeAssignment->setAttribute( 'op_code', eZNodeAssignment::OP_CODE_CREATE_NOP ); 02555 $nodeAssignment->store(); 02556 02557 if ( $asObject ) 02558 { 02559 return $node; 02560 } 02561 else 02562 { 02563 return $node->attribute( 'node_id' ); 02564 } 02565 } 02566 02567 /*! 02568 Adds a link to the given content object id. 02569 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 02570 the calls within a db transaction; thus within db->begin and db->commit. 02571 */ 02572 function addContentObjectRelation( $toObjectID, 02573 $fromObjectVersion = false, 02574 $attributeID = 0, 02575 $relationType = eZContentObject::RELATION_COMMON ) 02576 { 02577 if ( $attributeID !== 0 ) 02578 { 02579 $relationType = eZContentObject::RELATION_ATTRIBUTE; 02580 } 02581 02582 $relationType =(int) $relationType; 02583 if ( ( $relationType & eZContentObject::RELATION_ATTRIBUTE ) != 0 && 02584 $relationType != eZContentObject::RELATION_ATTRIBUTE ) 02585 { 02586 eZDebug::writeWarning( "Object relation type conflict", "eZContentObject::addContentObjectRelation"); 02587 } 02588 02589 $db = eZDB::instance(); 02590 02591 if ( !$fromObjectVersion ) 02592 $fromObjectVersion = $this->CurrentVersion; 02593 02594 $fromObjectID = $this->ID; 02595 02596 if ( !is_numeric( $toObjectID ) ) 02597 { 02598 eZDebug::writeError( "Related object ID (toObjectID): '$toObjectID', is not a numeric value.", 02599 "eZContentObject::addContentObjectRelation" ); 02600 return false; 02601 } 02602 $fromObjectID =(int) $fromObjectID; 02603 $attributeID =(int) $attributeID; 02604 $fromObjectVersion =(int) $fromObjectVersion; 02605 $relationBaseType = ( $relationType & eZContentObject::RELATION_ATTRIBUTE ) ? 02606 eZContentObject::RELATION_ATTRIBUTE : 02607 eZContentObject::RELATION_COMMON | eZContentObject::RELATION_EMBED | eZContentObject::RELATION_LINK; 02608 $relationTypeMatch = $db->bitAnd( 'relation_type', $relationBaseType ); 02609 $query = "SELECT count(*) AS count 02610 FROM ezcontentobject_link 02611 WHERE from_contentobject_id=$fromObjectID AND 02612 from_contentobject_version=$fromObjectVersion AND 02613 to_contentobject_id=$toObjectID AND 02614 $relationTypeMatch != 0 AND 02615 contentclassattribute_id=$attributeID AND 02616 op_code='0'"; 02617 $count = $db->arrayQuery( $query ); 02618 // if current relation does not exists 02619 if ( !isset( $count[0]['count'] ) || $count[0]['count'] == '0' ) 02620 { 02621 $db->begin(); 02622 $db->query( "INSERT INTO ezcontentobject_link ( from_contentobject_id, from_contentobject_version, to_contentobject_id, contentclassattribute_id, relation_type ) 02623 VALUES ( $fromObjectID, $fromObjectVersion, $toObjectID, $attributeID, $relationType )" ); 02624 // if an object relation is being added and it is in draft, add the row with op_code 1 02625 if ( $attributeID == 0 && $fromObjectVersion != $this->CurrentVersion ) 02626 { 02627 $db->query( "INSERT INTO ezcontentobject_link ( from_contentobject_id, from_contentobject_version, to_contentobject_id, contentclassattribute_id, op_code, relation_type ) 02628 VALUES ( $fromObjectID, $fromObjectVersion, $toObjectID, $attributeID, '1', $relationType )" ); 02629 } 02630 $db->commit(); 02631 } 02632 elseif ( isset( $count[0]['count'] ) && 02633 $count[0]['count'] != '0' && 02634 $attributeID == 0 && 02635 (eZContentObject::RELATION_ATTRIBUTE & $relationType) == 0 ) 02636 { 02637 $db->begin(); 02638 $newRelationType = $db->bitOr( 'relation_type', $relationType ); 02639 $db->query( "UPDATE ezcontentobject_link 02640 SET relation_type = $newRelationType 02641 WHERE from_contentobject_id=$fromObjectID AND 02642 from_contentobject_version=$fromObjectVersion AND 02643 to_contentobject_id=$toObjectID AND 02644 contentclassattribute_id=$attributeID AND 02645 op_code='0'" ); 02646 // if an object relation is being added and it is in draft, add the row with op_code 1 02647 if ( $attributeID == 0 && $fromObjectVersion != $this->CurrentVersion ) 02648 { 02649 $db->query( "INSERT INTO ezcontentobject_link ( from_contentobject_id, from_contentobject_version, to_contentobject_id, contentclassattribute_id, op_code, relation_type ) 02650 VALUES ( $fromObjectID, $fromObjectVersion, $toObjectID, $attributeID, '1', $relationType )" ); 02651 } 02652 $db->commit(); 02653 } 02654 } 02655 02656 /*! 02657 Removes a link to the given content object id. 02658 \param $toObjectID If \c false it will delete relations to all the objects. 02659 \param $attributeID ID of class attribute. 02660 IF it is > 0 we remove relations created by a specific objectrelation[list] attribute. 02661 If it is set to 0 we remove relations created without using of objectrelation[list] attribute. 02662 If it is set to false, we remove all relations, no matter how were they created: 02663 using objectrelation[list] attribute or using "Add related objects" functionality in obect editing mode. 02664 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 02665 the calls within a db transaction; thus within db->begin and db->commit. 02666 */ 02667 function removeContentObjectRelation( $toObjectID = false, $fromObjectVersion = false, $attributeID = 0, $relationType = eZContentObject::RELATION_COMMON ) 02668 { 02669 $db = eZDB::instance(); 02670 02671 if ( !$fromObjectVersion ) 02672 $fromObjectVersion = $this->CurrentVersion; 02673 $fromObjectVersion = (int) $fromObjectVersion; 02674 $fromObjectID = $this->ID; 02675 02676 if ( $toObjectID !== false ) 02677 { 02678 $toObjectID =(int) $toObjectID; 02679 $toObjectCondition = "AND to_contentobject_id=$toObjectID"; 02680 } 02681 else 02682 $toObjectCondition = ''; 02683 02684 if ( $attributeID !== false ) 02685 { 02686 $attributeID =(int) $attributeID; 02687 $classAttributeCondition = "AND contentclassattribute_id=$attributeID"; 02688 } 02689 else 02690 $classAttributeCondition = ''; 02691 02692 $lastRelationType = 0; 02693 $db->begin(); 02694 // if an object relation is being removed from the draft, add the row with op_code -1 02695 if ( !$attributeID && $fromObjectVersion != $this->CurrentVersion ) 02696 { 02697 $rows = $db->arrayQuery( "SELECT * FROM ezcontentobject_link 02698 WHERE from_contentobject_id=$fromObjectID 02699 AND from_contentobject_version=$fromObjectVersion 02700 AND contentclassattribute_id='0' 02701 $toObjectCondition 02702 AND op_code='0'" ); 02703 foreach ( $rows as $row ) 02704 { 02705 $db->query( "INSERT INTO ezcontentobject_link ( from_contentobject_id, from_contentobject_version, to_contentobject_id, contentclassattribute_id, op_code, relation_type ) 02706 VALUES ( $fromObjectID, $fromObjectVersion, " . $row['to_contentobject_id'] . ", '0', '-1', $relationType )" ); 02707 $lastRelationType = (int) $row['relation_type']; 02708 } 02709 } 02710 02711 if ( 0 !== ( eZContentObject::RELATION_ATTRIBUTE & $relationType ) || 02712 0 != $attributeID || 02713 $relationType == $lastRelationType ) 02714 { 02715 $db->query( "DELETE FROM ezcontentobject_link 02716 WHERE from_contentobject_id=$fromObjectID AND 02717 from_contentobject_version=$fromObjectVersion $classAttributeCondition $toObjectCondition AND 02718 op_code='0'" ); 02719 } 02720 else 02721 { 02722 if ( $db->databaseName() == 'oracle' ) 02723 { 02724 $notRelationType = - ( $relationType + 1 ); 02725 $db->query( "UPDATE ezcontentobject_link 02726 SET relation_type = " . $db->bitAnd( 'relation_type', $notRelationType ) . " 02727 WHERE from_contentobject_id=$fromObjectID AND 02728 from_contentobject_version=$fromObjectVersion $classAttributeCondition $toObjectCondition AND 02729 op_code='0'" ); 02730 } 02731 else 02732 { 02733 $db->query( "UPDATE ezcontentobject_link 02734 SET relation_type = ( relation_type & ".(~$relationType)." ) 02735 WHERE from_contentobject_id=$fromObjectID AND 02736 from_contentobject_version=$fromObjectVersion $classAttributeCondition $toObjectCondition AND 02737 op_code='0'" ); 02738 } 02739 } 02740 02741 $db->commit(); 02742 02743 } 02744 02745 function copyContentObjectRelations( $currentVersion, $newVersion, $newObjectID = false ) 02746 { 02747 $objectID = $this->ID; 02748 if ( !$newObjectID ) 02749 { 02750 $newObjectID = $objectID; 02751 } 02752 02753 $db = eZDB::instance(); 02754 $db->begin(); 02755 02756 $relations = $db->arrayQuery( "SELECT to_contentobject_id, op_code, relation_type FROM ezcontentobject_link 02757 WHERE contentclassattribute_id='0' 02758 AND from_contentobject_id='$objectID' 02759 AND from_contentobject_version='$currentVersion'" ); 02760 foreach ( $relations as $relation ) 02761 { 02762 $toContentObjectID = $relation['to_contentobject_id']; 02763 $opCode = $relation['op_code']; 02764 $relationType = $relation['relation_type']; 02765 $db->query( "INSERT INTO ezcontentobject_link( contentclassattribute_id, 02766 from_contentobject_id, 02767 from_contentobject_version, 02768 to_contentobject_id, 02769 op_code, 02770 relation_type ) 02771 VALUES ( '0', '$newObjectID', '$newVersion', '$toContentObjectID', '$opCode', '$relationType' )" ); 02772 } 02773 02774 $db->commit(); 02775 } 02776 02777 static function isObjectRelationTyped() 02778 { 02779 $siteIni = eZINI::instance( 'site.ini' ); 02780 if ( $siteIni->hasVariable( 'BackwardCompatibilitySettings', 'ObjectRelationTyped' ) ) 02781 { 02782 if ( 'enabled' == $siteIni->variable( 'BackwardCompatibilitySettings', 'ObjectRelationTyped' ) ) 02783 { 02784 return true; 02785 } 02786 } 02787 return false; 02788 } 02789 02790 static function relationTypeMask( $allRelations = false ) 02791 { 02792 $relationTypeMask = eZContentObject::RELATION_COMMON | 02793 eZContentObject::RELATION_EMBED; 02794 02795 if ( eZContentObject::isObjectRelationTyped() ) 02796 { 02797 $relationTypeMask |= eZContentObject::RELATION_LINK; 02798 } 02799 02800 if ( $allRelations ) 02801 { 02802 $relationTypeMask |= eZContentObject::RELATION_ATTRIBUTE; 02803 } 02804 02805 return $relationTypeMask; 02806 } 02807 02808 /*! 02809 Returns the related or reverse related objects: 02810 \param $attributeID : ( makes sense only when $params['AllRelations'] not set or eZContentObject::RELATION_ATTRIBUTE ) 02811 >0 - return relations made with attribute ID ( "related object(s)" datatype ) 02812 0 or false ( $params['AllRelations'] is eZContentObject::RELATION_ATTRIBUTE ) 02813 - return relations made with any attributes 02814 false ( $params['AllRelations'] not set ) 02815 - return ALL relations (deprecated, use "$params['AllRelations'] = true" instead) 02816 \param $groupByAttribute : false - return all relations as an array of content objects 02817 true - return all relations groupped by attribute ID 02818 This parameter makes sense only when $attributeID == false or $params['AllRelations'] = true 02819 \param $params : other parameters from template fetch function : 02820 $params['AllRelations'] - relation type filter : 02821 true - return ALL relations, including attribute-level 02822 false - return object-level relations 02823 >0 - bit mask of EZ_CONTENT_OBJECT_RELATION_* values 02824 $params['SortBy'] - related objects sorting mode. 02825 Supported modes: class_identifier, class_name, modified, name, published, section 02826 $params['IgnoreVisibility'] - ignores 'hidden' state of related objects if true 02827 \param $reverseRelatedObjects : if "true" returns reverse related contentObjects 02828 if "false" returns related contentObjects 02829 */ 02830 function relatedObjects( $fromObjectVersion = false, 02831 $objectID = false, 02832 $attributeID = 0, 02833 $groupByAttribute = false, 02834 $params = false, 02835 $reverseRelatedObjects = false ) 02836 { 02837 if ( $fromObjectVersion == false ) 02838 $fromObjectVersion = isset( $this->CurrentVersion ) ? $this->CurrentVersion : false; 02839 $fromObjectVersion =(int) $fromObjectVersion; 02840 if( !$objectID ) 02841 $objectID = $this->ID; 02842 $objectID =(int) $objectID; 02843 02844 $db = eZDB::instance(); 02845 $sortingString = ''; 02846 $sortingInfo = array( 'attributeFromSQL' => '', 02847 'attributeWhereSQL' => '' ); 02848 02849 $showInvisibleNodesCond = ''; 02850 // process params (only SortBy and IgnoreVisibility currently supported): 02851 // Supported sort_by modes: 02852 // class_identifier, class_name, modified, name, published, section 02853 if ( is_array( $params ) ) 02854 { 02855 if ( isset( $params['SortBy'] ) ) 02856 { 02857 $sortingInfo = eZContentObjectTreeNode::createSortingSQLStrings( $params['SortBy'] ); 02858 $sortingString = ' ORDER BY ' . $sortingInfo['sortingFields']; 02859 } 02860 if ( isset( $params['IgnoreVisibility'] ) && !$params['IgnoreVisibility'] ) 02861 { 02862 $showInvisibleNodesCond = " AND ( SELECT MIN( ezct.is_invisible ) FROM ezcontentobject_tree ezct WHERE ezct.contentobject_id = ezcontentobject.id ) = 0 "; 02863 } 02864 } 02865 02866 $relationTypeMasking = ''; 02867 $relationTypeMask = isset( $params['AllRelations'] ) ? $params['AllRelations'] : ( $attributeID === false ); 02868 if ( $attributeID && ( $relationTypeMask === false || $relationTypeMask === eZContentObject::RELATION_ATTRIBUTE ) ) 02869 { 02870 $attributeID =(int) $attributeID; 02871 $relationTypeMasking .= " AND contentclassattribute_id=$attributeID "; 02872 $relationTypeMask = eZContentObject::RELATION_ATTRIBUTE; 02873 } 02874 elseif ( is_bool( $relationTypeMask ) ) 02875 { 02876 $relationTypeMask = eZContentObject::relationTypeMask( $relationTypeMask ); 02877 } 02878 02879 if ( $db->databaseName() == 'oracle' ) 02880 { 02881 $relationTypeMasking .= " AND bitand( relation_type, $relationTypeMask ) <> 0 "; 02882 } 02883 else 02884 { 02885 $relationTypeMasking .= " AND ( relation_type & $relationTypeMask ) <> 0 "; 02886 } 02887 02888 // Create SQL 02889 $versionNameTables = ', ezcontentobject_name '; 02890 $versionNameTargets = ', ezcontentobject_name.name as name, ezcontentobject_name.real_translation '; 02891 02892 $versionNameJoins = " AND ezcontentobject.id = ezcontentobject_name.contentobject_id AND 02893 ezcontentobject.current_version = ezcontentobject_name.content_version AND "; 02894 $versionNameJoins .= eZContentLanguage::sqlFilter( 'ezcontentobject_name', 'ezcontentobject' ); 02895 02896 $fromOrToContentObjectID = $reverseRelatedObjects == false ? " AND ezcontentobject.id=ezcontentobject_link.to_contentobject_id AND 02897 ezcontentobject_link.from_contentobject_id='$objectID' AND 02898 ezcontentobject_link.from_contentobject_version='$fromObjectVersion' " 02899 : " AND ezcontentobject.id=ezcontentobject_link.from_contentobject_id AND 02900 ezcontentobject_link.to_contentobject_id=$objectID AND 02901 ezcontentobject_link.from_contentobject_version=ezcontentobject.current_version "; 02902 $query = "SELECT "; 02903 02904 if ( $groupByAttribute ) 02905 { 02906 $query .= "ezcontentobject_link.contentclassattribute_id, "; 02907 } 02908 $query .= " 02909 ezcontentclass.serialized_name_list AS class_serialized_name_list, 02910 ezcontentclass.identifier as contentclass_identifier, 02911 ezcontentclass.is_container as is_container, 02912 ezcontentobject.* $versionNameTargets 02913 FROM 02914 ezcontentclass, 02915 ezcontentobject, 02916 ezcontentobject_link 02917 $versionNameTables 02918 $sortingInfo[attributeFromSQL] 02919 WHERE 02920 ezcontentclass.id=ezcontentobject.contentclass_id AND 02921 ezcontentclass.version=0 AND 02922 ezcontentobject.status=" . eZContentObject::STATUS_PUBLISHED . " AND 02923 $sortingInfo[attributeWhereSQL] 02924 ezcontentobject_link.op_code='0' 02925 $relationTypeMasking 02926 $fromOrToContentObjectID 02927 $showInvisibleNodesCond 02928 $versionNameJoins 02929 $sortingString"; 02930 $relatedObjects = $db->arrayQuery( $query ); 02931 02932 $ret = array(); 02933 foreach ( $relatedObjects as $object ) 02934 { 02935 $obj = new eZContentObject( $object ); 02936 $obj->ClassName = eZContentClass::nameFromSerializedString( $object['class_serialized_name_list'] ); 02937 02938 if ( !$groupByAttribute ) 02939 { 02940 $ret[] = $obj; 02941 } 02942 else 02943 { 02944 $classAttrID = $object['contentclassattribute_id']; 02945 02946 if ( !isset( $ret[$classAttrID] ) ) 02947 $ret[$classAttrID] = array(); 02948 02949 $ret[$classAttrID][] = $obj; 02950 } 02951 } 02952 return $ret; 02953 } 02954 02955 /*! 02956 Returns the related objects. 02957 \param $attributeID : ( makes sense only when $params['AllRelations'] not set or eZContentObject::RELATION_ATTRIBUTE ) 02958 >0 - return relations made with attribute ID ( "related object(s)" datatype ) 02959 0 or false ( $params['AllRelations'] is eZContentObject::RELATION_ATTRIBUTE ) 02960 - return relations made with any attributes 02961 false ( $params['AllRelations'] not set ) 02962 - return ALL relations (deprecated, use "$params['AllRelations'] = true" instead) 02963 \param $groupByAttribute : false - return all relations as an array of content objects 02964 true - return all relations groupped by attribute ID 02965 This parameter makes sense only when $attributeID == false or $params['AllRelations'] = true 02966 \param $params : other parameters from template fetch function : 02967 $params['AllRelations'] - relation type filter : 02968 true - return ALL relations, including attribute-level 02969 false - return object-level relations 02970 >0 - bit mask of EZ_CONTENT_OBJECT_RELATION_* values 02971 $params['SortBy'] - related objects sorting mode. 02972 Supported modes: class_identifier, class_name, modified, name, published, section 02973 $params['IgnoreVisibility'] - ignores 'hidden' state of related objects if true 02974 */ 02975 function relatedContentObjectList( $fromObjectVersion = false, 02976 $fromObjectID = false, 02977 $attributeID = 0, 02978 $groupByAttribute = false, 02979 $params = false ) 02980 { 02981 eZDebugSetting::writeDebug( 'kernel-content-object-related-objects', $fromObjectID, "objectID" ); 02982 return $this->relatedObjects( $fromObjectVersion, $fromObjectID, $attributeID, $groupByAttribute, $params ); 02983 } 02984 02985 /*! 02986 Returns the xml-linked objects. 02987 */ 02988 function linkedContentObjectList( $fromObjectVersion = false, $fromObjectID = false ) 02989 { 02990 return $this->relatedObjects( $fromObjectVersion, 02991 $fromObjectID, 02992 0, 02993 false, 02994 array( 'AllRelations' => eZContentObject::RELATION_LINK ) ); 02995 } 02996 02997 /*! 02998 Returns the xml-embedded objects. 02999 */ 03000 function embeddedContentObjectList( $fromObjectVersion = false, $fromObjectID = false ) 03001 { 03002 return $this->relatedObjects( $fromObjectVersion, 03003 $fromObjectID, 03004 0, 03005 false, 03006 array( 'AllRelations' => eZContentObject::RELATION_EMBED ) ); 03007 } 03008 03009 /*! 03010 Returns the reverse xml-linked objects. 03011 */ 03012 function reverseLinkedObjectList( $fromObjectVersion = false, $fromObjectID = false ) 03013 { 03014 return $this->relatedObjects( $fromObjectVersion, 03015 $fromObjectID, 03016 0, 03017 false, 03018 array( 'AllRelations' => eZContentObject::RELATION_LINK ), 03019 true ); 03020 } 03021 03022 /*! 03023 Returns the reverse xml-embedded objects. 03024 */ 03025 function reverseEmbeddedObjectList( $fromObjectVersion = false, $fromObjectID = false ) 03026 { 03027 return $this->relatedObjects( $fromObjectVersion, 03028 $fromObjectID, 03029 0, 03030 false, 03031 array( 'AllRelations' => eZContentObject::RELATION_EMBED ), 03032 true ); 03033 } 03034 03035 // left for compatibility 03036 function relatedContentObjectArray( $fromObjectVersion = false, 03037 $fromObjectID = false, 03038 $attributeID = 0, 03039 $params = false ) 03040 { 03041 return eZContentObject::relatedContentObjectList( $fromObjectVersion, 03042 $fromObjectID, 03043 $attributeID, 03044 false, 03045 $params ); 03046 } 03047 03048 /*! 03049 \return the number of related objects 03050 \param $attributeID : ( makes sense only when $params['AllRelations'] not set or eZContentObject::RELATION_ATTRIBUTE ) 03051 >0 - return relations made with attribute ID ( "related object(s)" datatype ) 03052 0 or false ( $params['AllRelations'] is eZContentObject::RELATION_ATTRIBUTE ) 03053 - return relations made with any attributes 03054 false ( $params['AllRelations'] not set ) 03055 - return ALL relations (deprecated, use "$params['AllRelations'] = true" instead) 03056 \param $params : other parameters from template fetch function : 03057 $params['AllRelations'] - relation type filter : 03058 true - return ALL relations, including attribute-level 03059 false - return object-level relations 03060 >0 - bit mask of EZ_CONTENT_OBJECT_RELATION_* values 03061 $params['SortBy'] - related objects sorting mode. 03062 Supported modes: class_identifier, class_name, modified, name, published, section 03063 $params['IgnoreVisibility'] - ignores 'hidden' state of related objects if true 03064 */ 03065 function relatedContentObjectCount( $fromObjectVersion = false, 03066 $attributeID = 0, 03067 $params = false ) 03068 { 03069 eZDebugSetting::writeDebug( 'kernel-content-object-related-objects', $this->ID, "relatedContentObjectCount::objectID" ); 03070 return $this->relatedObjectCount( $fromObjectVersion, 03071 $attributeID, 03072 false, 03073 $params ); 03074 } 03075 03076 /*! 03077 Returns the objects to which this object are related . 03078 \param $attributeID : ( makes sense only when $params['AllRelations'] not set or eZContentObject::RELATION_ATTRIBUTE ) 03079 >0 - return relations made with attribute ID ( "related object(s)" datatype ) 03080 0 or false ( $params['AllRelations'] is eZContentObject::RELATION_ATTRIBUTE ) 03081 - return relations made with any attributes 03082 false ( $params['AllRelations'] not set ) 03083 - return ALL relations (deprecated, use "$params['AllRelations'] = true" instead) 03084 \param $groupByAttribute : false - return all relations as an array of content objects 03085 true - return all relations groupped by attribute ID 03086 This parameter makes sense only when $attributeID == false or $params['AllRelations'] = true 03087 \param $params : other parameters from template fetch function : 03088 $params['AllRelations'] - relation type filter : 03089 true - return ALL relations, including attribute-level 03090 false - return object-level relations 03091 >0 - bit mask of EZ_CONTENT_OBJECT_RELATION_* values 03092 $params['SortBy'] - related objects sorting mode. 03093 Supported modes: class_identifier, class_name, modified, name, published, section 03094 $params['IgnoreVisibility'] - ignores 'hidden' state of related objects if true 03095 */ 03096 function reverseRelatedObjectList( $version = false, 03097 $attributeID = 0, 03098 $groupByAttribute = false, 03099 $params = false ) 03100 { 03101 return $this->relatedObjects( $version, $this->ID, $attributeID, $groupByAttribute, $params, true ); 03102 } 03103 03104 /*! 03105 Returns the xml-linked objects count. 03106 */ 03107 function linkedContentObjectCount( $fromObjectVersion = false ) 03108 { 03109 return $this->relatedObjectCount( $fromObjectVersion, 03110 0, 03111 false, 03112 array( 'AllRelations' => eZContentObject::RELATION_LINK ) ); 03113 } 03114 03115 /*! 03116 Returns the xml-embedded objects count. 03117 */ 03118 function embeddedContentObjectCount( $fromObjectVersion = false ) 03119 { 03120 return $this->relatedObjectCount( $fromObjectVersion, 03121 0, 03122 false, 03123 array( 'AllRelations' => eZContentObject::RELATION_EMBED ) ); 03124 } 03125 03126 /*! 03127 Returns the reverse xml-linked objects count. 03128 */ 03129 function reverseLinkedObjectCount( $fromObjectVersion = false ) 03130 { 03131 return $this->relatedObjectCount( $fromObjectVersion, 03132 0, 03133 true, 03134 array( 'AllRelations' => eZContentObject::RELATION_LINK ) ); 03135 } 03136 03137 /*! 03138 Returns the reverse xml-embedded objects count. 03139 */ 03140 function reverseEmbeddedObjectCount( $fromObjectVersion = false ) 03141 { 03142 return $this->relatedObjectCount( $fromObjectVersion, 03143 0, 03144 true, 03145 array( 'AllRelations' => eZContentObject::RELATION_EMBED ) ); 03146 } 03147 03148 /** 03149 * Fetch the number of (reverse) related objects 03150 * 03151 * @param int $version 03152 * @param int $attributeID 03153 * This parameter only makes sense if $params[AllRelations] is unset, 03154 * set to false, or matches eZContentObject::RELATION_ATTRIBUTE 03155 * Possible values: 03156 * - 0 or false: 03157 * Count relations made with any attribute 03158 * - >0 03159 * Count relations made with attribute $attributeID 03160 * @param int|false $reverseRelatedObjects 03161 * Wether to count related objects (false) or reverse related 03162 * objects (false) 03163 * @param array|false $params 03164 * Various params, as an associative array. 03165 * Possible values: 03166 * - AllRelations (bool|int) 03167 * true: count ALL relations, object and attribute level 03168 * false: only count object level relations 03169 * other: bit mask of eZContentObject::RELATION_* constants 03170 * - IgnoreVisibility (bool) 03171 * If true, 'hidden' status will be ignored 03172 * 03173 * @return int The number of (reverse) related objects for the object 03174 **/ 03175 function relatedObjectCount( $version = false, $attributeID = 0, $reverseRelatedObjects = false, $params = false ) 03176 { 03177 $objectID = $this->ID; 03178 if ( $version == false ) 03179 $version = isset( $this->CurrentVersion ) ? $this->CurrentVersion : false; 03180 $version == (int) $version; 03181 03182 $db = eZDB::instance(); 03183 $showInvisibleNodesCond = ''; 03184 03185 // process params (only IgnoreVisibility currently supported): 03186 if ( is_array( $params ) ) 03187 { 03188 if ( isset( $params['IgnoreVisibility'] ) && !$params['IgnoreVisibility'] ) 03189 { 03190 $showInvisibleNodesCond = " AND ( SELECT MIN( ezct.is_invisible ) 03191 FROM ezcontentobject_tree ezct 03192 WHERE ezct.contentobject_id = ezcontentobject.id ) = 0 "; 03193 } 03194 } 03195 03196 $relationTypeMasking = ''; 03197 $relationTypeMask = isset( $params['AllRelations'] ) ? $params['AllRelations'] : ( $attributeID === false ); 03198 if ( $attributeID && ( $relationTypeMask === false || $relationTypeMask === eZContentObject::RELATION_ATTRIBUTE ) ) 03199 { 03200 $attributeID =(int) $attributeID; 03201 $relationTypeMasking .= " AND contentclassattribute_id=$attributeID "; 03202 $relationTypeMask = eZContentObject::RELATION_ATTRIBUTE; 03203 } 03204 elseif ( is_bool( $relationTypeMask ) ) 03205 { 03206 $relationTypeMask = eZContentObject::relationTypeMask( $relationTypeMask ); 03207 } 03208 03209 if ( $db->databaseName() == 'oracle' ) 03210 { 03211 $relationTypeMasking .= " AND bitand( relation_type, $relationTypeMask ) <> 0 "; 03212 } 03213 else 03214 { 03215 $relationTypeMasking .= " AND ( relation_type & $relationTypeMask ) <> 0 "; 03216 } 03217 03218 if ( $reverseRelatedObjects ) 03219 { 03220 if ( is_array( $objectID ) ) 03221 { 03222 if ( count( $objectID ) > 0 ) 03223 { 03224 $objectIDSQL = ' AND ' . $db->generateSQLINStatement( $objectID, 'ezcontentobject_link.to_contentobject_id', false, false, 'int' ) . ' AND 03225 ezcontentobject_link.from_contentobject_version=ezcontentobject.current_version'; 03226 } 03227 else 03228 { 03229 $objectIDSQL = ''; 03230 } 03231 } 03232 else 03233 { 03234 $objectID = (int) $objectID; 03235 $objectIDSQL = ' AND ezcontentobject_link.to_contentobject_id = ' . $objectID . ' AND 03236 ezcontentobject_link.from_contentobject_version=ezcontentobject.current_version'; 03237 } 03238 $select = " count( DISTINCT ezcontentobject.id ) AS count"; 03239 } 03240 else 03241 { 03242 $select = " count( ezcontentobject_link.from_contentobject_id ) as count "; 03243 $objectIDSQL = " AND ezcontentobject_link.from_contentobject_id='$objectID' 03244 AND ezcontentobject_link.from_contentobject_version='$version'"; 03245 } 03246 $query = "SELECT $select 03247 FROM 03248 ezcontentobject, ezcontentobject_link 03249 WHERE 03250 ezcontentobject.id=ezcontentobject_link.from_contentobject_id AND 03251 ezcontentobject.status=" . eZContentObject::STATUS_PUBLISHED . " AND 03252 ezcontentobject_link.op_code='0' 03253 $objectIDSQL 03254 $relationTypeMasking 03255 $showInvisibleNodesCond"; 03256 03257 $rows = $db->arrayQuery( $query ); 03258 return $rows[0]['count']; 03259 } 03260 03261 /*! 03262 Returns the number of objects to which this object is related. 03263 \param $attributeID : ( makes sense only when $params['AllRelations'] not set or eZContentObject::RELATION_ATTRIBUTE ) 03264 >0 - return relations made with attribute ID ( "related object(s)" datatype ) 03265 0 or false ( $params['AllRelations'] is eZContentObject::RELATION_ATTRIBUTE ) 03266 - return relations made with any attributes 03267 false ( $params['AllRelations'] not set ) 03268 - return ALL relations (deprecated, use "$params['AllRelations'] = true" instead) 03269 \param $params : other parameters from template fetch function : 03270 $params['AllRelations'] - relation type filter : 03271 true - return ALL relations, including attribute-level 03272 false - return object-level relations 03273 >0 - bit mask of EZ_CONTENT_OBJECT_RELATION_* values 03274 */ 03275 function reverseRelatedObjectCount( $version = false, $attributeID = 0, $params = false ) 03276 { 03277 return $this->relatedObjectCount( $version, $attributeID, true, $params ); 03278 } 03279 03280 /*! 03281 Returns the related objects. 03282 \note This function is a duplicate of reverseRelatedObjectList(), use that function instead. 03283 */ 03284 function contentObjectListRelatingThis( $version = false ) 03285 { 03286 return $this->reverseRelatedObjectList( $version ); 03287 } 03288 03289 function publishContentObjectRelations( $version ) 03290 { 03291 $objectID = $this->ID; 03292 $currentVersion = $this->CurrentVersion; 03293 $version =(int) $version; 03294 $db = eZDB::instance(); 03295 $db->begin(); 03296 03297 $toContentObjectIDs = array(); 03298 $relationTypesArray = array(); 03299 $publishedRelations = $db->arrayQuery( "SELECT to_contentobject_id, relation_type FROM ezcontentobject_link 03300 WHERE contentclassattribute_id='0' 03301 AND from_contentobject_id='$objectID' 03302 AND from_contentobject_version='$currentVersion' 03303 AND op_code='0'" ); 03304 03305 foreach ( $publishedRelations as $relation ) 03306 { 03307 $toContentObjectIDs[] = $relation['to_contentobject_id']; 03308 $relationTypesArray[$relation['to_contentobject_id']] = (int) $relation['relation_type']; 03309 } 03310 $toContentObjectIDs = array_unique( $toContentObjectIDs ); 03311 03312 $addedOrRemovedRelations = $db->arrayQuery( "SELECT to_contentobject_id, op_code, relation_type FROM ezcontentobject_link 03313 WHERE contentclassattribute_id='0' 03314 AND from_contentobject_id='$objectID' 03315 AND from_contentobject_version='$version' 03316 AND op_code!='0' 03317 ORDER BY id ASC" ); 03318 03319 foreach ( $addedOrRemovedRelations as $relation ) 03320 { 03321 $relationType = (int) $relation['relation_type']; 03322 if ( !isset( $relationTypesArray[$relation['to_contentobject_id']] ) ) 03323 { 03324 $relationTypesArray[$relation['to_contentobject_id']] = 0; 03325 } 03326 if ( $relation['op_code'] == 1 ) 03327 { 03328 if ( !in_array( $relation['to_contentobject_id'], $toContentObjectIDs ) ) 03329 { 03330 $toContentObjectIDs[] = $relation['to_contentobject_id']; 03331 } 03332 $relationTypesArray[$relation['to_contentobject_id']] |= $relationType; 03333 } 03334 else 03335 { 03336 $relationTypesArray[$relation['to_contentobject_id']] &= ~$relationType; 03337 if ( 0 === $relationTypesArray[$relation['to_contentobject_id']] ) 03338 { 03339 $toContentObjectIDs = array_diff( $toContentObjectIDs, array( $relation['to_contentobject_id'] ) ); 03340 } 03341 } 03342 } 03343 03344 $db->query( "DELETE FROM ezcontentobject_link 03345 WHERE contentclassattribute_id='0' 03346 AND from_contentobject_id='$objectID' 03347 AND from_contentobject_version='$version'" ); 03348 03349 foreach( $toContentObjectIDs as $toContentObjectID ) 03350 { 03351 $db->query( "INSERT INTO ezcontentobject_link( contentclassattribute_id, 03352 from_contentobject_id, 03353 from_contentobject_version, 03354 to_contentobject_id, 03355 op_code, 03356 relation_type ) 03357 VALUES ( '0', '$objectID', '$version', '$toContentObjectID', '0', '{$relationTypesArray[$toContentObjectID]}' )" ); 03358 } 03359 03360 $db->commit(); 03361 } 03362 03363 /*! 03364 Get parent node IDs 03365 */ 03366 function parentNodeIDArray() 03367 { 03368 return $this->parentNodes( true, false ); 03369 } 03370 03371 /*! 03372 \param $version No longer in use, published nodes are used instead. 03373 \param $asObject If true it fetches PHP objects, otherwise it fetches IDs. 03374 \return the parnet nodes for the current object. 03375 */ 03376 function parentNodes( $version = false, $asObject = true ) 03377 { 03378 // We no longer use node-assignment table to find the parents but uses 03379 // the 'published' tree structure. 03380 $retNodes = array(); 03381 03382 $nodes = $this->assignedNodes(); 03383 if ( $asObject ) 03384 { 03385 foreach ( $nodes as $node ) 03386 { 03387 $retNodes[] = $node->fetchParent(); 03388 } 03389 } 03390 else 03391 { 03392 foreach ( $nodes as $node ) 03393 { 03394 $parentNode = $node->fetchParent(); 03395 $retNodes[] = $parentNode->attribute( 'node_id' ); 03396 } 03397 } 03398 03399 return $retNodes; 03400 } 03401 03402 /*! 03403 Creates a new node assignment that will place the object as child of node \a $nodeID. 03404 \return The eZNodeAssignment object it created 03405 \param $parentNodeID The node ID of the parent node 03406 \param $isMain \c true if the created node is the main node of the object 03407 \param $remoteID A string denoting the unique remote ID of the assignment or \c false for no remote id. 03408 \note The return assignment will already be stored in the database 03409 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 03410 the calls within a db transaction; thus within db->begin and db->commit. 03411 */ 03412 function createNodeAssignment( $parentNodeID, $isMain, $remoteID = false, $sortField = 2 /* published */, $sortOrder = 0 /* desc */ ) 03413 { 03414 $nodeAssignment = eZNodeAssignment::create( array( 'contentobject_id' => $this->attribute( 'id' ), 03415 'contentobject_version' => $this->attribute( 'current_version' ), 03416 'parent_node' => $parentNodeID, 03417 'is_main' => ( $isMain ? 1 : 0 ), 03418 'sort_field' => $sortField, 03419 'sort_order' => $sortOrder ) ); 03420 if ( $remoteID !== false ) 03421 { 03422 $nodeAssignment->setAttribute( 'remote_id', $remoteID ); 03423 } 03424 $nodeAssignment->store(); 03425 return $nodeAssignment; 03426 } 03427 03428 /* 03429 * Creates object with nodeAssignment from given parent Node, class ID and language code. 03430 */ 03431 static function createWithNodeAssignment( $parentNode, $contentClassID, $languageCode, $remoteID = false ) 03432 { 03433 $class = eZContentClass::fetch( $contentClassID ); 03434 $parentObject = $parentNode->attribute( 'object' ); 03435 03436 // Check if the user has access to create a folder here 03437 if ( $class instanceof eZContentClass and 03438 $parentObject->checkAccess( 'create', $contentClassID, false, false, $languageCode ) == '1' ) 03439 { 03440 // Set section of the newly created object to the section's value of it's parent object 03441 $sectionID = $parentObject->attribute( 'section_id' ); 03442 03443 include_once( "kernel/classes/datatypes/ezuser/ezuser.php" ); 03444 $userID = eZUser::currentUserID(); 03445 03446 $db = eZDB::instance(); 03447 $db->begin(); 03448 $contentObject = $class->instantiateIn( $languageCode, $userID, $sectionID, false, eZContentObjectVersion::STATUS_INTERNAL_DRAFT ); 03449 $nodeAssignment = $contentObject->createNodeAssignment( $parentNode->attribute( 'node_id' ), 03450 true, $remoteID, 03451 $class->attribute( 'sort_field' ), 03452 $class->attribute( 'sort_order' ) ); 03453 $db->commit(); 03454 return $contentObject; 03455 } 03456 return null; 03457 } 03458 03459 03460 /*! 03461 Returns the node assignments for the current object. 03462 */ 03463 function assignedNodes( $asObject = true ) 03464 { 03465 $contentobjectID = $this->attribute( 'id' ); 03466 if ( $contentobjectID == null ) 03467 { 03468 $retValue = array(); 03469 return $retValue; 03470 } 03471 $query = "SELECT ezcontentobject.*, 03472 ezcontentobject_tree.*, 03473 ezcontentclass.serialized_name_list as class_serialized_name_list 03474 FROM ezcontentobject_tree, 03475 ezcontentobject, 03476 ezcontentclass 03477 WHERE contentobject_id=$contentobjectID AND 03478 ezcontentobject_tree.contentobject_id=ezcontentobject.id AND 03479 ezcontentclass.version=0 AND 03480 ezcontentclass.id = ezcontentobject.contentclass_id 03481 ORDER BY path_string"; 03482 $db = eZDB::instance(); 03483 $nodesListArray = $db->arrayQuery( $query ); 03484 if ( $asObject == true ) 03485 { 03486 $nodes = eZContentObjectTreeNode::makeObjectsArray( $nodesListArray ); 03487 return $nodes; 03488 } 03489 else 03490 return $nodesListArray; 03491 } 03492 03493 /*! 03494 Returns the main node id for the current object. 03495 */ 03496 function mainNodeID() 03497 { 03498 if ( !is_numeric( $this->MainNodeID ) ) 03499 { 03500 $mainNodeID = eZContentObjectTreeNode::findMainNode( $this->attribute( 'id' ) ); 03501 $this->MainNodeID = $mainNodeID; 03502 } 03503 return $this->MainNodeID; 03504 } 03505 03506 function mainNode() 03507 { 03508 return eZContentObjectTreeNode::findMainNode( $this->attribute( 'id' ), true ); 03509 } 03510 03511 /*! 03512 Sets the permissions for this object. 03513 */ 03514 function setPermissions( $permissionArray ) 03515 { 03516 $this->Permissions =& $permissionArray; 03517 } 03518 03519 /*! 03520 Returns the permission for the current object. 03521 */ 03522 function permissions( ) 03523 { 03524 return $this->Permissions; 03525 } 03526 03527 function canEditLanguages() 03528 { 03529 $availableLanguages = $this->availableLanguages(); 03530 $languages = array(); 03531 03532 foreach ( eZContentLanguage::prioritizedLanguages() as $language ) 03533 { 03534 $languageCode = $language->attribute( 'locale' ); 03535 if ( in_array( $languageCode, $availableLanguages ) && 03536 $this->canEdit( false, false, false, $languageCode ) ) 03537 { 03538 $languages[] = $language; 03539 } 03540 } 03541 03542 return $languages; 03543 } 03544 03545 function canCreateLanguages() 03546 { 03547 $availableLanguages = $this->availableLanguages(); 03548 $languages = array(); 03549 foreach ( eZContentLanguage::prioritizedLanguages() as $language ) 03550 { 03551 $languageCode = $language->attribute( 'locale' ); 03552 if ( !in_array( $languageCode, $availableLanguages ) && 03553 $this->checkAccess( 'edit', false, false, false, $languageCode ) ) 03554 { 03555 $languages[] = $language; 03556 } 03557 } 03558 03559 return $languages; 03560 } 03561 03562 /*! 03563 */ 03564 function checkGroupLimitationAccess( $limitationValueList, $userID, $contentObjectID = false ) 03565 { 03566 $access = 'denied'; 03567 03568 if ( is_array( $limitationValueList ) && is_numeric( $userID ) ) 03569 { 03570 if ( $contentObjectID !== false ) 03571 { 03572 $contentObject = eZContentObject::fetch( $contentObjectID ); 03573 } 03574 else 03575 { 03576 $contentObject = $this; 03577 } 03578 03579 if ( is_object( $contentObject ) ) 03580 { 03581 // limitation value == 1, means "self group" 03582 if ( in_array( 1, $limitationValueList ) ) 03583 { 03584 // no need to check groups if user ownes this object 03585 $ownerID = $contentObject->attribute( 'owner_id' ); 03586 if ( $ownerID == $userID || $contentObject->attribute( 'id' ) == $userID ) 03587 { 03588 $access = 'allowed'; 03589 } 03590 else 03591 { 03592 // get contentobjects for 'user' and 'owner' 03593 $userList = eZContentObject::fetchIDArray( array( $userID, $ownerID ) ); 03594 03595 // get parents for each location for 'user' and 'owner'. 03596 $groupList = array(); 03597 foreach ( array_keys( $userList ) as $key ) 03598 { 03599 $groupList[] = $userList[$key]->attribute( 'parent_nodes' ); 03600 } 03601 03602 // find group(s) which is common for 'user' and 'owner' 03603 // note: $groupList should contain 2 items only: parents for 'user' and parents for 'owner'. 03604 $commonGroup = array_intersect( $groupList[0], $groupList[1] ); 03605 03606 if ( count( $commonGroup ) > 0 ) 03607 { 03608 // ok, we have at least 1 common group 03609 $access = 'allowed'; 03610 } 03611 } 03612 } 03613 } 03614 } 03615 03616 return $access; 03617 } 03618 03619 /*! 03620 Check access for the current object 03621 03622 \param function name ( edit, read, remove, etc. ) 03623 \param original class ID ( used to check access for object creation ), default false 03624 \param parent class id ( used to check access for object creation ), default false 03625 \param return access list instead of access result (optional, default false ) 03626 03627 \return 1 if has access, 0 if not. 03628 If returnAccessList is set to true, access list is returned 03629 */ 03630 function checkAccess( $functionName, $originalClassID = false, $parentClassID = false, $returnAccessList = false, $language = false ) 03631 { 03632 $classID = $originalClassID; 03633 $user = eZUser::currentUser(); 03634 $userID = $user->attribute( 'contentobject_id' ); 03635 $origFunctionName = $functionName; 03636 03637 //include_once( 'kernel/classes/ezcontentlanguage.php' ); 03638 // Fetch the ID of the language if we get a string with a language code 03639 // e.g. 'eng-GB' 03640 $originalLanguage = $language; 03641 if ( is_string( $language ) && strlen( $language ) > 0 ) 03642 { 03643 $language = eZContentLanguage::idByLocale( $language ); 03644 } 03645 else 03646 { 03647 $language = false; 03648 } 03649 03650 // This will be filled in with the available languages of the object 03651 // if a Language check is performed. 03652 $languageList = false; 03653 03654 // The 'move' function simply reuses 'edit' for generic access 03655 // but adds another top-level check below 03656 // The original function is still available in $origFunctionName 03657 if ( $functionName == 'move' ) 03658 $functionName = 'edit'; 03659 03660 $accessResult = $user->hasAccessTo( 'content' , $functionName ); 03661 $accessWord = $accessResult['accessWord']; 03662 03663 /* 03664 // Uncomment this part if 'create' permissions should become implied 'edit'. 03665 // Merges in 'create' policies with 'edit' 03666 if ( $functionName == 'edit' && 03667 !in_array( $accessWord, array( 'yes', 'no' ) ) ) 03668 { 03669 // Add in create policies. 03670 $accessExtraResult = $user->hasAccessTo( 'content', 'create' ); 03671 if ( $accessExtraResult['accessWord'] != 'no' ) 03672 { 03673 $accessWord = $accessExtraResult['accessWord']; 03674 if ( isset( $accessExtraResult['policies'] ) ) 03675 { 03676 $accessResult['policies'] = array_merge( $accessResult['policies'], 03677 $accessExtraResult['policies'] ); 03678 } 03679 if ( isset( $accessExtraResult['accessList'] ) ) 03680 { 03681 $accessResult['accessList'] = array_merge( $accessResult['accessList'], 03682 $accessExtraResult['accessList'] ); 03683 } 03684 } 03685 } 03686 */ 03687 03688 if ( $origFunctionName == 'remove' or 03689 $origFunctionName == 'move' ) 03690 { 03691 $mainNode = $this->attribute( 'main_node' ); 03692 // We do not allow these actions on objects placed at top-level 03693 // - remove 03694 // - move 03695 if ( $mainNode and $mainNode->attribute( 'parent_node_id' ) <= 1 ) 03696 { 03697 return 0; 03698 } 03699 } 03700 03701 if ( $classID === false ) 03702 { 03703 $classID = $this->attribute( 'contentclass_id' ); 03704 } 03705 if ( $accessWord == 'yes' ) 03706 { 03707 return 1; 03708 } 03709 else if ( $accessWord == 'no' ) 03710 { 03711 if ( $functionName == 'edit' ) 03712 { 03713 // Check if we have 'create' access under the main parent 03714 if ( $this->attribute( 'current_version' ) == 1 && !$this->attribute( 'status' ) ) 03715 { 03716 $mainNode = eZNodeAssignment::fetchForObject( $this->attribute( 'id' ), $this->attribute( 'current_version' ) ); 03717 $parentObj = $mainNode[0]->attribute( 'parent_contentobject' ); 03718 $result = $parentObj->checkAccess( 'create', $this->attribute( 'contentclass_id' ), 03719 $parentObj->attribute( 'contentclass_id' ), false, $originalLanguage ); 03720 return $result; 03721 } 03722 else 03723 { 03724 return 0; 03725 } 03726 } 03727 03728 if ( $returnAccessList === false ) 03729 { 03730 return 0; 03731 } 03732 else 03733 { 03734 return $accessResult['accessList']; 03735 } 03736 } 03737 else 03738 { 03739 $policies =& $accessResult['policies']; 03740 $access = 'denied'; 03741 foreach ( array_keys( $policies ) as $pkey ) 03742 { 03743 $limitationArray =& $policies[ $pkey ]; 03744 if ( $access == 'allowed' ) 03745 { 03746 break; 03747 } 03748 03749 $limitationList = array(); 03750 if ( isset( $limitationArray['Subtree' ] ) ) 03751 { 03752 $checkedSubtree = false; 03753 } 03754 else 03755 { 03756 $checkedSubtree = true; 03757 $accessSubtree = false; 03758 } 03759 if ( isset( $limitationArray['Node'] ) ) 03760 { 03761 $checkedNode = false; 03762 } 03763 else 03764 { 03765 $checkedNode = true; 03766 $accessNode = false; 03767 } 03768 foreach ( array_keys( $limitationArray ) as $key ) 03769 { 03770 $access = 'denied'; 03771 switch( $key ) 03772 { 03773 case 'Class': 03774 { 03775 if ( $functionName == 'create' and 03776 !$originalClassID ) 03777 { 03778 $access = 'allowed'; 03779 } 03780 else if ( $functionName == 'create' and 03781 in_array( $classID, $limitationArray[$key] ) ) 03782 { 03783 $access = 'allowed'; 03784 } 03785 else if ( $functionName != 'create' and 03786 in_array( $this->attribute( 'contentclass_id' ), $limitationArray[$key] ) ) 03787 { 03788 $access = 'allowed'; 03789 } 03790 else 03791 { 03792 $access = 'denied'; 03793 $limitationList = array( 'Limitation' => $key, 03794 'Required' => $limitationArray[$key] ); 03795 } 03796 } break; 03797 03798 case 'ParentClass': 03799 { 03800 03801 if ( in_array( $this->attribute( 'contentclass_id' ), $limitationArray[$key] ) ) 03802 { 03803 $access = 'allowed'; 03804 } 03805 else 03806 { 03807 $access = 'denied'; 03808 $limitationList = array( 'Limitation' => $key, 03809 'Required' => $limitationArray[$key] ); 03810 } 03811 } break; 03812 03813 case 'ParentDepth': 03814 { 03815 $assignedNodes = $this->attribute( 'assigned_nodes' ); 03816 if ( count( $assignedNodes ) > 0 ) 03817 { 03818 foreach ( $assignedNodes as $assignedNode ) 03819 { 03820 $depth = $assignedNode->attribute( 'depth' ); 03821 if ( in_array( $depth, $limitationArray[$key] ) ) 03822 { 03823 $access = 'allowed'; 03824 break; 03825 } 03826 } 03827 } 03828 03829 if ( $access != 'allowed' ) 03830 { 03831 $access = 'denied'; 03832 $limitationList = array( 'Limitation' => $key, 03833 'Required' => $limitationArray[$key] ); 03834 } 03835 } break; 03836 03837 case 'Section': 03838 case 'User_Section': 03839 { 03840 if ( in_array( $this->attribute( 'section_id' ), $limitationArray[$key] ) ) 03841 { 03842 $access = 'allowed'; 03843 } 03844 else 03845 { 03846 $access = 'denied'; 03847 $limitationList = array( 'Limitation' => $key, 03848 'Required' => $limitationArray[$key] ); 03849 } 03850 } break; 03851 03852 case 'Language': 03853 { 03854 $languageMask = 0; 03855 // If we don't have a language list yet we need to fetch it 03856 // and optionally filter out based on $language. 03857 03858 if ( $functionName == 'create' ) 03859 { 03860 // If the function is 'create' we do not use the language_mask for matching. 03861 if ( $language !== false ) 03862 { 03863 $languageMask = $language; 03864 } 03865 else 03866 { 03867 // If the create is used and no language specified then 03868 // we need to match against all possible languages (which 03869 // is all bits set, ie. -1). 03870 $languageMask = -1; 03871 } 03872 } 03873 else 03874 { 03875 if ( $language !== false ) 03876 { 03877 if ( $languageList === false ) 03878 { 03879 $languageMask = (int)$this->attribute( 'language_mask' ); 03880 // We are restricting language check to just one language 03881 $languageMask &= (int)$language; 03882 // If the resulting mask is 0 it means that the user is trying to 03883 // edit a language which does not exist, ie. translating. 03884 // The mask will then become the language trying to edit. 03885 if ( $languageMask == 0 ) 03886 { 03887 $languageMask = $language; 03888 } 03889 } 03890 } 03891 else 03892 { 03893 $languageMask = -1; 03894 } 03895 } 03896 // Fetch limit mask for limitation list 03897 $limitMask = eZContentLanguage::maskByLocale( $limitationArray[$key] ); 03898 if ( ( $languageMask & $limitMask ) != 0 ) 03899 { 03900 $access = 'allowed'; 03901 } 03902 else 03903 { 03904 $access = 'denied'; 03905 $limitationList = array( 'Limitation' => $key, 03906 'Required' => $limitationArray[$key] ); 03907 } 03908 } break; 03909 03910 case 'Owner': 03911 { 03912 // if limitation value == 2, anonymous limited to current session. 03913 if ( in_array( 2, $limitationArray[$key] ) && 03914 $user->isAnonymous() ) 03915 { 03916 //include_once( 'kernel/classes/ezpreferences.php' ); 03917 $createdObjectIDList = eZPreferences::value( 'ObjectCreationIDList' ); 03918 if ( $createdObjectIDList && 03919 in_array( $this->ID, unserialize( $createdObjectIDList ) ) ) 03920 { 03921 $access = 'allowed'; 03922 } 03923 } 03924 else if ( $this->attribute( 'owner_id' ) == $userID || $this->ID == $userID ) 03925 { 03926 $access = 'allowed'; 03927 } 03928 if ( $access != 'allowed' ) 03929 { 03930 $access = 'denied'; 03931 $limitationList = array ( 'Limitation' => $key, 'Required' => $limitationArray[$key] ); 03932 } 03933 } break; 03934 03935 case 'Group': 03936 { 03937 $access = $this->checkGroupLimitationAccess( $limitationArray[$key], $userID ); 03938 03939 if ( $access != 'allowed' ) 03940 { 03941 $access = 'denied'; 03942 $limitationList = array ( 'Limitation' => $key, 03943 'Required' => $limitationArray[$key] ); 03944 } 03945 } break; 03946 03947 case 'Node': 03948 { 03949 $accessNode = false; 03950 $mainNodeID = $this->attribute( 'main_node_id' ); 03951 foreach ( $limitationArray[$key] as $nodeID ) 03952 { 03953 $node = eZContentObjectTreeNode::fetch( $nodeID, false, false ); 03954 $limitationNodeID = $node['main_node_id']; 03955 if ( $mainNodeID == $limitationNodeID ) 03956 { 03957 $access = 'allowed'; 03958 $accessNode = true; 03959 break; 03960 } 03961 } 03962 if ( $access != 'allowed' && $checkedSubtree && !$accessSubtree ) 03963 { 03964 $access = 'denied'; 03965 // ??? TODO: if there is a limitation on Subtree, return two limitations? 03966 $limitationList = array( 'Limitation' => $key, 03967 'Required' => $limitationArray[$key] ); 03968 } 03969 else 03970 { 03971 $access = 'allowed'; 03972 } 03973 $checkedNode = true; 03974 } break; 03975 03976 case 'Subtree': 03977 { 03978 $accessSubtree = false; 03979 $assignedNodes = $this->attribute( 'assigned_nodes' ); 03980 if ( count( $assignedNodes ) != 0 ) 03981 { 03982 foreach ( $assignedNodes as $assignedNode ) 03983 { 03984 $path = $assignedNode->attribute( 'path_string' ); 03985 $subtreeArray = $limitationArray[$key]; 03986 foreach ( $subtreeArray as $subtreeString ) 03987 { 03988 if ( strstr( $path, $subtreeString ) ) 03989 { 03990 $access = 'allowed'; 03991 $accessSubtree = true; 03992 break; 03993 } 03994 } 03995 } 03996 } 03997 else 03998 { 03999 $parentNodes = $this->attribute( 'parent_nodes' ); 04000 if ( count( $parentNodes ) == 0 ) 04001 { 04002 if ( $this->attribute( 'owner_id' ) == $userID || $this->ID == $userID ) 04003 { 04004 $access = 'allowed'; 04005 $accessSubtree = true; 04006 } 04007 } 04008 else 04009 { 04010 foreach ( $parentNodes as $parentNode ) 04011 { 04012 $parentNode = eZContentObjectTreeNode::fetch( $parentNode, false, false ); 04013 $path = $parentNode['path_string']; 04014 04015 $subtreeArray = $limitationArray[$key]; 04016 foreach ( $subtreeArray as $subtreeString ) 04017 { 04018 if ( strstr( $path, $subtreeString ) ) 04019 { 04020 $access = 'allowed'; 04021 $accessSubtree = true; 04022 break; 04023 } 04024 } 04025 } 04026 } 04027 } 04028 if ( $access != 'allowed' && $checkedNode && !$accessNode ) 04029 { 04030 $access = 'denied'; 04031 // ??? TODO: if there is a limitation on Node, return two limitations? 04032 $limitationList = array( 'Limitation' => $key, 04033 'Required' => $limitationArray[$key] ); 04034 } 04035 else 04036 { 04037 $access = 'allowed'; 04038 } 04039 $checkedSubtree = true; 04040 } break; 04041 04042 case 'User_Subtree': 04043 { 04044 $assignedNodes = $this->attribute( 'assigned_nodes' ); 04045 if ( count( $assignedNodes ) != 0 ) 04046 { 04047 foreach ( $assignedNodes as $assignedNode ) 04048 { 04049 $path = $assignedNode->attribute( 'path_string' ); 04050 $subtreeArray = $limitationArray[$key]; 04051 foreach ( $subtreeArray as $subtreeString ) 04052 { 04053 if ( strstr( $path, $subtreeString ) ) 04054 { 04055 $access = 'allowed'; 04056 } 04057 } 04058 } 04059 } 04060 else 04061 { 04062 $parentNodes = $this->attribute( 'parent_nodes' ); 04063 if ( count( $parentNodes ) == 0 ) 04064 { 04065 if ( $this->attribute( 'owner_id' ) == $userID || $this->ID == $userID ) 04066 { 04067 $access = 'allowed'; 04068 } 04069 } 04070 else 04071 { 04072 foreach ( $parentNodes as $parentNode ) 04073 { 04074 $parentNode = eZContentObjectTreeNode::fetch( $parentNode, false, false ); 04075 $path = $parentNode['path_string']; 04076 04077 $subtreeArray = $limitationArray[$key]; 04078 foreach ( $subtreeArray as $subtreeString ) 04079 { 04080 if ( strstr( $path, $subtreeString ) ) 04081 { 04082 $access = 'allowed'; 04083 break; 04084 } 04085 } 04086 } 04087 } 04088 } 04089 if ( $access != 'allowed' ) 04090 { 04091 $access = 'denied'; 04092 $limitationList = array( 'Limitation' => $key, 04093 'Required' => $limitationArray[$key] ); 04094 } 04095 } break; 04096 } 04097 if ( $access == 'denied' ) 04098 { 04099 break; 04100 } 04101 } 04102 04103 $policyList[] = array( 'PolicyID' => $pkey, 04104 'LimitationList' => $limitationList ); 04105 } 04106 04107 if ( $access == 'denied' ) 04108 { 04109 if ( $functionName == 'edit' ) 04110 { 04111 // Check if we have 'create' access under the main parent 04112 if ( $this->attribute( 'current_version' ) == 1 && !$this->attribute( 'status' ) ) 04113 { 04114 $mainNode = eZNodeAssignment::fetchForObject( $this->attribute( 'id' ), $this->attribute( 'current_version' ) ); 04115 $parentObj = $mainNode[0]->attribute( 'parent_contentobject' ); 04116 $result = $parentObj->checkAccess( 'create', $this->attribute( 'contentclass_id' ), 04117 $parentObj->attribute( 'contentclass_id' ), false, $originalLanguage ); 04118 if ( $result ) 04119 { 04120 $access = 'allowed'; 04121 } 04122 return $result; 04123 } 04124 } 04125 } 04126 04127 if ( $access == 'denied' ) 04128 { 04129 if ( $returnAccessList === false ) 04130 { 04131 return 0; 04132 } 04133 else 04134 { 04135 return array( 'FunctionRequired' => array ( 'Module' => 'content', 04136 'Function' => $origFunctionName, 04137 'ClassID' => $classID, 04138 'MainNodeID' => $this->attribute( 'main_node_id' ) ), 04139 'PolicyList' => $policyList ); 04140 } 04141 } 04142 else 04143 { 04144 return 1; 04145 } 04146 } 04147 } 04148 04149 // code-template::create-block: class-list-from-policy, is-object 04150 // code-template::auto-generated:START class-list-from-policy 04151 // This code is automatically generated from templates/classlistfrompolicy.ctpl 04152 // DO NOT EDIT THIS CODE DIRECTLY, CHANGE THE TEMPLATE FILE INSTEAD 04153 04154 function classListFromPolicy( $policy, $allowedLanguageCodes = false ) 04155 { 04156 $canCreateClassIDListPart = array(); 04157 $hasClassIDLimitation = false; 04158 if ( isset( $policy['Class'] ) ) 04159 { 04160 $canCreateClassIDListPart = $policy['Class']; 04161 $hasClassIDLimitation = true; 04162 } 04163 04164 if ( isset( $policy['User_Section'] ) ) 04165 { 04166 if ( !in_array( $this->attribute( 'section_id' ), $policy['User_Section'] ) ) 04167 { 04168 return array(); 04169 } 04170 } 04171 04172 if ( isset( $policy['User_Subtree'] ) ) 04173 { 04174 $allowed = false; 04175 $assignedNodes = $this->attribute( 'assigned_nodes' ); 04176 foreach ( $assignedNodes as $assignedNode ) 04177 { 04178 $path = $assignedNode->attribute( 'path_string' ); 04179 foreach ( $policy['User_Subtree'] as $subtreeString ) 04180 { 04181 if ( strstr( $path, $subtreeString ) ) 04182 { 04183 $allowed = true; 04184 break; 04185 } 04186 } 04187 } 04188 if( !$allowed ) 04189 { 04190 return array(); 04191 } 04192 } 04193 04194 if ( isset( $policy['Section'] ) ) 04195 { 04196 if ( !in_array( $this->attribute( 'section_id' ), $policy['Section'] ) ) 04197 { 04198 return array(); 04199 } 04200 } 04201 04202 if ( isset( $policy['ParentClass'] ) ) 04203 { 04204 if ( !in_array( $this->attribute( 'contentclass_id' ), $policy['ParentClass'] ) ) 04205 { 04206 return array(); 04207 } 04208 } 04209 04210 if ( isset( $policy['Assigned'] ) ) 04211 { 04212 if ( $this->attribute( 'owner_id' ) != $user->attribute( 'contentobject_id' ) ) 04213 { 04214 return array(); 04215 } 04216 } 04217 04218 $allowedNode = false; 04219 if ( isset( $policy['Node'] ) ) 04220 { 04221 $allowed = false; 04222 foreach( $policy['Node'] as $nodeID ) 04223 { 04224 $mainNodeID = $this->attribute( 'main_node_id' ); 04225 $node = eZContentObjectTreeNode::fetch( $nodeID, false, false ); 04226 if ( $mainNodeID == $node['main_node_id'] ) 04227 { 04228 $allowed = true; 04229 $allowedNode = true; 04230 break; 04231 } 04232 } 04233 if ( !$allowed && !isset( $policy['Subtree'] ) ) 04234 { 04235 return array(); 04236 } 04237 } 04238 04239 if ( isset( $policy['Subtree'] ) ) 04240 { 04241 $allowed = false; 04242 $assignedNodes = $this->attribute( 'assigned_nodes' ); 04243 foreach ( $assignedNodes as $assignedNode ) 04244 { 04245 $path = $assignedNode->attribute( 'path_string' ); 04246 foreach ( $policy['Subtree'] as $subtreeString ) 04247 { 04248 if ( strstr( $path, $subtreeString ) ) 04249 { 04250 $allowed = true; 04251 break; 04252 } 04253 } 04254 } 04255 if ( !$allowed && !$allowedNode ) 04256 { 04257 return array(); 04258 } 04259 } 04260 04261 if ( isset( $policy['Language'] ) ) 04262 { 04263 if ( $allowedLanguageCodes ) 04264 { 04265 $allowedLanguageCodes = array_intersect( $allowedLanguageCodes, $policy['Language'] ); 04266 } 04267 else 04268 { 04269 $allowedLanguageCodes = $policy['Language']; 04270 } 04271 } 04272 04273 if ( $hasClassIDLimitation ) 04274 { 04275 return array( 'classes' => $canCreateClassIDListPart, 'language_codes' => $allowedLanguageCodes ); 04276 } 04277 return array( 'classes' => '*', 'language_codes' => $allowedLanguageCodes ); 04278 } 04279 04280 // This code is automatically generated from templates/classlistfrompolicy.ctpl 04281 // code-template::auto-generated:END class-list-from-policy 04282 04283 // code-template::create-block: can-instantiate-class-list, group-filter, object-policy-list, name-create, object-creation, object-sql-creation 04284 // code-template::auto-generated:START can-instantiate-class-list 04285 // This code is automatically generated from templates/classcreatelist.ctpl 04286 // DO NOT EDIT THIS CODE DIRECTLY, CHANGE THE TEMPLATE FILE INSTEAD 04287 04288 /*! 04289 Finds all classes that the current user can create objects from and returns. 04290 It is also possible to filter the list event more with \a $includeFilter and \a $groupList. 04291 04292 \param $asObject If \c true then it return eZContentClass objects, if not it will 04293 be an associative array with \c name and \c id keys. 04294 \param $includeFilter If \c true then it will include only from class groups defined in 04295 \a $groupList, if not it will exclude those groups. 04296 \param $groupList An array with class group IDs that should be used in filtering, use 04297 \c false if you do not wish to filter at all. 04298 \param $id A unique name for the current fetch, this must be supplied when filtering is 04299 used if you want caching to work. 04300 */ 04301 function canCreateClassList( $asObject = false, $includeFilter = true, $groupList = false, $fetchID = false ) 04302 { 04303 $ini = eZINI::instance(); 04304 $groupArray = array(); 04305 $languageCodeList = eZContentLanguage::fetchLocaleList(); 04306 $allowedLanguages = array( '*' => array() ); 04307 04308 $user = eZUser::currentUser(); 04309 $accessResult = $user->hasAccessTo( 'content' , 'create' ); 04310 $accessWord = $accessResult['accessWord']; 04311 04312 $classIDArray = array(); 04313 $classList = array(); 04314 $fetchAll = false; 04315 if ( $accessWord == 'yes' ) 04316 { 04317 $fetchAll = true; 04318 $allowedLanguages['*'] = $languageCodeList; 04319 } 04320 else if ( $accessWord == 'no' ) 04321 { 04322 // Cannnot create any objects, return empty list. 04323 return $classList; 04324 } 04325 else 04326 { 04327 $policies = $accessResult['policies']; 04328 foreach ( $policies as $policyKey => $policy ) 04329 { 04330 $policyArray = $this->classListFromPolicy( $policy, $languageCodeList ); 04331 if ( count( $policyArray ) == 0 ) 04332 { 04333 continue; 04334 } 04335 $classIDArrayPart = $policyArray['classes']; 04336 $languageCodeArrayPart = $policyArray['language_codes']; 04337 if ( $classIDArrayPart == '*' ) 04338 { 04339 $fetchAll = true; 04340 $allowedLanguages['*'] = array_unique( array_merge( $allowedLanguages['*'], $languageCodeArrayPart ) ); 04341 } 04342 else 04343 { 04344 foreach( $classIDArrayPart as $class ) 04345 { 04346 if ( isset( $allowedLanguages[$class] ) ) 04347 { 04348 $allowedLanguages[$class] = array_unique( array_merge( $allowedLanguages[$class], $languageCodeArrayPart ) ); 04349 } 04350 else 04351 { 04352 $allowedLanguages[$class] = $languageCodeArrayPart; 04353 } 04354 } 04355 $classIDArray = array_merge( $classIDArray, array_diff( $classIDArrayPart, $classIDArray ) ); 04356 } 04357 } 04358 } 04359 04360 $db = eZDB::instance(); 04361 04362 $filterTableSQL = ''; 04363 $filterSQL = ''; 04364 // Create extra SQL statements for the class group filters. 04365 if ( is_array( $groupList ) ) 04366 { 04367 if ( count( $groupList ) == 0 ) 04368 { 04369 return $classList; 04370 } 04371 04372 $filterTableSQL = ', ezcontentclass_classgroup ccg'; 04373 $filterSQL = ( " AND\n" . 04374 " cc.id = ccg.contentclass_id AND\n" . 04375 " " ); 04376 $filterSQL .= $db->generateSQLINStatement( $groupList, 'ccg.group_id', !$includeFilter, true, 'int' ); 04377 } 04378 04379 $classNameFilter = eZContentClassName::sqlFilter( 'cc' ); 04380 04381 if ( $fetchAll ) 04382 { 04383 // If $asObject is true we fetch all fields in class 04384 $fields = $asObject ? "cc.*, $classNameFilter[nameField]" : "cc.id, $classNameFilter[nameField]"; 04385 $rows = $db->arrayQuery( "SELECT DISTINCT $fields\n" . 04386 "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from]\n" . 04387 "WHERE cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . " $filterSQL AND $classNameFilter[where]\n" . 04388 "ORDER BY $classNameFilter[nameField] ASC" ); 04389 $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject ); 04390 } 04391 else 04392 { 04393 // If the constrained class list is empty we are not allowed to create any class 04394 if ( count( $classIDArray ) == 0 ) 04395 { 04396 return $classList; 04397 } 04398 04399 $classIDCondition = $db->generateSQLInStatement( $classIDArray, 'cc.id' ); 04400 // If $asObject is true we fetch all fields in class 04401 $fields = $asObject ? "cc.*, $classNameFilter[nameField]" : "cc.id, $classNameFilter[nameField]"; 04402 $rows = $db->arrayQuery( "SELECT DISTINCT $fields\n" . 04403 "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from]\n" . 04404 "WHERE $classIDCondition AND\n" . 04405 " cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . " $filterSQL AND $classNameFilter[where]\n" . 04406 "ORDER BY $classNameFilter[nameField] ASC" ); 04407 $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject ); 04408 } 04409 04410 if ( $asObject ) 04411 { 04412 foreach ( $classList as $key => $class ) 04413 { 04414 $id = $class->attribute( 'id' ); 04415 if ( isset( $allowedLanguages[$id] ) ) 04416 { 04417 $languageCodes = array_unique( array_merge( $allowedLanguages['*'], $allowedLanguages[$id] ) ); 04418 } 04419 else 04420 { 04421 $languageCodes = $allowedLanguages['*']; 04422 } 04423 $classList[$key]->setCanInstantiateLanguages( $languageCodes ); 04424 } 04425 } 04426 04427 eZDebugSetting::writeDebug( 'kernel-content-class', $classList, "class list fetched from db" ); 04428 return $classList; 04429 } 04430 04431 // This code is automatically generated from templates/classcreatelist.ctpl 04432 // code-template::auto-generated:END can-instantiate-class-list 04433 04434 /*! 04435 Get accesslist for specified function 04436 04437 \param function 04438 04439 \return AccessList 04440 */ 04441 function accessList( $function ) 04442 { 04443 switch( $function ) 04444 { 04445 case 'read': 04446 { 04447 return $this->checkAccess( 'read', false, false, true ); 04448 } break; 04449 04450 case 'edit': 04451 { 04452 return $this->checkAccess( 'edit', false, false, true ); 04453 } break; 04454 } 04455 return 0; 04456 } 04457 04458 /*! 04459 \return \c true if the current user can read this content object. 04460 \note The reference for the return value is required to workaround 04461 a bug with PHP references. 04462 */ 04463 function canRead( ) 04464 { 04465 if ( !isset( $this->Permissions["can_read"] ) ) 04466 { 04467 $this->Permissions["can_read"] = $this->checkAccess( 'read' ); 04468 } 04469 return ( $this->Permissions["can_read"] == 1 ); 04470 } 04471 04472 /*! 04473 \return \c true if the current user can create a pdf of this content object. 04474 \note The reference for the return value is required to workaround 04475 a bug with PHP references. 04476 */ 04477 function canPdf( ) 04478 { 04479 if ( !isset( $this->Permissions["can_pdf"] ) ) 04480 { 04481 $this->Permissions["can_pdf"] = $this->checkAccess( 'pdf' ); 04482 } 04483 return ( $this->Permissions["can_pdf"] == 1 ); 04484 } 04485 04486 /*! 04487 \return \c true if the node can be viewed as embeded object by the current user. 04488 \sa checkAccess(). 04489 \note The reference for the return value is required to workaround 04490 a bug with PHP references. 04491 */ 04492 function canViewEmbed( ) 04493 { 04494 if ( !isset( $this->Permissions["can_view_embed"] ) ) 04495 { 04496 $this->Permissions["can_view_embed"] = $this->checkAccess( 'view_embed' ); 04497 } 04498 return ( $this->Permissions["can_view_embed"] == 1 ); 04499 } 04500 04501 /*! 04502 \return \c true if the current user can diff this content object. 04503 \note The reference for the return value is required to workaround 04504 a bug with PHP references. 04505 */ 04506 function canDiff( ) 04507 { 04508 if ( !isset( $this->Permissions["can_diff"] ) ) 04509 { 04510 $this->Permissions["can_diff"] = $this->checkAccess( 'diff' ); 04511 } 04512 return ( $this->Permissions["can_diff"] == 1 ); 04513 } 04514 04515 /*! 04516 \note The reference for the return value is required to workaround 04517 a bug with PHP references. 04518 */ 04519 function canCreate( ) 04520 { 04521 if ( !isset( $this->Permissions["can_create"] ) ) 04522 { 04523 $this->Permissions["can_create"] = $this->checkAccess( 'create' ); 04524 } 04525 return ( $this->Permissions["can_create"] == 1 ); 04526 } 04527 04528 /*! 04529 \note The reference for the return value is required to workaround 04530 a bug with PHP references. 04531 */ 04532 function canEdit( $originalClassID = false, $parentClassID = false, $returnAccessList = false, $language = false ) 04533 { 04534 $isCalledClean = ( func_num_args() == 0 ); 04535 if ( isset( $this->Permissions["can_edit"] ) && $isCalledClean ) 04536 { 04537 $canEdit = $this->Permissions["can_edit"]; 04538 } 04539 else 04540 { 04541 $canEdit = $this->checkAccess( 'edit', $originalClassID, $parentClassID, $returnAccessList, $language ); 04542 if ( $canEdit != 1 ) 04543 { 04544 $user = eZUser::currentUser(); 04545 if ( $user->attribute( 'contentobject_id' ) === $this->attribute( 'id' ) ) 04546 { 04547 $access = $user->hasAccessTo( 'user', 'selfedit' ); 04548 if ( $access['accessWord'] == 'yes' ) 04549 { 04550 $canEdit = 1; 04551 } 04552 } 04553 } 04554 04555 if ( $isCalledClean ) 04556 { 04557 $this->Permissions["can_edit"] = $canEdit; 04558 } 04559 } 04560 return ( $canEdit == 1 ); 04561 } 04562 04563 /*! 04564 \note The reference for the return value is required to workaround 04565 a bug with PHP references. 04566 */ 04567 function canTranslate( ) 04568 { 04569 if ( !isset( $this->Permissions["can_translate"] ) ) 04570 { 04571 $this->Permissions["can_translate"] = $this->checkAccess( 'translate' ); 04572 if ( $this->Permissions["can_translate"] != 1 ) 04573 { 04574 $user = eZUser::currentUser(); 04575 if ( $user->id() == $this->attribute( 'id' ) ) 04576 { 04577 $access = $user->hasAccessTo( 'user', 'selfedit' ); 04578 if ( $access['accessWord'] == 'yes' ) 04579 { 04580 $this->Permissions["can_translate"] = 1; 04581 } 04582 } 04583 } 04584 } 04585 return ( $this->Permissions["can_translate"] == 1 ); 04586 } 04587 04588 /*! 04589 \note The reference for the return value is required to workaround 04590 a bug with PHP references. 04591 */ 04592 function canRemove( ) 04593 { 04594 04595 if ( !isset( $this->Permissions["can_remove"] ) ) 04596 { 04597 $this->Permissions["can_remove"] = $this->checkAccess( 'remove' ); 04598 } 04599 return ( $this->Permissions["can_remove"] == 1 ); 04600 } 04601 04602 /*! 04603 Check if the object can be moved. (actually checks 'edit' and 'remove' permissions) 04604 \return \c true if the object can be moved by the current user. 04605 \sa checkAccess(). 04606 \note The reference for the return value is required to workaround 04607 a bug with PHP references. 04608 \deprecated The function canMove() is preferred since its naming is clearer. 04609 */ 04610 function canMove( ) 04611 { 04612 return $this->canMoveFrom(); 04613 } 04614 04615 /*! 04616 Check if the object can be moved. (actually checks 'edit' and 'remove' permissions) 04617 \return \c true if the object can be moved by the current user. 04618 \sa checkAccess(). 04619 \note The reference for the return value is required to workaround 04620 a bug with PHP references. 04621 */ 04622 function canMoveFrom( ) 04623 { 04624 04625 if ( !isset( $this->Permissions['can_move_from'] ) ) 04626 { 04627 $this->Permissions['can_move_from'] = $this->checkAccess( 'edit' ) && $this->checkAccess( 'remove' ); 04628 } 04629 return ( $this->Permissions['can_move_from'] == 1 ); 04630 } 04631 04632 /*! 04633 \return The name of the class which this object was created from. 04634 04635 \note The object will cache the class name information so multiple calls will be fast. 04636 */ 04637 function className() 04638 { 04639 if ( !is_numeric( $this->ClassID ) ) 04640 { 04641 return null; 04642 } 04643 04644 if ( $this->ClassName !== false ) 04645 return $this->ClassName; 04646 04647 $db = eZDB::instance(); 04648 $id = (int)$this->ClassID; 04649 $sql = "SELECT serialized_name_list FROM ezcontentclass WHERE id=$id and version=0"; 04650 $rows = $db->arrayQuery( $sql ); 04651 if ( count( $rows ) > 0 ) 04652 { 04653 $this->ClassName = eZContentClass::nameFromSerializedString( $rows[0]['serialized_name_list'] ); 04654 } 04655 return $this->ClassName; 04656 } 04657 04658 /*! 04659 Returns an array of the content actions which can be performed on 04660 the current object. 04661 */ 04662 function contentActionList() 04663 { 04664 $version = $this->attribute( 'current_version' ); 04665 $language = $this->initialLanguageCode(); 04666 if ( !isset( $this->ContentObjectAttributeArray[$version][$language] ) ) 04667 { 04668 $attributeList = $this->contentObjectAttributes(); 04669 $this->ContentObjectAttributeArray[$version][$language] =& $attributeList; 04670 } 04671 else 04672 $attributeList = $this->ContentObjectAttributeArray[$version][$language]; 04673 04674 // Fetch content actions if not already fetched 04675 if ( $this->ContentActionList === false ) 04676 { 04677 04678 $contentActionList = array(); 04679 foreach ( $attributeList as $attribute ) 04680 { 04681 $contentActions = $attribute->contentActionList(); 04682 if ( count( $contentActions ) > 0 ) 04683 { 04684 $contentActionList = $attribute->contentActionList(); 04685 04686 if ( is_array( $contentActionList ) ) 04687 { 04688 foreach ( $contentActionList as $action ) 04689 { 04690 if ( !$this->hasContentAction( $action['action'] ) ) 04691 { 04692 $this->ContentActionList[] = $action; 04693 } 04694 } 04695 } 04696 } 04697 } 04698 } 04699 return $this->ContentActionList; 04700 } 04701 04702 /*! 04703 \return true if the content action is in the content action list 04704 */ 04705 function hasContentAction( $name ) 04706 { 04707 $return = false; 04708 if ( is_array ( $this->ContentActionList ) ) 04709 { 04710 foreach ( $this->ContentActionList as $action ) 04711 { 04712 if ( $action['action'] == $name ) 04713 { 04714 $return = true; 04715 } 04716 } 04717 } 04718 return $return; 04719 } 04720 04721 /*! 04722 \return the languages the object has been translated into/exists in. 04723 04724 Returns an array with the language codes. 04725 04726 It uses the attribute \c avail_lang as the source for the language list. 04727 */ 04728 function availableLanguages() 04729 { 04730 $languages = array(); 04731 $languageObjects = $this->languages(); 04732 04733 foreach ( $languageObjects as $languageObject ) 04734 { 04735 $languages[] = $languageObject->attribute( 'locale' ); 04736 } 04737 04738 return $languages; 04739 } 04740 04741 function availableLanguagesJsArray() 04742 { 04743 return eZContentLanguage::jsArrayByMask( $this->LanguageMask ); 04744 } 04745 04746 function languages() 04747 { 04748 return isset( $this->LanguageMask ) ? 04749 eZContentLanguage::prioritizedLanguagesByMask( $this->LanguageMask ) : 04750 array(); 04751 } 04752 04753 function allLanguages() 04754 { 04755 $languages = isset( $this->LanguageMask ) ? eZContentLanguage::languagesByMask( $this->LanguageMask ) : array(); 04756 return $languages; 04757 } 04758 04759 static function defaultLanguage() 04760 { 04761 if ( ! isset( $GLOBALS['eZContentObjectDefaultLanguage'] ) ) 04762 { 04763 $defaultLanguage = false; 04764 $language = eZContentLanguage::topPriorityLanguage(); 04765 if ( $language ) 04766 { 04767 $defaultLanguage = $language->attribute( 'locale' ); 04768 } 04769 else 04770 { 04771 $ini = eZINI::instance(); 04772 if ( $ini->hasVariable( 'RegionalSettings', 'ContentObjectLocale' ) ) 04773 { 04774 $defaultLanguage = $ini->variable( 'RegionalSettings', 'ContentObjectLocale' ); 04775 eZContentLanguage::fetchByLocale( $defaultLanguage, true ); 04776 } 04777 } 04778 $GLOBALS['eZContentObjectDefaultLanguage'] = $defaultLanguage; 04779 } 04780 04781 return $GLOBALS['eZContentObjectDefaultLanguage']; 04782 } 04783 04784 /*! 04785 \static 04786 Set default language. Checks if default language is valid. 04787 04788 \param default language. 04789 \note Deprecated. 04790 */ 04791 static function setDefaultLanguage( $lang ) 04792 { 04793 return false; 04794 } 04795 04796 /*! 04797 04798 */ 04799 function setClassName( $name ) 04800 { 04801 $this->ClassName = $name; 04802 } 04803 04804 /*! 04805 \returns an array with locale strings, these strings represents the languages which content objects are allowed to be translated into. 04806 \note the setting ContentSettings/TranslationList in site.ini determines the array. 04807 \sa translationList 04808 */ 04809 static function translationStringList() 04810 { 04811 $translationList = array(); 04812 $languageList = eZContentLanguage::fetchList(); 04813 04814 foreach ( $languageList as $language ) 04815 { 04816 $translationList[] = $language->attribute( 'locale' ); 04817 } 04818 04819 return $translationList; 04820 } 04821 04822 /*! 04823 \returns an array with locale objects, these objects represents the languages the content objects are allowed to be translated into. 04824 \note the setting ContentSettings/TranslationList in site.ini determines the array. 04825 \sa translationStringList 04826 */ 04827 static function translationList() 04828 { 04829 $translationList = array(); 04830 $languageList = eZContentLanguage::fetchList(); 04831 04832 foreach ( $languageList as $language ) 04833 { 04834 $translationList[] = $language->localeObject(); 04835 } 04836 04837 return $translationList; 04838 } 04839 04840 /*! 04841 Returns the attributes for the content object version \a $version and content object \a $contentObjectID. 04842 \a $language defines the language to fetch. 04843 \sa attributes 04844 */ 04845 function fetchClassAttributes( $version = 0, $asObject = true ) 04846 { 04847 return eZContentClassAttribute::fetchListByClassID( $this->attribute( 'contentclass_id' ), $version, $asObject ); 04848 } 04849 04850 /*! 04851 \private 04852 Maps input lange to another one if defined in $options['language_map']. 04853 If it cannot map it returns the original language. 04854 \returns string 04855 */ 04856 static function mapLanguage( $language, $options ) 04857 { 04858 if ( isset( $options['language_map'][$language] ) ) 04859 { 04860 return $options['language_map'][$language]; 04861 } 04862 return $language; 04863 } 04864 04865 /*! 04866 \static 04867 Unserialize xml structure. Create object from xml input. 04868 04869 \param package 04870 \param XML DOM Node 04871 \param parent node object. 04872 \param Options 04873 \param owner ID, override owner ID, null to use XML owner id (optional) 04874 04875 \returns created object, false if could not create object/xml invalid 04876 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 04877 the calls within a db transaction; thus within db->begin and db->commit. 04878 */ 04879 static function unserialize( $package, $domNode, &$options, $ownerID = false, $handlerType = 'ezcontentobject' ) 04880 { 04881 if ( $domNode->localName != 'object' ) 04882 { 04883 $retValue = false; 04884 return $retValue; 04885 } 04886 04887 $initialLanguage = eZContentObject::mapLanguage( $domNode->getAttribute( 'initial_language' ), $options ); 04888 if( $initialLanguage === 'skip' ) 04889 { 04890 $retValue = true; 04891 return $retValue; 04892 } 04893 04894 $sectionID = $domNode->getAttributeNS( 'http://ez.no/ezobject', 'section_id' ); 04895 if ( $ownerID === false ) 04896 { 04897 $ownerID = $domNode->getAttributeNS( 'http://ez.no/ezobject', 'owner_id' ); 04898 } 04899 $remoteID = $domNode->getAttribute( 'remote_id' ); 04900 $name = $domNode->getAttribute( 'name' ); 04901 $classRemoteID = $domNode->getAttribute( 'class_remote_id' ); 04902 $classIdentifier = $domNode->getAttributeNS( 'http://ez.no/ezobject', 'class_identifier' ); 04903 $alwaysAvailable = ( $domNode->getAttributeNS( 'http://ez.no/ezobject', 'always_available' ) == '1' ); 04904 04905 $contentClass = eZContentClass::fetchByRemoteID( $classRemoteID ); 04906 if ( !$contentClass ) 04907 { 04908 $contentClass = eZContentClass::fetchByIdentifier( $classIdentifier ); 04909 } 04910 04911 if ( !$contentClass ) 04912 { 04913 $options['error'] = array( 'error_code' => eZContentObject::PACKAGE_ERROR_NO_CLASS, 04914 'element_id' => $remoteID, 04915 'description' => "Can't install object '$name': Unable to fetch class with remoteID: $classRemoteID." ); 04916 $retValue = false; 04917 return $retValue; 04918 } 04919 04920 $versionListNode = $domNode->getElementsByTagName( 'version-list' )->item( 0 ); 04921 04922 $importedLanguages = array(); 04923 foreach( $versionListNode->getElementsByTagName( 'version' ) as $versionDOMNode ) 04924 { 04925 foreach ( $versionDOMNode->getElementsByTagName( 'object-translation' ) as $versionDOMNodeChild ) 04926 { 04927 $importedLanguage = eZContentObject::mapLanguage( $versionDOMNodeChild->getAttribute( 'language' ), $options ); 04928 $language = eZContentLanguage::fetchByLocale( $importedLanguage ); 04929 // Check if the language is allowed in this setup. 04930 if ( $language ) 04931 { 04932 $hasTranslation = true; 04933 } 04934 else 04935 { 04936 if ( $importedLanguage == 'skip' ) 04937 continue; 04938 04939 // if there is no needed translation in system then add it 04940 $locale = eZLocale::instance( $importedLanguage ); 04941 $translationName = $locale->internationalLanguageName(); 04942 $translationLocale = $locale->localeCode(); 04943 04944 if ( $locale->isValid() ) 04945 { 04946 eZContentLanguage::addLanguage( $locale->localeCode(), $locale->internationalLanguageName() ); 04947 $hasTranslation = true; 04948 } 04949 else 04950 $hasTranslation = false; 04951 } 04952 if ( $hasTranslation ) 04953 { 04954 $importedLanguages[] = $importedLanguage; 04955 $importedLanguages = array_unique( $importedLanguages ); 04956 } 04957 } 04958 } 04959 04960 // If object exists we return a error. 04961 // Minimum instal element is an object now. 04962 04963 $contentObject = eZContentObject::fetchByRemoteID( $remoteID ); 04964 // Figure out initial language 04965 if ( !$initialLanguage || 04966 !in_array( $initialLanguage, $importedLanguages ) ) 04967 { 04968 $initialLanguage = false; 04969 foreach ( eZContentLanguage::prioritizedLanguages() as $language ) 04970 { 04971 if ( in_array( $language->attribute( 'locale' ), $importedLanguages ) ) 04972 { 04973 $initialLanguage = $language->attribute( 'locale' ); 04974 break; 04975 } 04976 } 04977 } 04978 if ( !$contentObject ) 04979 { 04980 $firstVersion = true; 04981 $contentObject = $contentClass->instantiateIn( $initialLanguage, $ownerID, $sectionID ); 04982 } 04983 else 04984 { 04985 $firstVersion = false; 04986 $description = "Object '$name' already exists."; 04987 04988 // include_once( 'kernel/classes/ezpackagehandler.php' ); 04989 $choosenAction = eZPackageHandler::errorChoosenAction( eZContentObject::PACKAGE_ERROR_EXISTS, 04990 $options, $description, $handlerType, false ); 04991 04992 switch( $choosenAction ) 04993 { 04994 case eZPackage::NON_INTERACTIVE: 04995 { 04996 // Keep existing contentobject. 04997 } break; 04998 04999 case eZContentObject::PACKAGE_REPLACE: 05000 { 05001 //include_once( 'kernel/classes/ezcontentobjectoperations.php' ); 05002 eZContentObjectOperations::remove( $contentObject->attribute( 'id' ) ); 05003 05004 unset( $contentObject ); 05005 $contentObject = $contentClass->instantiateIn( $initialLanguage, $ownerID, $sectionID ); 05006 $firstVersion = true; 05007 } break; 05008 05009 case eZContentObject::PACKAGE_SKIP: 05010 { 05011 $retValue = true; 05012 return $retValue; 05013 } break; 05014 05015 case eZContentObject::PACKAGE_NEW: 05016 { 05017 $contentObject->setAttribute( 'remote_id', md5( (string)mt_rand() . (string)time() ) ); 05018 $contentObject->store(); 05019 unset( $contentObject ); 05020 $contentObject = $contentClass->instantiate( $ownerID, $sectionID ); 05021 $firstVersion = true; 05022 } break; 05023 05024 default: 05025 { 05026 $options['error'] = array( 'error_code' => eZContentObject::PACKAGE_ERROR_EXISTS, 05027 'element_id' => $remoteID, 05028 'description' => $description, 05029 'actions' => array( eZContentObject::PACKAGE_REPLACE => 'Replace existing object', 05030 eZContentObject::PACKAGE_SKIP => 'Skip object', 05031 eZContentObject::PACKAGE_NEW => 'Keep existing and create a new one' ) ); 05032 $retValue = false; 05033 return $retValue; 05034 } break; 05035 } 05036 } 05037 05038 $db = eZDB::instance(); 05039 $db->begin(); 05040 05041 if ( $alwaysAvailable ) 05042 { 05043 // Make sure always available bit is set. 05044 $contentObject->setAttribute( 'language_mask', (int)$contentObject->attribute( 'language_mask' ) | 1 ); 05045 } 05046 05047 $contentObject->setAttribute( 'section_id', $sectionID ); 05048 $contentObject->store(); 05049 $activeVersion = false; 05050 $lastVersion = false; 05051 $versionListActiveVersion = $versionListNode->getAttribute( 'active_version' ); 05052 05053 $contentObject->setAttribute( 'remote_id', $remoteID ); 05054 $contentObject->setAttribute( 'contentclass_id', $contentClass->attribute( 'id' ) ); 05055 $contentObject->store(); 05056 05057 $sectionObject = eZSection::fetch( $sectionID ); 05058 if ( $sectionObject instanceof eZSection ) 05059 { 05060 $updateWithParentSection = false; 05061 } 05062 else 05063 { 05064 $updateWithParentSection = true; 05065 } 05066 05067 $options['language_array'] = $importedLanguages; 05068 $versionList = array(); 05069 foreach( $versionListNode->getElementsByTagName( 'version' ) as $versionDOMNode ) 05070 { 05071 unset( $nodeList ); 05072 $nodeList = array(); 05073 $contentObjectVersion = eZContentObjectVersion::unserialize( $versionDOMNode, 05074 $contentObject, 05075 $ownerID, 05076 $sectionID, 05077 $versionListActiveVersion, 05078 $firstVersion, 05079 $nodeList, 05080 $options, 05081 $package ); 05082 05083 if ( !$contentObjectVersion ) 05084 { 05085 $db->commit(); 05086 05087 $retValue = false; 05088 return $retValue; 05089 } 05090 05091 $versionStatus = $versionDOMNode->getAttributeNS( 'http://ez.no/ezobject', 'status' ); 05092 $versionList[$versionDOMNode->getAttributeNS( 'http://ez.no/ezobject', 'version' )] = array( 'node_list' => $nodeList, 05093 'status' => $versionStatus ); 05094 unset( $versionStatus ); 05095 05096 $firstVersion = false; 05097 $lastVersion = $contentObjectVersion->attribute( 'version' ); 05098 if ( $versionDOMNode->getAttribute( 'version' ) == $versionListActiveVersion ) 05099 { 05100 $activeVersion = $contentObjectVersion->attribute( 'version' ); 05101 } 05102 eZNodeAssignment::setNewMainAssignment( $contentObject->attribute( 'id' ), $lastVersion ); 05103 05104 //include_once( 'lib/ezutils/classes/ezoperationhandler.php' ); 05105 eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $contentObject->attribute( 'id' ), 05106 'version' => $lastVersion ) ); 05107 05108 $mainNodeInfo = null; 05109 foreach ( $nodeList as $nodeInfo ) 05110 { 05111 if ( $nodeInfo['is_main'] ) 05112 { 05113 $mainNodeInfo =& $nodeInfo; 05114 break; 05115 } 05116 } 05117 if ( $mainNodeInfo ) 05118 { 05119 $existingMainNode = eZContentObjectTreeNode::fetchByRemoteID( $mainNodeInfo['parent_remote_id'], false ); 05120 if ( $existingMainNode ) 05121 { 05122 eZContentObjectTreeNode::updateMainNodeID( $existingMainNode['node_id'], 05123 $mainNodeInfo['contentobject_id'], 05124 $mainNodeInfo['contentobject_version'], 05125 $mainNodeInfo['parent_node'], 05126 $updateWithParentSection ); 05127 } 05128 } 05129 unset( $mainNodeInfo ); 05130 // Refresh $contentObject from DB. 05131 $contentObject = eZContentObject::fetch( $contentObject->attribute( 'id' ) ); 05132 } 05133 if ( !$activeVersion ) 05134 { 05135 $activeVersion = $lastVersion; 05136 } 05137 05138 /* 05139 $contentObject->setAttribute( 'current_version', $activeVersion ); 05140 */ 05141 $contentObject->setAttribute( 'name', $name ); 05142 if ( isset( $options['use_dates_from_package'] ) && $options['use_dates_from_package'] ) 05143 { 05144 $contentObject->setAttribute( 'published', eZDateUtils::textToDate( $domNode->getAttributeNS( 'http://ez.no/ezobject', 'published' ) ) ); 05145 $contentObject->setAttribute( 'modified', eZDateUtils::textToDate( $domNode->getAttributeNS( 'http://ez.no/ezobject', 'modified' ) ) ); 05146 } 05147 $contentObject->store(); 05148 05149 $versions = $contentObject->versions(); 05150 $objectName = $contentObject->name(); 05151 $objectID = $contentObject->attribute( 'id' ); 05152 foreach ( $versions as $version ) 05153 { 05154 $versionNum = $version->attribute( 'version' ); 05155 $oldVersionStatus = $version->attribute( 'status' ); 05156 $newVersionStatus = isset( $versionList[$versionNum] ) ? $versionList[$versionNum]['status'] : null; 05157 05158 // set the correct status for non-published versions 05159 if ( isset( $newVersionStatus ) && $oldVersionStatus != $newVersionStatus && $newVersionStatus != eZContentObjectVersion::STATUS_PUBLISHED ) 05160 { 05161 $version->setAttribute( 'status', $newVersionStatus ); 05162 $version->store( array( 'status' ) ); 05163 } 05164 05165 // when translation does not have object name set then we copy object name from the current object version 05166 $translations = $version->translations( false ); 05167 if ( !$translations ) 05168 continue; 05169 foreach ( $translations as $translation ) 05170 { 05171 if ( ! $contentObject->name( $versionNum, $translation ) ) 05172 { 05173 eZDebug::writeNotice( "Setting name '$objectName' for version ($versionNum) of the content object ($objectID) in language($translation)" ); 05174 $contentObject->setName( $objectName, $versionNum, $translation ); 05175 } 05176 } 05177 } 05178 05179 foreach ( $versionList[$versionListActiveVersion]['node_list'] as $nodeInfo ) 05180 { 05181 unset( $parentNode ); 05182 $parentNode = eZContentObjectTreeNode::fetchNode( $contentObject->attribute( 'id' ), 05183 $nodeInfo['parent_node'] ); 05184 if ( is_object( $parentNode ) ) 05185 { 05186 $parentNode->setAttribute( 'priority', $nodeInfo['priority'] ); 05187 $parentNode->store( array( 'priority' ) ); 05188 } 05189 } 05190 05191 $db->commit(); 05192 05193 return $contentObject; 05194 } 05195 05196 /*! 05197 Performs additional unserialization actions that need to be performed when all 05198 objects contained in the package are already installed. (maintain objects' cross-relations) 05199 */ 05200 05201 function postUnserialize( $package ) 05202 { 05203 foreach( $this->versions() as $version ) 05204 { 05205 $version->postUnserialize( $package ); 05206 } 05207 } 05208 05209 /*! 05210 \return a DOM structure of the content object and it's attributes. 05211 05212 \param package 05213 \param Content object version, true for current version, false for all, else array containing specific versions. 05214 \param package options ( optianal ) 05215 \param array of allowed nodes ( optional ) 05216 \param array of top nodes in current package export (optional ) 05217 05218 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 05219 the calls within a db transaction; thus within db->begin and db->commit. 05220 */ 05221 function serialize( $package, $specificVersion = false, $options = false, $contentNodeIDArray = false, $topNodeIDArray = false ) 05222 { 05223 if ( $options && 05224 $options['node_assignment'] == 'main' ) 05225 { 05226 if ( !isset( $contentNodeIDArray[$this->attribute( 'main_node_id' )] ) ) 05227 { 05228 return false; 05229 } 05230 } 05231 05232 //include_once( 'lib/ezlocale/classes/ezdateutils.php' ); 05233 05234 $dom = new DomDocument(); 05235 $objectNode = $dom->createElementNS( 'http://ez.no/ezobject', 'ezremote:object' ); 05236 05237 $objectNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:id', $this->ID ); 05238 $objectNode->setAttribute( 'name', $this->Name ); 05239 $objectNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:section_id', $this->SectionID ); 05240 $objectNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:owner_id', $this->OwnerID ); 05241 $objectNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:class_id', $this->ClassID ); 05242 $objectNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:published', eZDateUtils::rfc1123Date( $this->attribute( 'published' ) ) ); 05243 $objectNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:modified', eZDateUtils::rfc1123Date( $this->attribute( 'modified' ) ) ); 05244 if ( !$this->attribute( 'remote_id' ) ) 05245 { 05246 $this->setAttribute( 'remote_id', md5( (string)mt_rand() ) . (string)time() ); 05247 $this->store(); 05248 } 05249 $objectNode->setAttribute( 'remote_id', $this->attribute( 'remote_id' ) ); 05250 $contentClass = $this->attribute( 'content_class' ); 05251 $objectNode->setAttribute( 'class_remote_id', $contentClass->attribute( 'remote_id' ) ); 05252 $objectNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:class_identifier', $contentClass->attribute( 'identifier' ) ); 05253 $alwaysAvailableText = '0'; 05254 if ( (int)$this->attribute( 'language_mask' ) & 1 ) 05255 { 05256 $alwaysAvailableText = '1'; 05257 } 05258 $objectNode->setAttributeNS( 'http://ez.no/ezobject', 'ezremote:always_available', $alwaysAvailableText ); 05259 05260 $versions = array(); 05261 $oneLanguagePerVersion = false; 05262 if ( $specificVersion === false ) 05263 { 05264 $versions = $this->versions(); 05265 // Since we are exporting all versions it should only contain 05266 // one language per version 05267 //$oneLanguagePerVersion = true; // uncomment to get one language per version 05268 } 05269 else if ( $specificVersion === true ) 05270 { 05271 $versions[] = $this->currentVersion(); 05272 } 05273 else 05274 { 05275 $versions[] = $this->version( $specificVersion ); 05276 // Since we are exporting a specific version it should only contain 05277 // one language per version? 05278 $oneLanguagePerVersion = true; 05279 } 05280 05281 $this->fetchClassAttributes(); 05282 05283 $exportedLanguages = array(); 05284 05285 $versionsNode = $dom->createElementNS( 'http://ez.no/object/', 'ezobject:version-list' ); 05286 $versionsNode->setAttribute( 'active_version', $this->CurrentVersion ); 05287 foreach ( $versions as $version ) 05288 { 05289 if ( !$version ) 05290 { 05291 continue; 05292 } 05293 $options['only_initial_language'] = $oneLanguagePerVersion; 05294 $versionNode = $version->serialize( $package, $options, $contentNodeIDArray, $topNodeIDArray ); 05295 if ( $versionNode ) 05296 { 05297 $importedVersionNode = $dom->importNode( $versionNode, true ); 05298 $versionsNode->appendChild( $importedVersionNode ); 05299 foreach ( $versionNode->getElementsByTagName( 'object-translation' ) as $versionNodeChild ) 05300 { 05301 $exportedLanguage = $versionNodeChild->getAttribute( 'language' ); 05302 $exportedLanguages[] = $exportedLanguage; 05303 $exportedLanguages = array_unique( $exportedLanguages ); 05304 } 05305 } 05306 unset( $versionNode ); 05307 unset( $versionNode ); 05308 } 05309 $initialLanguageCode = $this->attribute( 'initial_language_code' ); 05310 if ( in_array( $initialLanguageCode, $exportedLanguages ) ) 05311 { 05312 $objectNode->setAttribute( 'initial_language', $initialLanguageCode ); 05313 } 05314 $objectNode->appendChild( $versionsNode ); 05315 return $objectNode; 05316 } 05317 05318 /*! 05319 \return a structure with information required for caching. 05320 */ 05321 function cacheInfo( $Params ) 05322 { 05323 $contentCacheInfo =& $GLOBALS['eZContentCacheInfo']; 05324 if ( !isset( $contentCacheInfo ) ) 05325 { 05326 //include_once( 'kernel/classes/datatypes/ezuser/ezuser.php' ); 05327 //include_once( 'kernel/classes/ezuserdiscountrule.php' ); 05328 $user = eZUser::currentUser(); 05329 $language = false; 05330 if ( isset( $Params['Language'] ) ) 05331 { 05332 $language = $Params['Language']; 05333 } 05334 $roleList = $user->roleIDList(); 05335 $discountList = eZUserDiscountRule::fetchIDListByUserID( $user->attribute( 'contentobject_id' ) ); 05336 $contentCacheInfo = array( 'language' => $language, 05337 'role_list' => $roleList, 05338 'discount_list' => $discountList ); 05339 } 05340 return $contentCacheInfo; 05341 } 05342 05343 /*! 05344 Sets all view cache files to be expired 05345 */ 05346 static function expireAllViewCache() 05347 { 05348 eZExpiryHandler::registerShutdownFunction(); 05349 $handler = eZExpiryHandler::instance(); 05350 $handler->setTimestamp( 'content-view-cache', time() ); 05351 $handler->store(); 05352 } 05353 05354 /*! 05355 Sets all content cache files to be expired. Both view cache and cache blocks are expired. 05356 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 05357 the calls within a db transaction; thus within db->begin and db->commit. 05358 */ 05359 static function expireAllCache() 05360 { 05361 eZExpiryHandler::registerShutdownFunction(); 05362 $handler = eZExpiryHandler::instance(); 05363 $handler->setTimestamp( 'content-view-cache', time() ); 05364 $handler->setTimestamp( 'template-block-cache', time() ); 05365 $handler->setTimestamp( 'content-tree-menu', time() ); 05366 $handler->store(); 05367 } 05368 05369 /*! 05370 Expires all template block cache. This should be expired anytime any content 05371 is published/modified or removed. 05372 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 05373 the calls within a db transaction; thus within db->begin and db->commit. 05374 */ 05375 static function expireTemplateBlockCache() 05376 { 05377 eZExpiryHandler::registerShutdownFunction(); 05378 $handler = eZExpiryHandler::instance(); 05379 $handler->setTimestamp( 'template-block-cache', time() ); 05380 $handler->store(); 05381 } 05382 05383 /*! 05384 \static 05385 Callse eZContentObject::xpireTemplateBlockCache() unless template caching is disabled. 05386 */ 05387 static function expireTemplateBlockCacheIfNeeded() 05388 { 05389 $ini = eZINI::instance(); 05390 if ( $ini->variable( 'TemplateSettings', 'TemplateCache' ) == 'enabled' ) 05391 eZContentObject::expireTemplateBlockCache(); 05392 } 05393 05394 /*! 05395 Sets all complex viewmode content cache files to be expired. 05396 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 05397 the calls within a db transaction; thus within db->begin and db->commit. 05398 */ 05399 static function expireComplexViewModeCache() 05400 { 05401 eZExpiryHandler::registerShutdownFunction(); 05402 $handler = eZExpiryHandler::instance(); 05403 $handler->setTimestamp( 'content-complex-viewmode-cache', time() ); 05404 $handler->store(); 05405 } 05406 05407 /*! 05408 \return if the content cache timestamp \a $timestamp is expired. 05409 */ 05410 static function isCacheExpired( $timestamp ) 05411 { 05412 eZExpiryHandler::registerShutdownFunction(); 05413 $handler = eZExpiryHandler::instance(); 05414 if ( !$handler->hasTimestamp( 'content-view-cache' ) ) 05415 return false; 05416 $expiryTime = $handler->timestamp( 'content-view-cache' ); 05417 if ( $expiryTime > $timestamp ) 05418 return true; 05419 return false; 05420 } 05421 05422 /*! 05423 \return true if the viewmode is a complex viewmode. 05424 */ 05425 static function isComplexViewMode( $viewMode ) 05426 { 05427 $ini = eZINI::instance(); 05428 $viewModes = $ini->variableArray( 'ContentSettings', 'ComplexDisplayViewModes' ); 05429 return in_array( $viewMode, $viewModes ); 05430 } 05431 05432 /*! 05433 \return true if the viewmode is a complex viewmode and the viewmode timestamp is expired. 05434 */ 05435 static function isComplexViewModeCacheExpired( $viewMode, $timestamp ) 05436 { 05437 if ( !eZContentObject::isComplexViewMode( $viewMode ) ) 05438 return false; 05439 eZExpiryHandler::registerShutdownFunction(); 05440 $handler = eZExpiryHandler::instance(); 05441 if ( !$handler->hasTimestamp( 'content-complex-viewmode-cache' ) ) 05442 return false; 05443 $expiryTime = $handler->timestamp( 'content-complex-viewmode-cache' ); 05444 if ( $expiryTime > $timestamp ) 05445 return true; 05446 return false; 05447 } 05448 05449 /*! 05450 Returns a list of all the authors for this object. The returned value is an 05451 array of eZ user objects. 05452 */ 05453 function authorArray() 05454 { 05455 $db = eZDB::instance(); 05456 05457 $userArray = $db->arrayQuery( "SELECT DISTINCT ezuser.contentobject_id, ezuser.login, ezuser.email, ezuser.password_hash, ezuser.password_hash_type 05458 FROM ezcontentobject_version, ezuser where ezcontentobject_version.contentobject_id='$this->ID' 05459 AND ezcontentobject_version.creator_id=ezuser.contentobject_id" ); 05460 05461 $return = array(); 05462 05463 foreach ( $userArray as $userRow ) 05464 { 05465 $return[] = new eZUser( $userRow ); 05466 } 05467 return $return; 05468 } 05469 05470 /*! 05471 \return the number of objects of the given class is created by the given user. 05472 */ 05473 static function fetchObjectCountByUserID( $classID, $userID ) 05474 { 05475 $count = 0; 05476 if ( is_numeric( $classID ) and is_numeric( $userID ) ) 05477 { 05478 $db = eZDB::instance(); 05479 $classID =(int) $classID; 05480 $userID =(int) $userID; 05481 $countArray = $db->arrayQuery( "SELECT count(*) AS count FROM ezcontentobject WHERE contentclass_id=$classID AND owner_id=$userID" ); 05482 $count = $countArray[0]['count']; 05483 } 05484 return $count; 05485 } 05486 05487 /*! 05488 \static 05489 \deprecated This method is left here only for backward compatibility. 05490 Use eZContentObjectVersion::removeVersions() method instead. 05491 */ 05492 static function removeVersions( $versionStatus = false ) 05493 { 05494 eZContentObjectVersion::removeVersions( $versionStatus ); 05495 } 05496 05497 /*! 05498 Sets the object's name to $newName: tries to find attributes that are in 'object pattern name' 05499 and updates them. 05500 \return \c true if object's name was changed, otherwise \c false. 05501 */ 05502 function rename( $newName ) 05503 { 05504 // get 'object name pattern' 05505 $objectNamePattern = ''; 05506 $contentClass = $this->contentClass(); 05507 if ( is_object( $contentClass ) ) 05508 $objectNamePattern = $contentClass->ContentObjectName; 05509 05510 if ( $objectNamePattern == '' ) 05511 return false; 05512 05513 // get parts of object's name pattern( like <attr1|attr2>, <attr3> ) 05514 $objectNamePatternPartsPattern = '/<([^>]+)>/U'; 05515 preg_match_all( $objectNamePatternPartsPattern, $objectNamePattern, $objectNamePatternParts ); 05516 05517 if( count( $objectNamePatternParts ) === 0 || count( $objectNamePatternParts[1] ) == 0 ) 05518 return false; 05519 05520 $objectNamePatternParts = $objectNamePatternParts[1]; 05521 05522 // replace all <...> with (.*) 05523 $newNamePattern = preg_replace( $objectNamePatternPartsPattern, '(.*)', $objectNamePattern ); 05524 // add terminators 05525 $newNamePattern = '/' . $newNamePattern . '/'; 05526 05527 // find parts of $newName 05528 preg_match_all( $newNamePattern, $newName, $newNameParts ); 05529 05530 // looks ok, we can create new version of object 05531 $contentObjectVersion = $this->createNewVersion(); 05532 // get contentObjectAttributes 05533 $dataMap = $contentObjectVersion->attribute( 'data_map' ); 05534 if ( count( $dataMap ) === 0 ) 05535 return false; 05536 05537 // assign parts of $newName to the object's attributes. 05538 $pos = 0; 05539 while( $pos < count( $objectNamePatternParts ) ) 05540 { 05541 $attributes = $objectNamePatternParts[$pos]; 05542 05543 // if we have something like <attr1|attr2> then 05544 // 'attr1' will be updated only. 05545 $attributes = explode( '|', $attributes ); 05546 $attribute = $attributes[0]; 05547 05548 $newNamePart = $newNameParts[$pos+1]; 05549 if ( count( $newNamePart ) === 0 ) 05550 { 05551 if( $pos === 0 ) 05552 { 05553 // whole $newName goes into the first attribute 05554 $attributeValue = $newName; 05555 } 05556 else 05557 { 05558 // all other attibutes will be set to '' 05559 $attributeValue = ''; 05560 } 05561 } 05562 else 05563 { 05564 $attributeValue = $newNamePart[0]; 05565 } 05566 05567 $contentAttribute =& $dataMap[$attribute]; 05568 $dataType = $contentAttribute->dataType(); 05569 if( is_object( $dataType ) && $dataType->isSimpleStringInsertionSupported() ) 05570 { 05571 $result = ''; 05572 $dataType->insertSimpleString( $this, $contentObjectVersion, false, $contentAttribute, $attributeValue, $result ); 05573 $contentAttribute->store(); 05574 } 05575 05576 ++$pos; 05577 } 05578 05579 //include_once( 'lib/ezutils/classes/ezoperationhandler.php' ); 05580 $operationResult = eZOperationHandler::execute( 'content', 'publish', array( 'object_id' => $this->attribute( 'id' ), 05581 'version' => $contentObjectVersion->attribute( 'version') ) ); 05582 return ($operationResult != null ? true : false); 05583 } 05584 05585 function removeTranslation( $languageID ) 05586 { 05587 $language = eZContentLanguage::fetch( $languageID ); 05588 05589 if ( !$language ) 05590 { 05591 return false; 05592 } 05593 05594 // check permissions for editing 05595 if ( !$this->checkAccess( 'edit', false, false, false, $languageID ) ) 05596 { 05597 return false; 05598 } 05599 05600 // check if it is not the initial language 05601 $objectInitialLanguageID = $this->attribute( 'initial_language_id' ); 05602 if ( $objectInitialLanguageID == $languageID ) 05603 { 05604 return false; 05605 } 05606 05607 // change language_mask of the object 05608 $languageMask = (int) $this->attribute( 'language_mask' ); 05609 $languageMask = (int) $languageMask & ~ (int) $languageID; 05610 $this->setAttribute( 'language_mask', $languageMask ); 05611 05612 $db = eZDB::instance(); 05613 $db->begin(); 05614 05615 $this->store(); 05616 05617 $objectID = $this->ID; 05618 05619 // If the current version has initial_language_id $languageID, change it to the initial_language_id of the object. 05620 $currentVersion = $this->currentVersion(); 05621 if ( $currentVersion->attribute( 'initial_language_id' ) == $languageID ) 05622 { 05623 $currentVersion->setAttribute( 'initial_language_id', $objectInitialLanguageID ); 05624 $currentVersion->store(); 05625 } 05626 05627 // Remove all versions which had the language as its initial ID. Because of previous checks, it is sure we will not remove the published version. 05628 $versionsToRemove = $this->versions( true, array( 'conditions' => array( 'initial_language_id' => $languageID ) ) ); 05629 foreach ( $versionsToRemove as $version ) 05630 { 05631 $version->removeThis(); 05632 } 05633 05634 $altLanguageID = $languageID++; 05635 05636 // Remove all attributes in the language 05637 $attributes = $db->arrayQuery( "SELECT * FROM ezcontentobject_attribute 05638 WHERE contentobject_id='$objectID' 05639 AND ( language_id='$languageID' OR language_id='$altLanguageID' )" ); 05640 foreach ( $attributes as $attribute ) 05641 { 05642 $attributeObject = new eZContentObjectAttribute( $attribute ); 05643 $attributeObject->remove( $attributeObject->attribute( 'id' ), $attributeObject->attribute( 'version' ) ); 05644 unset( $attributeObject ); 05645 } 05646 05647 // Remove all names in the language 05648 $db->query( "DELETE FROM ezcontentobject_name 05649 WHERE contentobject_id='$objectID' 05650 AND ( language_id='$languageID' OR language_id='$altLanguageID' )" ); 05651 05652 // Update masks of the objects 05653 $mask = eZContentLanguage::maskForRealLanguages() - (int) $languageID; 05654 05655 if ( $db->databaseName() == 'oracle' ) 05656 { 05657 $db->query( "UPDATE ezcontentobject_version SET language_mask = bitand( language_mask, $mask ) 05658 WHERE contentobject_id='$objectID'" ); 05659 } 05660 else 05661 { 05662 $db->query( "UPDATE ezcontentobject_version SET language_mask = language_mask & $mask 05663 WHERE contentobject_id='$objectID'" ); 05664 } 05665 05666 $urlElementfilter = new eZURLAliasQuery(); 05667 $urlElementfilter->type = 'name'; 05668 // We want all languages present here, so we are turning off 05669 // language filtering 05670 $urlElementfilter->languages = false; 05671 $urlElementfilter->limit = false; 05672 05673 $nodes = $this->assignedNodes(); 05674 05675 foreach ( $nodes as $node ) 05676 { 05677 $parent = null; 05678 $textMD5 = null; 05679 05680 $urlElementfilter->actions = array( 'eznode:' . $node->attribute( 'node_id' ) ); 05681 $urlElementfilter->prepare(); 05682 $urlElements = $urlElementfilter->fetchAll(); 05683 05684 foreach ($urlElements as $url ) 05685 { 05686 if ( $url->attribute( 'lang_mask' ) === (int)$languageID or 05687 $url->attribute( 'lang_mask') === (int)$altLanguageID ) 05688 { 05689 $parent = $url->attribute( 'parent'); 05690 $textMD5 = $url->attribute( 'text_md5' ); 05691 break; 05692 } 05693 } 05694 05695 if ( $parent !== null and $textMD5 !== null ) 05696 eZURLAliasML::removeSingleEntry( $parent, $textMD5, $language ); 05697 } 05698 $db->commit(); 05699 05700 return true; 05701 } 05702 05703 function isAlwaysAvailable() 05704 { 05705 return ( $this->attribute( 'language_mask' ) & 1 ); 05706 } 05707 05708 function setAlwaysAvailableLanguageID( $languageID, $version = false ) 05709 { 05710 $db = eZDB::instance(); 05711 $db->begin(); 05712 05713 if ( $version == false ) 05714 { 05715 $version = $this->currentVersion(); 05716 if ( $languageID ) 05717 { 05718 $this->setAttribute( 'language_mask', (int)$this->attribute( 'language_mask' ) | 1 ); 05719 } 05720 else 05721 { 05722 $this->setAttribute( 'language_mask', (int)$this->attribute( 'language_mask' ) & ~1 ); 05723 } 05724 $this->store(); 05725 } 05726 05727 $objectID = $this->attribute( 'id' ); 05728 $versionID = $version->attribute( 'version' ); 05729 05730 // reset 'always available' flag 05731 $sql = "UPDATE ezcontentobject_name SET language_id="; 05732 if ( $db->databaseName() == 'oracle' ) 05733 { 05734 $sql .= "bitand( language_id, -2 )"; 05735 } 05736 else 05737 { 05738 $sql .= "language_id & ~1"; 05739 } 05740 $sql .= " WHERE contentobject_id = '$objectID' AND content_version = '$versionID'"; 05741 $db->query( $sql ); 05742 05743 if ( $languageID != false ) 05744 { 05745 $newLanguageID = $languageID | 1; 05746 $sql = "UPDATE ezcontentobject_name 05747 SET language_id='$newLanguageID' 05748 WHERE language_id='$languageID' AND contentobject_id = '$objectID' AND content_version = '$versionID'"; 05749 $db->query( $sql ); 05750 } 05751 05752 $version->setAlwaysAvailableLanguageID( $languageID ); 05753 05754 // Update url alias for all locations 05755 $nodeRows = eZContentObjectTreeNode::fetchByContentObjectID( $objectID, false ); 05756 $actions = array(); 05757 foreach ( $nodeRows as $nodeRow ) 05758 { 05759 $nodeID = (int)$nodeRow['node_id']; 05760 $actions[] = array( 'eznode', $nodeID ); 05761 } 05762 eZURLAliasML::setLangMaskAlwaysAvailable( $languageID, $actions, null ); 05763 05764 $db->commit(); 05765 } 05766 05767 function allowedAssignSectionList() 05768 { 05769 $currentUser = eZUser::currentUser(); 05770 $sectionIDList = $currentUser->canAssignToObjectSectionList( $this ); 05771 05772 $sectionList = array(); 05773 if ( in_array( '*', $sectionIDList ) ) 05774 { 05775 $sectionList = eZSection::fetchList( false ); 05776 } 05777 else 05778 { 05779 $sectionIDList[] = $this->attribute( 'section_id' ); 05780 $sectionList = eZSection::fetchFilteredList( array( 'id' => array( $sectionIDList ) ), false, false, false ); 05781 } 05782 return $sectionList; 05783 } 05784 05785 public $ID; 05786 public $Name; 05787 05788 /// Stores the current language 05789 public $CurrentLanguage; 05790 05791 /// Stores the current class name 05792 public $ClassName; 05793 05794 /// Cached class identifier 05795 public $ClassIdentifier; 05796 05797 /// Contains the datamap for content object attributes 05798 public $DataMap = array(); 05799 05800 /// Contains an array of the content object actions for the current object 05801 public $ContentActionList = false; 05802 05803 /// Contains a cached version of the content object attributes for the given version and language 05804 public $ContentObjectAttributes = array(); 05805 05806 /// Contains the main node id for this object 05807 public $MainNodeID = false; 05808 05809 /// Contains the arrays of relatedobject id by fetching input for this object 05810 public $InputRelationList = array(); 05811 } 05812 05813 ?>