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