|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZContentClass class. 00004 * 00005 * @copyright Copyright (C) 1999-2012 eZ Systems AS. All rights reserved. 00006 * @license http://www.gnu.org/licenses/gpl-2.0.txt GNU General Public License v2 00007 * @version //autogentag// 00008 * @package kernel 00009 */ 00010 00011 /*! 00012 \class eZContentClass ezcontentclass.php 00013 \ingroup eZKernel 00014 \brief Handles eZ Publish content classes 00015 00016 \sa eZContentObject 00017 */ 00018 00019 class eZContentClass extends eZPersistentObject 00020 { 00021 const VERSION_STATUS_DEFINED = 0; 00022 const VERSION_STATUS_TEMPORARY = 1; 00023 const VERSION_STATUS_MODIFIED = 2; 00024 00025 /** 00026 * Max length of content object name. 00027 * @var int 00028 */ 00029 const CONTENT_OBJECT_NAME_MAX_LENGTH = 255; 00030 00031 function eZContentClass( $row ) 00032 { 00033 if ( is_array( $row ) ) 00034 { 00035 $this->eZPersistentObject( $row ); 00036 $this->VersionCount = false; 00037 $this->InGroups = null; 00038 $this->AllGroups = null; 00039 if ( isset( $row["version_count"] ) ) 00040 $this->VersionCount = $row["version_count"]; 00041 00042 $this->NameList = new eZContentClassNameList(); 00043 if ( isset( $row['serialized_name_list'] ) ) 00044 $this->NameList->initFromSerializedList( $row['serialized_name_list'] ); 00045 else 00046 $this->NameList->initDefault(); 00047 00048 $this->DescriptionList = new eZSerializedObjectNameList(); 00049 if ( isset( $row['serialized_description_list'] ) ) 00050 $this->DescriptionList->initFromSerializedList( $row['serialized_description_list'] ); 00051 else 00052 $this->DescriptionList->initDefault(); 00053 } 00054 $this->DataMap = false; 00055 } 00056 00057 static function definition() 00058 { 00059 static $definition = array( "fields" => array( "id" => array( 'name' => 'ID', 00060 'datatype' => 'integer', 00061 'default' => 0, 00062 'required' => true ), 00063 "version" => array( 'name' => 'Version', 00064 'datatype' => 'integer', 00065 'default' => 0, 00066 'required' => true ), 00067 "serialized_name_list" => array( 'name' => 'SerializedNameList', 00068 'datatype' => 'string', 00069 'default' => '', 00070 'required' => true ), 00071 'serialized_description_list' => array( 'name' => 'SerializedDescriptionList', 00072 'datatype' => 'string', 00073 'default' => '', 00074 'required' => true ), 00075 "identifier" => array( 'name' => "Identifier", 00076 'datatype' => 'string', 00077 'default' => '', 00078 'required' => true ), 00079 "contentobject_name" => array( 'name' => "ContentObjectName", 00080 'datatype' => 'string', 00081 'default' => '', 00082 'required' => true ), 00083 "url_alias_name" => array( 'name' => "URLAliasName", 00084 'datatype' => 'string', 00085 'default' => '', 00086 'required' => false ), 00087 "creator_id" => array( 'name' => "CreatorID", 00088 'datatype' => 'integer', 00089 'default' => 0, 00090 'required' => true, 00091 'foreign_class' => 'eZUser', 00092 'foreign_attribute' => 'contentobject_id', 00093 'multiplicity' => '1..*' ), 00094 "modifier_id" => array( 'name' => "ModifierID", 00095 'datatype' => 'integer', 00096 'default' => 0, 00097 'required' => true, 00098 'foreign_class' => 'eZUser', 00099 'foreign_attribute' => 'contentobject_id', 00100 'multiplicity' => '1..*' ), 00101 "created" => array( 'name' => "Created", 00102 'datatype' => 'integer', 00103 'default' => 0, 00104 'required' => true ), 00105 "remote_id" => array( 'name' => "RemoteID", 00106 'datatype' => 'string', 00107 'default' => '', 00108 'required' => true ), 00109 "modified" => array( 'name' => "Modified", 00110 'datatype' => 'integer', 00111 'default' => 0, 00112 'required' => true ), 00113 "is_container" => array( 'name' => "IsContainer", 00114 'datatype' => 'integer', 00115 'default' => 0, 00116 'required' => true ), 00117 'always_available' => array( 'name' => "AlwaysAvailable", 00118 'datatype' => 'integer', 00119 'default' => 0, 00120 'required' => true ), 00121 'language_mask' => array( 'name' => "LanguageMask", 00122 'datatype' => 'integer', 00123 'default' => 0, 00124 'required' => true ), 00125 'initial_language_id' => array( 'name' => "InitialLanguageID", 00126 'datatype' => 'integer', 00127 'default' => 0, 00128 'required' => true, 00129 'foreign_class' => 'eZContentLanguage', 00130 'foreign_attribute' => 'id', 00131 'multiplicity' => '1..*' ), 00132 'sort_field' => array( 'name' => 'SortField', 00133 'datatype' => 'integer', 00134 'default' => 1, 00135 'required' => true ), 00136 'sort_order' => array( 'name' => 'SortOrder', 00137 'datatype' => 'integer', 00138 'default' => 1, 00139 'required' => true ) ), 00140 "keys" => array( "id", "version" ), 00141 "function_attributes" => array( "data_map" => "dataMap", 00142 'object_count' => 'objectCount', 00143 'object_list' => 'objectList', 00144 'version_count' => 'versionCount', 00145 'version_status' => 'versionStatus', 00146 'remote_id' => 'remoteID', // Note: This overrides remote_id field 00147 'ingroup_list' => 'fetchGroupList', 00148 'ingroup_id_list' => 'fetchGroupIDList', 00149 'match_ingroup_id_list' => 'fetchMatchGroupIDList', 00150 'group_list' => 'fetchAllGroups', 00151 'creator' => 'creator', 00152 'modifier' => 'modifier', 00153 'can_instantiate_languages' => 'canInstantiateLanguages', 00154 'name' => 'name', 00155 'nameList' => 'nameList', 00156 'description' => 'description', 00157 'descriptionList' => 'descriptionList', 00158 'languages' => 'languages', 00159 'prioritized_languages' => 'prioritizedLanguages', 00160 'prioritized_languages_js_array' => 'prioritizedLanguagesJsArray', 00161 'can_create_languages' => 'canCreateLanguages', 00162 'top_priority_language_locale' => 'topPriorityLanguageLocale', 00163 'always_available_language' => 'alwaysAvailableLanguage' ), 00164 'set_functions' => array( 'name' => 'setName' ), 00165 "increment_key" => "id", 00166 "class_name" => "eZContentClass", 00167 "sort" => array( "id" => "asc" ), 00168 "name" => "ezcontentclass" ); 00169 return $definition; 00170 } 00171 00172 function __clone() 00173 { 00174 unset( $this->Version ); 00175 unset( $this->InGroups ); 00176 unset( $this->AllGroups ); 00177 unset( $this->CanInstantiateLanguages ); 00178 unset( $this->VersionCount ); 00179 $this->ID = null; 00180 $this->RemoteID = eZRemoteIdUtility::generate( 'class' ); 00181 } 00182 00183 /*! 00184 Creates an 'eZContentClass' object. 00185 00186 To specify contentclass name use either $optionalValues['serialized_name_list'] or 00187 combination of $optionalValues['name'] and/or $languageLocale. 00188 00189 In case of conflict(when both 'serialized_name_list' and 'name' with/without $languageLocale 00190 are specified) 'serialized_name_list' has top priority. This means that 'name' and 00191 $languageLocale will be ingnored because 'serialized_name_list' already has all needed info 00192 about names and languages. 00193 00194 If 'name' is specified then the contentclass will have a name in $languageLocale(if specified) or 00195 in default language. 00196 00197 If neither of 'serialized_name_list' or 'name' isn't specified then the contentclass will have an empty 00198 name in 'languageLocale'(if specified) or in default language. 00199 00200 'language_mask' and 'initial_language_id' attributes will be set according to specified(either 00201 in 'serialized_name_list' or by $languageLocale) languages. 00202 00203 \return 'eZContentClass' object. 00204 */ 00205 static function create( $userID = false, $optionalValues = array(), $languageLocale = false ) 00206 { 00207 $dateTime = time(); 00208 if ( !$userID ) 00209 $userID = eZUser::currentUserID(); 00210 00211 $nameList = new eZContentClassNameList(); 00212 if ( isset( $optionalValues['serialized_name_list'] ) ) 00213 $nameList->initFromSerializedList( $optionalValues['serialized_name_list'] ); 00214 else if ( isset( $optionalValues['name'] ) ) 00215 $nameList->initFromString( $optionalValues['name'], $languageLocale ); 00216 else 00217 $nameList->initFromString( '', $languageLocale ); 00218 00219 $descriptionList = new eZSerializedObjectNameList(); 00220 if ( isset( $optionalValues['serialized_description_list'] ) ) 00221 $descriptionList->initFromSerializedList( $optionalValues['serialized_description_list'] ); 00222 else if ( isset( $optionalValues['description'] ) ) 00223 $descriptionList->initFromString( $optionalValues['description'], $languageLocale ); 00224 else 00225 $descriptionList->initFromString( '', $languageLocale ); 00226 00227 $languageMask = $nameList->languageMask(); 00228 $initialLanguageID = $nameList->alwaysAvailableLanguageID(); 00229 00230 $contentClassDefinition = eZContentClass::definition(); 00231 $row = array( 00232 "id" => null, 00233 "version" => 1, 00234 "serialized_name_list" => $nameList->serializeNames(), 00235 'serialized_description_list' => $descriptionList->serializeNames(), 00236 "identifier" => "", 00237 "contentobject_name" => "", 00238 "creator_id" => $userID, 00239 "modifier_id" => $userID, 00240 "created" => $dateTime, 00241 'remote_id' => eZRemoteIdUtility::generate( 'class' ), 00242 "modified" => $dateTime, 00243 "is_container" => $contentClassDefinition[ 'fields' ][ 'is_container' ][ 'default' ], 00244 "always_available" => $contentClassDefinition[ 'fields' ][ 'always_available' ][ 'default' ], 00245 'language_mask' => $languageMask, 00246 'initial_language_id' => $initialLanguageID, 00247 "sort_field" => $contentClassDefinition[ 'fields' ][ 'sort_field' ][ 'default' ], 00248 "sort_order" => $contentClassDefinition[ 'fields' ][ 'sort_order' ][ 'default' ] ); 00249 00250 $row = array_merge( $row, $optionalValues ); 00251 00252 $contentClass = new eZContentClass( $row ); 00253 00254 // setting 'dirtyData' to make sure the 'NameList' will be stored into db. 00255 $contentClass->NameList->setHasDirtyData( true ); 00256 00257 return $contentClass; 00258 } 00259 00260 function instantiateIn( $lang, $userID = false, $sectionID = 0, $versionNumber = false, $versionStatus = eZContentObjectVersion::STATUS_INTERNAL_DRAFT ) 00261 { 00262 return eZContentClass::instantiate( $userID, $sectionID, $versionNumber, $lang, $versionStatus ); 00263 } 00264 00265 /*! 00266 Creates a new content object instance and stores it. 00267 00268 \param userID user ID (optional), current user if not set (also store object id in session if $userID = false) 00269 \param sectionID section ID (optional), 0 if not set 00270 \param versionNumber version number, create initial version if not set 00271 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00272 the calls within a db transaction; thus within db->begin and db->commit. 00273 */ 00274 function instantiate( $userID = false, $sectionID = 0, $versionNumber = false, $languageCode = false, $versionStatus = eZContentObjectVersion::STATUS_INTERNAL_DRAFT ) 00275 { 00276 $attributes = $this->fetchAttributes(); 00277 00278 if ( $userID === false ) 00279 { 00280 $user = eZUser::currentUser(); 00281 $userID = $user->attribute( 'contentobject_id' ); 00282 } 00283 00284 if ( $languageCode == false ) 00285 { 00286 $languageCode = eZContentObject::defaultLanguage(); 00287 } 00288 00289 $object = eZContentObject::create( ezpI18n::tr( "kernel/contentclass", "New %1", null, array( $this->name( $languageCode ) ) ), 00290 $this->attribute( "id" ), 00291 $userID, 00292 $sectionID, 00293 1, 00294 $languageCode ); 00295 00296 if ( $this->attribute( 'always_available' ) ) 00297 { 00298 $object->setAttribute( 'language_mask', (int)$object->attribute( 'language_mask') | 1 ); 00299 } 00300 00301 $db = eZDB::instance(); 00302 $db->begin(); 00303 00304 $object->store(); 00305 $object->assignDefaultStates(); 00306 $object->setName( ezpI18n::tr( "kernel/contentclass", "New %1", null, array( $this->name( $languageCode ) ) ), false, $languageCode ); 00307 00308 if ( !$versionNumber ) 00309 { 00310 $version = $object->createInitialVersion( $userID, $languageCode ); 00311 } 00312 else 00313 { 00314 $version = eZContentObjectVersion::create( $object->attribute( "id" ), $userID, $versionNumber, $languageCode ); 00315 } 00316 if ( $versionStatus !== false ) 00317 { 00318 $version->setAttribute( 'status', $versionStatus ); 00319 } 00320 00321 $version->store(); 00322 00323 foreach ( $attributes as $attribute ) 00324 { 00325 $attribute->instantiate( $object->attribute( 'id' ), $languageCode ); 00326 } 00327 00328 if ( isset( $user ) && $user instanceof eZUser && $user->isAnonymous() ) 00329 { 00330 $createdObjectIDList = eZPreferences::value( 'ObjectCreationIDList' ); 00331 if ( !$createdObjectIDList ) 00332 { 00333 $createdObjectIDList = array( $object->attribute( 'id' ) ); 00334 } 00335 else 00336 { 00337 $createdObjectIDList = unserialize( $createdObjectIDList ); 00338 $createdObjectIDList[] = $object->attribute( 'id' ); 00339 } 00340 eZPreferences::setValue( 'ObjectCreationIDList', serialize( $createdObjectIDList ) ); 00341 } 00342 00343 $db->commit(); 00344 return $object; 00345 } 00346 00347 function canInstantiateClasses() 00348 { 00349 $accessResult = eZUser::currentUser()->hasAccessTo( 'content' , 'create' ); 00350 $canInstantiateClasses = 1; 00351 if ( $accessResult['accessWord'] == 'no' ) 00352 { 00353 $canInstantiateClasses = 0; 00354 } 00355 return $canInstantiateClasses; 00356 } 00357 00358 // code-template::create-block: can-instantiate-class-list, group-filter, role-caching, class-policy-list, name-instantiate, object-creation, class-sql-creation, static-method 00359 // code-template::auto-generated:START can-instantiate-class-list 00360 // This code is automatically generated from templates/classcreatelist.ctpl 00361 // DO NOT EDIT THIS CODE DIRECTLY, CHANGE THE TEMPLATE FILE INSTEAD 00362 00363 /*! 00364 \static 00365 Finds all classes that the current user can create objects from and returns. 00366 It is also possible to filter the list event more with \a $includeFilter and \a $groupList. 00367 00368 \param $asObject If \c true then it return eZContentClass objects, if not it will 00369 be an associative array with \c name and \c id keys. 00370 \param $includeFilter If \c true then it will include only from class groups defined in 00371 \a $groupList, if not it will exclude those groups. 00372 \param $groupList An array with class group IDs that should be used in filtering, use 00373 \c false if you do not wish to filter at all. 00374 \param $fetchID A unique name for the current fetch, this must be supplied when filtering is 00375 used if you want caching to work. 00376 */ 00377 static function canInstantiateClassList( $asObject = false, $includeFilter = true, $groupList = false, $fetchID = false ) 00378 { 00379 $ini = eZINI::instance(); 00380 $groupArray = array(); 00381 00382 $enableCaching = ( $ini->variable( 'RoleSettings', 'EnableCaching' ) == 'true' ); 00383 if ( is_array( $groupList ) ) 00384 { 00385 if ( $fetchID == false ) 00386 $enableCaching = false; 00387 } 00388 00389 if ( $enableCaching ) 00390 { 00391 $http = eZHTTPTool::instance(); 00392 eZExpiryHandler::registerShutdownFunction(); 00393 $handler = eZExpiryHandler::instance(); 00394 $expiredTimeStamp = 0; 00395 if ( $handler->hasTimestamp( 'user-class-cache' ) ) 00396 $expiredTimeStamp = $handler->timestamp( 'user-class-cache' ); 00397 00398 $classesCachedForUser = $http->sessionVariable( 'ClassesCachedForUser' ); 00399 $classesCachedTimestamp = $http->sessionVariable( 'ClassesCachedTimestamp' ); 00400 00401 $cacheVar = 'CanInstantiateClassList'; 00402 if ( is_array( $groupList ) and $fetchID !== false ) 00403 { 00404 $cacheVar = 'CanInstantiateClassListGroup'; 00405 } 00406 00407 $user = eZUser::currentUser(); 00408 $userID = $user->id(); 00409 if ( ( $classesCachedTimestamp >= $expiredTimeStamp ) && $classesCachedForUser == $userID ) 00410 { 00411 if ( $http->hasSessionVariable( $cacheVar ) ) 00412 { 00413 if ( $fetchID !== false ) 00414 { 00415 // Check if the group contains our ID, if not we need to fetch from DB 00416 $groupArray = $http->sessionVariable( $cacheVar ); 00417 if ( isset( $groupArray[$fetchID] ) ) 00418 { 00419 return $groupArray[$fetchID]; 00420 } 00421 } 00422 else 00423 { 00424 return $http->sessionVariable( $cacheVar ); 00425 } 00426 } 00427 } 00428 else 00429 { 00430 $http->setSessionVariable( 'ClassesCachedForUser' , $userID ); 00431 $http->setSessionVariable( 'ClassesCachedTimestamp', time() ); 00432 } 00433 } 00434 00435 $languageCodeList = eZContentLanguage::fetchLocaleList(); 00436 $allowedLanguages = array( '*' => array() ); 00437 00438 $user = eZUser::currentUser(); 00439 $accessResult = $user->hasAccessTo( 'content' , 'create' ); 00440 $accessWord = $accessResult['accessWord']; 00441 00442 $classIDArray = array(); 00443 $classList = array(); 00444 $fetchAll = false; 00445 if ( $accessWord == 'yes' ) 00446 { 00447 $fetchAll = true; 00448 $allowedLanguages['*'] = $languageCodeList; 00449 } 00450 else if ( $accessWord == 'no' ) 00451 { 00452 // Cannot create any objects, return empty list. 00453 return $classList; 00454 } 00455 else 00456 { 00457 $policies = $accessResult['policies']; 00458 foreach ( $policies as $policyKey => $policy ) 00459 { 00460 $classIDArrayPart = '*'; 00461 if ( isset( $policy['Class'] ) ) 00462 { 00463 $classIDArrayPart = $policy['Class']; 00464 } 00465 $languageCodeArrayPart = $languageCodeList; 00466 if ( isset( $policy['Language'] ) ) 00467 { 00468 $languageCodeArrayPart = array_intersect( $policy['Language'], $languageCodeList ); 00469 } 00470 00471 // No class limitation for this policy AND no previous limitation(s) 00472 if ( $classIDArrayPart == '*' && empty( $classIDArray ) ) 00473 { 00474 $fetchAll = true; 00475 $allowedLanguages['*'] = array_unique( array_merge( $allowedLanguages['*'], $languageCodeArrayPart ) ); 00476 } 00477 else if ( is_array( $classIDArrayPart ) ) 00478 { 00479 $fetchAll = false; 00480 foreach( $classIDArrayPart as $class ) 00481 { 00482 if ( isset( $allowedLanguages[$class] ) ) 00483 { 00484 $allowedLanguages[$class] = array_unique( array_merge( $allowedLanguages[$class], $languageCodeArrayPart ) ); 00485 } 00486 else 00487 { 00488 $allowedLanguages[$class] = $languageCodeArrayPart; 00489 } 00490 } 00491 $classIDArray = array_merge( $classIDArray, array_diff( $classIDArrayPart, $classIDArray ) ); 00492 } 00493 } 00494 } 00495 00496 $db = eZDB::instance(); 00497 00498 $filterTableSQL = ''; 00499 $filterSQL = ''; 00500 // Create extra SQL statements for the class group filters. 00501 if ( is_array( $groupList ) ) 00502 { 00503 if ( count( $groupList ) == 0 ) 00504 { 00505 return $classList; 00506 } 00507 00508 $filterTableSQL = ', ezcontentclass_classgroup ccg'; 00509 $filterSQL = ( " AND" . 00510 " cc.id = ccg.contentclass_id AND" . 00511 " " ); 00512 $filterSQL .= $db->generateSQLINStatement( $groupList, 'ccg.group_id', !$includeFilter, true, 'int' ); 00513 } 00514 00515 $classNameFilter = eZContentClassName::sqlFilter( 'cc' ); 00516 $filterSQL .= " AND cc.id=" . $classNameFilter['from'] . ".contentclass_id"; 00517 00518 if ( $fetchAll ) 00519 { 00520 // If $asObject is true we fetch all fields in class 00521 $fields = $asObject ? "cc.*, $classNameFilter[nameField]" : "cc.id, $classNameFilter[nameField]"; 00522 $rows = $db->arrayQuery( "SELECT DISTINCT $fields " . 00523 "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from] " . 00524 "WHERE cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . " $filterSQL " . 00525 "ORDER BY $classNameFilter[nameField] ASC" ); 00526 $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject ); 00527 } 00528 else 00529 { 00530 // If the constrained class list is empty we are not allowed to create any class 00531 if ( count( $classIDArray ) == 0 ) 00532 { 00533 return $classList; 00534 } 00535 00536 $classIDCondition = $db->generateSQLINStatement( $classIDArray, 'cc.id' ); 00537 // If $asObject is true we fetch all fields in class 00538 $fields = $asObject ? "cc.*, $classNameFilter[nameField]" : "cc.id, $classNameFilter[nameField]"; 00539 $rows = $db->arrayQuery( "SELECT DISTINCT $fields " . 00540 "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from] " . 00541 "WHERE $classIDCondition AND" . 00542 " cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . " $filterSQL " . 00543 "ORDER BY $classNameFilter[nameField] ASC" ); 00544 $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject ); 00545 } 00546 00547 if ( $asObject ) 00548 { 00549 foreach ( $classList as $key => $class ) 00550 { 00551 $id = $class->attribute( 'id' ); 00552 if ( isset( $allowedLanguages[$id] ) ) 00553 { 00554 $languageCodes = array_unique( array_merge( $allowedLanguages['*'], $allowedLanguages[$id] ) ); 00555 } 00556 else 00557 { 00558 $languageCodes = $allowedLanguages['*']; 00559 } 00560 $classList[$key]->setCanInstantiateLanguages( $languageCodes ); 00561 } 00562 } 00563 00564 eZDebugSetting::writeDebug( 'kernel-content-class', $classList, "class list fetched from db" ); 00565 if ( $enableCaching ) 00566 { 00567 if ( $fetchID !== false ) 00568 { 00569 $groupArray[$fetchID] = $classList; 00570 $http->setSessionVariable( $cacheVar, $groupArray ); 00571 } 00572 else 00573 { 00574 $http->setSessionVariable( $cacheVar, $classList ); 00575 } 00576 } 00577 00578 return $classList; 00579 } 00580 00581 // This code is automatically generated from templates/classcreatelist.ctpl 00582 // code-template::auto-generated:END can-instantiate-class-list 00583 00584 /*! 00585 \return The creator of the class as an eZUser object by using the $CreatorID as user ID. 00586 */ 00587 function creator() 00588 { 00589 if ( isset( $this->CreatorID ) and $this->CreatorID ) 00590 { 00591 return eZUser::fetch( $this->CreatorID ); 00592 } 00593 return null; 00594 } 00595 00596 /*! 00597 \return The modifier of the class as an eZUser object by using the $ModifierID as user ID. 00598 */ 00599 function modifier() 00600 { 00601 if ( isset( $this->ModifierID ) and $this->ModifierID ) 00602 { 00603 return eZUser::fetch( $this->ModifierID ); 00604 } 00605 return null; 00606 } 00607 00608 /*! 00609 Find all groups the current class is placed in and returns a list of group objects. 00610 \return An array with eZContentClassGroup objects. 00611 \sa fetchGroupIDList() 00612 */ 00613 function fetchGroupList() 00614 { 00615 $this->InGroups = eZContentClassClassGroup::fetchGroupList( $this->attribute( "id" ), 00616 $this->attribute( "version" ), 00617 true ); 00618 return $this->InGroups; 00619 } 00620 00621 /*! 00622 Find all groups the current class is placed in and returns a list of group IDs. 00623 \return An array with integers (ids). 00624 \sa fetchGroupList() 00625 */ 00626 function fetchGroupIDList() 00627 { 00628 $list = eZContentClassClassGroup::fetchGroupList( $this->attribute( "id" ), 00629 $this->attribute( "version" ), 00630 false ); 00631 $this->InGroupIDs = array(); 00632 foreach ( $list as $item ) 00633 { 00634 $this->InGroupIDs[] = $item['group_id']; 00635 } 00636 return $this->InGroupIDs; 00637 } 00638 00639 /*! 00640 Returns the result from fetchGroupIDList() if class group overrides is 00641 enabled in content.ini. 00642 \return An array with eZContentClassGroup objects or \c false if disabled. 00643 \note \c EnableClassGroupOverride in group \c ContentOverrideSettings from INI file content.ini 00644 controls this behaviour. 00645 */ 00646 function fetchMatchGroupIDList() 00647 { 00648 $contentINI = eZINI::instance( 'content.ini' ); 00649 if( $contentINI->variable( 'ContentOverrideSettings', 'EnableClassGroupOverride' ) == 'true' ) 00650 { 00651 return $this->attribute( 'ingroup_id_list' ); 00652 } 00653 00654 return false; 00655 } 00656 00657 /*! 00658 Finds all Classes in the system and returns them. 00659 \return An array with eZContentClass objects. 00660 */ 00661 static function fetchAllClasses( $asObject = true, $includeFilter = true, $groupList = false ) 00662 { 00663 $filterTableSQL = ''; 00664 $filterSQL = ''; 00665 if ( is_array( $groupList ) ) 00666 { 00667 $filterTableSQL = ', ezcontentclass_classgroup ccg'; 00668 $filterSQL = ( " AND" . 00669 " cc.id = ccg.contentclass_id AND" . 00670 " ccg.group_id " ); 00671 $groupText = implode( ', ', $groupList ); 00672 if ( $includeFilter ) 00673 $filterSQL .= "IN ( $groupText )"; 00674 else 00675 $filterSQL .= "NOT IN ( $groupText )"; 00676 } 00677 00678 $classNameFilter = eZContentClassName::sqlFilter( 'cc' ); 00679 00680 $classList = array(); 00681 $db = eZDb::instance(); 00682 // If $asObject is true we fetch all fields in class 00683 $fields = $asObject ? "cc.*" : "cc.id, $classNameFilter[nameField]"; 00684 $rows = $db->arrayQuery( "SELECT DISTINCT $fields " . 00685 "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from] " . 00686 "WHERE cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . "$filterSQL AND $classNameFilter[where]" . 00687 "ORDER BY $classNameFilter[nameField] ASC" ); 00688 00689 $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject ); 00690 return $classList; 00691 } 00692 00693 /*! 00694 Finds all Class groups in the system and returns them. 00695 \return An array with eZContentClassGroup objects. 00696 \sa fetchGroupList(), fetchGroupIDList() 00697 */ 00698 function fetchAllGroups() 00699 { 00700 $this->AllGroups = eZContentClassGroup::fetchList(); 00701 return $this->AllGroups; 00702 } 00703 00704 /*! 00705 \return true if the class is part of the group \a $groupID 00706 */ 00707 function inGroup( $groupID ) 00708 { 00709 return eZContentClassClassGroup::classInGroup( $this->attribute( 'id' ), 00710 $this->attribute( 'version' ), 00711 $groupID ); 00712 } 00713 00714 /*! 00715 \static 00716 Will remove all temporary classes from the database. 00717 */ 00718 static function removeTemporary() 00719 { 00720 $version = eZContentClass::VERSION_STATUS_TEMPORARY; 00721 $temporaryClasses = eZContentClass::fetchList( $version, true ); 00722 $db = eZDB::instance(); 00723 $db->begin(); 00724 foreach ( $temporaryClasses as $class ) 00725 { 00726 $class->remove( true, $version ); 00727 } 00728 eZPersistentObject::removeObject( eZContentClassAttribute::definition(), 00729 array( 'version' => $version ) ); 00730 00731 $db->commit(); 00732 } 00733 00734 /*! 00735 Get remote id of content node 00736 */ 00737 function remoteID() 00738 { 00739 $remoteID = eZPersistentObject::attribute( 'remote_id', true ); 00740 if ( !$remoteID && 00741 $this->Version == eZContentClass::VERSION_STATUS_DEFINED ) 00742 { 00743 $this->setAttribute( 'remote_id', eZRemoteIdUtility::generate( 'class' ) ); 00744 $this->sync( array( 'remote_id' ) ); 00745 $remoteID = eZPersistentObject::attribute( 'remote_id', true ); 00746 } 00747 00748 return $remoteID; 00749 } 00750 00751 /*! 00752 \note If you want to remove a class with all data associated with it (objects/classMembers) 00753 you should use eZContentClassOperations::remove() 00754 */ 00755 function remove( $removeAttributes = false, $version = eZContentClass::VERSION_STATUS_DEFINED ) 00756 { 00757 // If we are not allowed to remove just return false 00758 if ( $this->Version == eZContentClass::VERSION_STATUS_DEFINED && !$this->isRemovable() ) 00759 return false; 00760 00761 if ( is_array( $removeAttributes ) or $removeAttributes ) 00762 $this->removeAttributes( $removeAttributes ); 00763 00764 $this->NameList->remove( $this ); 00765 eZPersistentObject::remove(); 00766 } 00767 00768 /*! 00769 Checks if the class can be removed and returns \c true if it can, \c false otherwise. 00770 \sa removableInformation() 00771 */ 00772 function isRemovable() 00773 { 00774 $info = $this->removableInformation( false ); 00775 return count( $info['list'] ) == 0; 00776 } 00777 00778 /*! 00779 Returns information on why the class cannot be removed, 00780 it does the same checks as in isRemovable() but generates 00781 some text in the return array. 00782 \return An array which contains: 00783 - text - Plain text description why this cannot be removed 00784 - list - An array with reasons why this failed, each entry contains: 00785 - text - Plain text description of the reason. 00786 - list - A sublist of reason (e.g from an attribute), is optional. 00787 \param $includeAll Controls whether the returned information will contain all 00788 sources for not being to remove or just the first that it finds. 00789 */ 00790 function removableInformation( $includeAll = true ) 00791 { 00792 $result = array( 'text' => ezpI18n::tr( 'kernel/contentclass', "Cannot remove class '%class_name':", 00793 null, array( '%class_name' => $this->attribute( 'name' ) ) ), 00794 'list' => array() ); 00795 $db = eZDB::instance(); 00796 00797 // Check top-level nodes 00798 $rows = $db->arrayQuery( "SELECT ezcot.node_id 00799 FROM ezcontentobject_tree ezcot, ezcontentobject ezco 00800 WHERE ezcot.depth = 1 AND 00801 ezco.contentclass_id = $this->ID AND 00802 ezco.id=ezcot.contentobject_id" ); 00803 if ( count( $rows ) > 0 ) 00804 { 00805 $result['list'][] = array( 'text' => ezpI18n::tr( 'kernel/contentclass', 'The class is used by a top-level node and cannot be removed. 00806 You will need to change the class of the node by using the swap functionality.' ) ); 00807 if ( !$includeAll ) 00808 return $result; 00809 } 00810 00811 // Check class attributes 00812 foreach ( $this->fetchAttributes() as $attribute ) 00813 { 00814 $dataType = $attribute->dataType(); 00815 if ( !$dataType->isClassAttributeRemovable( $attribute ) ) 00816 { 00817 $info = $dataType->classAttributeRemovableInformation( $attribute, $includeAll ); 00818 $result['list'][] = $info; 00819 if ( !$includeAll ) 00820 return $result; 00821 } 00822 } 00823 00824 return $result; 00825 } 00826 00827 /*! 00828 \note Removes class attributes 00829 00830 \param removeAttributes Array of attributes to remove 00831 \param version Version to remove( optional ) 00832 */ 00833 function removeAttributes( $removeAttributes = false, $version = false ) 00834 { 00835 if ( is_array( $removeAttributes ) ) 00836 { 00837 $db = eZDB::instance(); 00838 $db->begin(); 00839 foreach( $removeAttributes as $attribute ) 00840 { 00841 $attribute->removeThis(); 00842 } 00843 $db->commit(); 00844 } 00845 else 00846 { 00847 $contentClassID = $this->ID; 00848 00849 if ( $version === false ) 00850 { 00851 $version = $this->Version; 00852 } 00853 $classAttributes = $this->fetchAttributes( ); 00854 00855 $db = eZDB::instance(); 00856 $db->begin(); 00857 foreach ( $classAttributes as $classAttribute ) 00858 { 00859 $dataType = $classAttribute->dataType(); 00860 $dataType->deleteStoredClassAttribute( $classAttribute, $version ); 00861 } 00862 eZPersistentObject::removeObject( eZContentClassAttribute::definition(), 00863 array( 'contentclass_id' => $contentClassID, 00864 'version' => $version ) ); 00865 $db->commit(); 00866 } 00867 } 00868 00869 function compareAttributes( $attr1, $attr2 ) 00870 { 00871 return ( $attr1->attribute( "placement" ) > $attr2->attribute( "placement" ) ) ? 1 : -1; 00872 } 00873 00874 function adjustAttributePlacements( $attributes ) 00875 { 00876 if ( !is_array( $attributes ) ) 00877 return; 00878 usort( $attributes, array( $this, "compareAttributes" ) ); 00879 $i = 0; 00880 foreach( $attributes as $attribute ) 00881 { 00882 $attribute->setAttribute( "placement", ++$i ); 00883 } 00884 } 00885 00886 function store( $store_childs = false, $fieldFilters = null ) 00887 { 00888 00889 self::expireCache(); 00890 00891 $db = eZDB::instance(); 00892 $db->begin(); 00893 00894 if ( is_array( $store_childs ) || 00895 $store_childs ) 00896 { 00897 if ( is_array( $store_childs ) ) 00898 { 00899 $attributes = $store_childs; 00900 } 00901 else 00902 { 00903 $attributes = $this->fetchAttributes(); 00904 } 00905 00906 foreach( $attributes as $attribute ) 00907 { 00908 if ( is_object ( $attribute ) ) 00909 $attribute->store(); 00910 } 00911 } 00912 00913 eZExpiryHandler::registerShutdownFunction(); 00914 $handler = eZExpiryHandler::instance(); 00915 $handler->setTimestamp( 'user-class-cache', time() ); 00916 $handler->store(); 00917 00918 $this->setAttribute( 'serialized_name_list', $this->NameList->serializeNames() ); 00919 $this->setAttribute( 'serialized_description_list', $this->DescriptionList->serializeNames() ); 00920 00921 eZPersistentObject::store( $fieldFilters ); 00922 00923 $this->NameList->store( $this ); 00924 00925 $db->commit(); 00926 } 00927 00928 function sync( $fieldFilters = null ) 00929 { 00930 if ( $this->hasDirtyData() ) 00931 $this->store( false, $fieldFilters ); 00932 } 00933 00934 /*! 00935 Initializes this class as a copy of \a $originalClass by 00936 creating new a new name and identifier. 00937 It will check if there are other classes already with this name 00938 in which case it will append a unique number to the name and identifier. 00939 */ 00940 function initializeCopy( &$originalClass ) 00941 { 00942 $name = ezpI18n::tr( 'kernel/class', 'Copy of %class_name', null, 00943 array( '%class_name' => $originalClass->attribute( 'name' ) ) ); 00944 $identifier = 'copy_of_' . $originalClass->attribute( 'identifier' ); 00945 $db = eZDB::instance(); 00946 $sql = "SELECT count( ezcontentclass_name.name ) AS count FROM ezcontentclass, ezcontentclass_name WHERE ezcontentclass.id = ezcontentclass_name.contentclass_id AND ezcontentclass_name.name like '" . $db->escapeString( $name ) . "%'"; 00947 $rows = $db->arrayQuery( $sql ); 00948 $count = $rows[0]['count']; 00949 if ( $count > 0 ) 00950 { 00951 ++$count; 00952 $name .= $count; 00953 $identifier .= $count; 00954 } 00955 $this->setName( $name ); 00956 $this->setAttribute( 'identifier', $identifier ); 00957 $this->setAttribute( 'created', time() ); 00958 $user = eZUser::currentUser(); 00959 $userID = $user->attribute( "contentobject_id" ); 00960 $this->setAttribute( 'creator_id', $userID ); 00961 } 00962 00963 /** 00964 * Stores the current class as a defined version, updates the contentobject_name 00965 * attribute and recreates the class group entries. 00966 * 00967 * @note It will remove any existing temporary or defined classes before storing. 00968 * 00969 * @param array $attributes array of attributes of the content class 00970 */ 00971 public function storeDefined( $attributes ) 00972 { 00973 $this->storeVersioned( $attributes, self::VERSION_STATUS_DEFINED ); 00974 } 00975 00976 /** 00977 * Stores the current class as a modified version, updates the contentobject_name 00978 * attribute and recreates the class group entries. 00979 * 00980 * @note It will remove classes in the previous and specified version before storing. 00981 * 00982 * @param array $attributes array of attributes 00983 * @param int $version version status 00984 * @since Version 4.3 00985 */ 00986 public function storeVersioned( $attributes, $version ) 00987 { 00988 $previousVersion = $this->attribute( 'version' ); 00989 00990 $db = eZDB::instance(); 00991 $db->begin(); 00992 00993 // Before removing anything from the attributes, load attribute information 00994 // which might otherwise not accessible when recreating them below. 00995 // See issue #18164 00996 foreach ( $attributes as $attribute ) 00997 { 00998 $attribute->content(); 00999 } 01000 01001 $this->removeAttributes( false, $version ); 01002 $this->removeAttributes( false, $previousVersion ); 01003 $this->remove( false ); 01004 $this->setVersion( $version, $attributes ); 01005 $this->setAttribute( "modifier_id", eZUser::currentUser()->attribute( "contentobject_id" ) ); 01006 $this->setAttribute( "modified", time() ); 01007 $this->adjustAttributePlacements( $attributes ); 01008 foreach( $attributes as $attribute ) 01009 { 01010 $attribute->storeVersioned( $version ); 01011 } 01012 01013 // Set contentobject_name to something sensible if it is missing 01014 if ( count( $attributes ) > 0 && trim( $this->attribute( 'contentobject_name' ) ) == '' ) 01015 { 01016 $this->setAttribute( 'contentobject_name', '<' . $attributes[0]->attribute( 'identifier' ) . '>' ); 01017 } 01018 01019 // Recreate class member entries 01020 eZContentClassClassGroup::removeClassMembers( $this->ID, $version ); 01021 01022 foreach( eZContentClassClassGroup::fetchGroupList( $this->ID, $previousVersion ) as $classgroup ) 01023 { 01024 $classgroup->setAttribute( 'contentclass_version', $version ); 01025 $classgroup->store(); 01026 } 01027 eZContentClassClassGroup::removeClassMembers( $this->ID, $previousVersion ); 01028 01029 eZExpiryHandler::registerShutdownFunction(); 01030 $handler = eZExpiryHandler::instance(); 01031 $time = time(); 01032 $handler->setTimestamp( 'user-class-cache', $time ); 01033 $handler->setTimestamp( 'class-identifier-cache', $time ); 01034 $handler->setTimestamp( 'sort-key-cache', $time ); 01035 $handler->store(); 01036 01037 eZContentCacheManager::clearAllContentCache(); 01038 01039 $this->setAttribute( 'serialized_name_list', $this->NameList->serializeNames() ); 01040 $this->setAttribute( 'serialized_description_list', $this->DescriptionList->serializeNames() ); 01041 eZPersistentObject::store(); 01042 $this->NameList->store( $this ); 01043 01044 $db->commit(); 01045 } 01046 01047 function setVersion( $version, $set_childs = false ) 01048 { 01049 if ( is_array( $set_childs ) or $set_childs ) 01050 { 01051 if ( is_array( $set_childs ) ) 01052 { 01053 $attributes = $set_childs; 01054 } 01055 else 01056 { 01057 $attributes = $this->fetchAttributes(); 01058 } 01059 foreach( $attributes as $attribute ) 01060 { 01061 $attribute->setAttribute( "version", $version ); 01062 } 01063 } 01064 01065 if ( $this->Version != $version ) 01066 $this->NameList->setHasDirtyData(); 01067 01068 $this->setAttribute( "version", $version ); 01069 } 01070 01071 static function exists( $id, $version = eZContentClass::VERSION_STATUS_DEFINED, $userID = false, $useIdentifier = false ) 01072 { 01073 $conds = array( "version" => $version ); 01074 if ( $useIdentifier ) 01075 $conds["identifier"] = $id; 01076 else 01077 $conds["id"] = $id; 01078 if ( $userID !== false and is_numeric( $userID ) ) 01079 $conds["creator_id"] = $userID; 01080 $version_sort = "desc"; 01081 if ( $version == eZContentClass::VERSION_STATUS_DEFINED ) 01082 $conds['version'] = $version; 01083 $rows = eZPersistentObject::fetchObjectList( eZContentClass::definition(), 01084 null, 01085 $conds, 01086 null, 01087 array( "offset" => 0, 01088 "length" => 1 ), 01089 false ); 01090 if ( count( $rows ) > 0 ) 01091 return $rows[0]['id']; 01092 return false; 01093 } 01094 01095 static function fetch( $id, $asObject = true, $version = eZContentClass::VERSION_STATUS_DEFINED, $user_id = false ,$parent_id = null ) 01096 { 01097 global $eZContentClassObjectCache; 01098 01099 // If the object given by its id is not cached or should be returned as array 01100 // then we fetch it from the DB (objects are always cached as arrays). 01101 if ( !isset( $eZContentClassObjectCache[$id] ) or $asObject === false or $version != eZContentClass::VERSION_STATUS_DEFINED ) 01102 { 01103 $conds = array( "id" => $id, 01104 "version" => $version ); 01105 01106 if ( $user_id !== false and is_numeric( $user_id ) ) 01107 $conds["creator_id"] = $user_id; 01108 01109 $version_sort = "desc"; 01110 if ( $version == eZContentClass::VERSION_STATUS_DEFINED ) 01111 $version_sort = "asc"; 01112 $rows = eZPersistentObject::fetchObjectList( eZContentClass::definition(), 01113 null, 01114 $conds, 01115 array( "version" => $version_sort ), 01116 array( "offset" => 0, 01117 "length" => 2 ), 01118 false ); 01119 01120 if ( count( $rows ) == 0 ) 01121 { 01122 $contentClass = null; 01123 return $contentClass; 01124 } 01125 01126 $row = $rows[0]; 01127 $row["version_count"] = count( $rows ); 01128 01129 if ( $asObject ) 01130 { 01131 $contentClass = new eZContentClass( $row ); 01132 if ( $version == eZContentClass::VERSION_STATUS_DEFINED ) 01133 { 01134 $eZContentClassObjectCache[$id] = $contentClass; 01135 } 01136 return $contentClass; 01137 } 01138 else 01139 $contentClass = $row; 01140 } 01141 else 01142 { 01143 $contentClass = $eZContentClassObjectCache[$id]; 01144 } 01145 01146 return $contentClass; 01147 } 01148 01149 static function fetchByRemoteID( $remoteID, $asObject = true, $version = eZContentClass::VERSION_STATUS_DEFINED, $user_id = false ,$parent_id = null ) 01150 { 01151 $conds = array( "remote_id" => $remoteID, 01152 "version" => $version ); 01153 if ( $user_id !== false and is_numeric( $user_id ) ) 01154 $conds["creator_id"] = $user_id; 01155 $version_sort = "desc"; 01156 if ( $version == eZContentClass::VERSION_STATUS_DEFINED ) 01157 $version_sort = "asc"; 01158 $rows = eZPersistentObject::fetchObjectList( eZContentClass::definition(), 01159 null, 01160 $conds, 01161 array( "version" => $version_sort ), 01162 array( "offset" => 0, 01163 "length" => 2 ), 01164 false ); 01165 if ( count( $rows ) == 0 ) 01166 { 01167 $contentClass = null; 01168 return $contentClass; 01169 } 01170 01171 $row = $rows[0]; 01172 $row["version_count"] = count( $rows ); 01173 01174 if ( $asObject ) 01175 { 01176 return new eZContentClass( $row ); 01177 } 01178 01179 return $row; 01180 } 01181 01182 static function fetchByIdentifier( $identifier, $asObject = true, $version = eZContentClass::VERSION_STATUS_DEFINED, $user_id = false ,$parent_id = null ) 01183 { 01184 $conds = array( "identifier" => $identifier, 01185 "version" => $version ); 01186 if ( $user_id !== false and is_numeric( $user_id ) ) 01187 $conds["creator_id"] = $user_id; 01188 $version_sort = "desc"; 01189 if ( $version == eZContentClass::VERSION_STATUS_DEFINED ) 01190 $version_sort = "asc"; 01191 $rows = eZPersistentObject::fetchObjectList( eZContentClass::definition(), 01192 null, 01193 $conds, 01194 array( "version" => $version_sort ), 01195 array( "offset" => 0, 01196 "length" => 2 ), 01197 false ); 01198 if ( count( $rows ) == 0 ) 01199 { 01200 $contentClass = null; 01201 return $contentClass; 01202 } 01203 01204 $row = $rows[0]; 01205 $row["version_count"] = count( $rows ); 01206 01207 if ( $asObject ) 01208 { 01209 return new eZContentClass( $row ); 01210 } 01211 return $row; 01212 } 01213 01214 /*! 01215 \static 01216 */ 01217 static function fetchList( $version = eZContentClass::VERSION_STATUS_DEFINED, $asObject = true, $user_id = false, 01218 $sorts = null, $fields = null, $classFilter = false, $limit = null ) 01219 { 01220 $conds = array(); 01221 $custom_fields = null; 01222 $custom_tables = null; 01223 $custom_conds = null; 01224 01225 if ( is_numeric( $version ) ) 01226 $conds["version"] = $version; 01227 if ( $user_id !== false and is_numeric( $user_id ) ) 01228 $conds["creator_id"] = $user_id; 01229 if ( $classFilter ) 01230 { 01231 $classIDCount = 0; 01232 $classIdentifierCount = 0; 01233 01234 $classIDFilter = array(); 01235 $classIdentifierFilter = array(); 01236 foreach ( $classFilter as $classType ) 01237 { 01238 if ( is_numeric( $classType ) ) 01239 { 01240 $classIDFilter[] = $classType; 01241 $classIDCount++; 01242 } 01243 else 01244 { 01245 $classIdentifierFilter[] = $classType; 01246 $classIdentifierCount++; 01247 } 01248 } 01249 01250 if ( $classIDCount > 1 ) 01251 $conds['id'] = array( $classIDFilter ); 01252 else if ( $classIDCount == 1 ) 01253 $conds['id'] = $classIDFilter[0]; 01254 if ( $classIdentifierCount > 1 ) 01255 $conds['identifier'] = array( $classIdentifierFilter ); 01256 else if ( $classIdentifierCount == 1 ) 01257 $conds['identifier'] = $classIdentifierFilter[0]; 01258 } 01259 01260 if ( $sorts && isset( $sorts['name'] ) ) 01261 { 01262 $nameFiler = eZContentClassName::sqlFilter( 'ezcontentclass' ); 01263 $custom_tables = array( $nameFiler['from'] ); 01264 $custom_conds = "AND " . $nameFiler['where']; 01265 $custom_fields = array( $nameFiler['nameField'] ); 01266 01267 $sorts[$nameFiler['orderBy']] = $sorts['name']; 01268 unset( $sorts['name'] ); 01269 } 01270 01271 return eZPersistentObject::fetchObjectList( eZContentClass::definition(), 01272 $fields, 01273 $conds, 01274 $sorts, 01275 $limit, 01276 $asObject, 01277 false, 01278 $custom_fields, 01279 $custom_tables, 01280 $custom_conds ); 01281 } 01282 01283 /*! 01284 Returns all attributes as an associative array with the key taken from the attribute identifier. 01285 */ 01286 function dataMap() 01287 { 01288 if ( !isset( $this->DataMap[$this->Version] ) ) 01289 { 01290 $attributes = $this->fetchAttributes( false, true, $this->Version ); 01291 foreach ( $attributes as $attribute ) 01292 { 01293 $this->DataMap[$this->Version][$attribute->attribute( 'identifier' )] = $attribute; 01294 } 01295 } 01296 return $this->DataMap[$this->Version]; 01297 } 01298 01299 function fetchAttributes( $id = false, $asObject = true, $version = eZContentClass::VERSION_STATUS_DEFINED ) 01300 { 01301 if ( $id === false ) 01302 { 01303 $id = $this->ID; 01304 $version = $this->Version; 01305 } 01306 01307 return eZContentClassAttribute::fetchFilteredList( array( "contentclass_id" => $id, 01308 "version" => $version ), 01309 $asObject ); 01310 } 01311 01312 /*! 01313 Fetch class attribute by identifier, return null if none exist. 01314 01315 \param attribute identifier. 01316 01317 \return Class Attribute, null if none matched 01318 */ 01319 function fetchAttributeByIdentifier( $identifier, $asObject = true ) 01320 { 01321 $attributeArray = eZContentClassAttribute::fetchFilteredList( array( 'contentclass_id' => $this->ID, 01322 'version' => $this->Version, 01323 'identifier' => $identifier ), $asObject ); 01324 if ( count( $attributeArray ) > 0 ) 01325 { 01326 return $attributeArray[0]; 01327 } 01328 return null; 01329 } 01330 01331 function fetchSearchableAttributes( $id = false, $asObject = true, $version = eZContentClass::VERSION_STATUS_DEFINED ) 01332 { 01333 if ( $id === false ) 01334 { 01335 $id = $this->ID; 01336 $version = $this->Version; 01337 } 01338 01339 return eZContentClassAttribute::fetchFilteredList( array( "contentclass_id" => $id, 01340 "is_searchable" => 1, 01341 "version" => $version ), $asObject ); 01342 } 01343 01344 function versionStatus() 01345 { 01346 01347 if ( $this->VersionCount == 1 ) 01348 { 01349 if ( $this->Version == eZContentClass::VERSION_STATUS_TEMPORARY ) 01350 { 01351 return eZContentClass::VERSION_STATUS_TEMPORARY; 01352 } 01353 return eZContentClass::VERSION_STATUS_DEFINED; 01354 } 01355 return eZContentClass::VERSION_STATUS_MODIFIED; 01356 } 01357 01358 /*! 01359 \deprecated 01360 \return The version count for the class if has been determined. 01361 */ 01362 function versionCount() 01363 { 01364 return $this->VersionCount; 01365 } 01366 01367 /** 01368 * Will generate a name for the content object based on the class 01369 * settings for content object limited by self::CONTENT_OBJECT_NAME_MAX_LENGTH. 01370 * 01371 * @param eZContentObject $contentObject 01372 * @param int|false $version 01373 * @param string|false $translation 01374 * @return string 01375 */ 01376 function contentObjectName( eZContentObject $contentObject, $version = false, $translation = false ) 01377 { 01378 $contentObjectNamePattern = $this->ContentObjectName; 01379 01380 $ini = eZINI::instance(); 01381 $length = (int) $ini->variable('ContentSettings', 'ContentObjectNameLimit'); 01382 $sequence = $ini->variable('ContentSettings', 'ContentObjectNameLimitSequence'); 01383 if ( $length < 1 || $length > self::CONTENT_OBJECT_NAME_MAX_LENGTH ) 01384 { 01385 $length = self::CONTENT_OBJECT_NAME_MAX_LENGTH; 01386 } 01387 $nameResolver = new eZNamePatternResolver( $contentObjectNamePattern, $contentObject, $version, $translation ); 01388 $contentObjectName = $nameResolver->resolveNamePattern( $length, $sequence ); 01389 01390 return $contentObjectName; 01391 } 01392 01393 /** 01394 * Will generate a name for the url alias based on the class 01395 * settings for content object limited by site.ini\[URLTranslator]\UrlAliasNameLimit 01396 * 01397 * @param eZContentObject $contentObject 01398 * @param int|false $version 01399 * @param string|false $translation 01400 * @return string 01401 */ 01402 function urlAliasName( eZContentObject $contentObject, $version = false, $translation = false ) 01403 { 01404 if ( $this->URLAliasName ) 01405 { 01406 $urlAliasNamePattern = $this->URLAliasName; 01407 } 01408 else 01409 { 01410 $urlAliasNamePattern = $this->ContentObjectName; 01411 } 01412 01413 $length = (int) eZINI::instance()->variable('URLTranslator', 'UrlAliasNameLimit'); 01414 $nameResolver = new eZNamePatternResolver( $urlAliasNamePattern, $contentObject, $version, $translation ); 01415 $urlAliasName = $nameResolver->resolveNamePattern( $length ); 01416 01417 return $urlAliasName; 01418 } 01419 01420 /*! 01421 Generates a name for the content object based on the content object name pattern 01422 and data map of an object. 01423 */ 01424 function buildContentObjectName( $contentObjectName, $dataMap, $tmpTags = false ) 01425 { 01426 preg_match_all( "|<[^>]+>|U", 01427 $contentObjectName, 01428 $tagMatchArray ); 01429 01430 foreach ( $tagMatchArray[0] as $tag ) 01431 { 01432 $tagName = str_replace( "<", "", $tag ); 01433 $tagName = str_replace( ">", "", $tagName ); 01434 01435 $tagParts = explode( '|', $tagName ); 01436 01437 $namePart = ""; 01438 foreach ( $tagParts as $name ) 01439 { 01440 // get the value of the attribute to use in name 01441 if ( isset( $dataMap[$name] ) ) 01442 { 01443 $namePart = $dataMap[$name]->title(); 01444 if ( $namePart != "" ) 01445 break; 01446 } 01447 elseif ( $tmpTags && isset( $tmpTags[$name] ) && $tmpTags[$name] != '' ) 01448 { 01449 $namePart = $tmpTags[$name]; 01450 break; 01451 } 01452 01453 } 01454 01455 // replace tag with object name part 01456 $contentObjectName = str_replace( $tag, $namePart, $contentObjectName ); 01457 } 01458 return $contentObjectName; 01459 } 01460 01461 /*! 01462 \return will return the number of objects published by this class. 01463 */ 01464 function objectCount() 01465 { 01466 $db = eZDB::instance(); 01467 01468 $countRow = $db->arrayQuery( 'SELECT count(*) AS count FROM ezcontentobject '. 01469 'WHERE contentclass_id='.$this->ID ." and status = " . eZContentObject::STATUS_PUBLISHED ); 01470 01471 return $countRow[0]['count']; 01472 } 01473 01474 /*! 01475 \return will return the list of objects published by this class. 01476 */ 01477 function objectList() 01478 { 01479 return eZContentObject::fetchSameClassList( $this->ID ); 01480 } 01481 01482 /*! 01483 \return Sets the languages which are allowed to be instantiated for the class. 01484 Used only for the content/ fetch function. 01485 */ 01486 function setCanInstantiateLanguages( $languageCodes ) 01487 { 01488 $this->CanInstantiateLanguages = $languageCodes; 01489 } 01490 01491 function canInstantiateLanguages() 01492 { 01493 if ( is_array( $this->CanInstantiateLanguages ) ) 01494 { 01495 return array_intersect( eZContentLanguage::prioritizedLanguageCodes(), $this->CanInstantiateLanguages ); 01496 } 01497 return array(); 01498 } 01499 01500 /*! 01501 \static 01502 Returns a contentclass name from serialized array \a $serializedNameList using 01503 top language from siteaccess language list or 'always available' name 01504 from \a $serializedNameList. 01505 01506 \return string with contentclass name. 01507 */ 01508 static function nameFromSerializedString( $serializedNameList ) 01509 { 01510 return eZContentClassNameList::nameFromSerializedString( $serializedNameList ); 01511 } 01512 01513 /*! 01514 \static 01515 Returns a contentclass description from serialized array \a $serializedNameList using 01516 top language from siteaccess language list or 'always available' name 01517 from \a $serializedNameList. 01518 01519 \return string with contentclass description. 01520 */ 01521 static function descriptionFromSerializedString( $serializedNameList ) 01522 { 01523 return eZSerializedObjectNameList::nameFromSerializedString( $serializedNameList ); 01524 } 01525 01526 function hasNameInLanguage( $languageLocale ) 01527 { 01528 $hasName = $this->NameList->hasNameInLocale( $languageLocale ); 01529 return $hasName; 01530 } 01531 01532 /*! 01533 Returns a contentclass name in \a $languageLocale language. 01534 Uses siteaccess language list or 'always available' language if \a $languageLocale is 'false'. 01535 01536 \return string with contentclass name. 01537 */ 01538 function name( $languageLocale = false ) 01539 { 01540 return $this->NameList->name( $languageLocale ); 01541 } 01542 01543 function setName( $name, $languageLocale = false ) 01544 { 01545 if ( !$languageLocale ) 01546 $languageLocale = $this->topPriorityLanguageLocale(); 01547 $this->NameList->setNameByLanguageLocale( $name, $languageLocale ); 01548 01549 $languageID = eZContentLanguage::idByLocale( $languageLocale ); 01550 $languageMask = $this->attribute( 'language_mask' ); 01551 $this->setAttribute( 'language_mask', $languageMask | $languageID ); 01552 } 01553 01554 function nameList() 01555 { 01556 return $this->NameList->nameList(); 01557 } 01558 01559 /*! 01560 Returns a contentclass description in \a $languageLocale language. 01561 Uses siteaccess language list or 'always available' language if \a $languageLocale is 'false'. 01562 01563 \return string with contentclass name. 01564 */ 01565 function description( $languageLocale = false ) 01566 { 01567 return $this->DescriptionList->name( $languageLocale ); 01568 } 01569 01570 function setDescription( $description, $languageLocale = false ) 01571 { 01572 $this->DescriptionList->setName( $description, $languageLocale ); 01573 } 01574 01575 function descriptionList() 01576 { 01577 return $this->DescriptionList->nameList(); 01578 } 01579 01580 function setAlwaysAvailableLanguageID( $languageID, $updateChilds = true ) 01581 { 01582 $db = eZDB::instance(); 01583 $db->begin(); 01584 01585 $languageLocale = false; 01586 if ( $languageID ) 01587 { 01588 $language = eZContentLanguage::fetch( $languageID ); 01589 $languageLocale = $language->attribute( 'locale' ); 01590 } 01591 01592 if ( $languageID ) 01593 { 01594 $this->setAttribute( 'language_mask', (int)$this->attribute( 'language_mask' ) | 1 ); 01595 $this->NameList->setAlwaysAvailableLanguage( $languageLocale ); 01596 $this->DescriptionList->setAlwaysAvailableLanguage( $languageLocale ); 01597 } 01598 else 01599 { 01600 $this->setAttribute( 'language_mask', (int)$this->attribute( 'language_mask' ) & ~1 ); 01601 $this->NameList->setAlwaysAvailableLanguage( false ); 01602 $this->DescriptionList->setAlwaysAvailableLanguage( false ); 01603 } 01604 $this->store(); 01605 01606 $classID = $this->attribute( 'id' ); 01607 $version = $this->attribute( 'version' ); 01608 01609 $attributes = $this->fetchAttributes(); 01610 foreach( $attributes as $attribute ) 01611 { 01612 $attribute->setAlwaysAvailableLanguage( $languageLocale ); 01613 $attribute->store(); 01614 } 01615 01616 // reset 'always available' flag 01617 $sql = "UPDATE ezcontentclass_name SET language_id="; 01618 if ( $db->databaseName() == 'oracle' ) 01619 { 01620 $sql .= "bitand( language_id, -2 )"; 01621 } 01622 else 01623 { 01624 $sql .= "language_id & ~1"; 01625 } 01626 $sql .= " WHERE contentclass_id = '$classID' AND contentclass_version = '$version'"; 01627 $db->query( $sql ); 01628 01629 if ( $languageID != false ) 01630 { 01631 $newLanguageID = $languageID | 1; 01632 01633 $sql = "UPDATE ezcontentclass_name 01634 SET language_id='$newLanguageID' 01635 WHERE language_id='$languageID' AND contentclass_id = '$classID' AND contentclass_version = '$version'"; 01636 $db->query( $sql ); 01637 } 01638 01639 $db->commit(); 01640 } 01641 01642 function clearAlwaysAvailableLanguageID() 01643 { 01644 $this->setAlwaysAvailableLanguageID( false ); 01645 } 01646 01647 /*! 01648 Wrapper for eZContentClassNameList::languages. 01649 */ 01650 function languages() 01651 { 01652 return $this->NameList->languages(); 01653 } 01654 01655 /*! 01656 Wrapper for eZContentClassNameList::prioritizedLanguages. 01657 */ 01658 function prioritizedLanguages() 01659 { 01660 return $this->NameList->prioritizedLanguages(); 01661 } 01662 01663 function prioritizedLanguagesJsArray() 01664 { 01665 return $this->NameList->prioritizedLanguagesJsArray(); 01666 } 01667 01668 /*! 01669 Wrapper for eZContentClassNameList::untranslatedLanguages. 01670 */ 01671 function canCreateLanguages() 01672 { 01673 return $this->NameList->untranslatedLanguages(); 01674 } 01675 01676 /*! 01677 Wrapper for eZContentClassNameList::topPriorityLanguageLocale. 01678 */ 01679 function topPriorityLanguageLocale() 01680 { 01681 return $this->NameList->topPriorityLanguageLocale(); 01682 } 01683 01684 /*! 01685 Wrapper for eZContentClassNameList::alwaysAvailableLanguage. 01686 01687 \return 'language' object. 01688 */ 01689 function alwaysAvailableLanguage() 01690 { 01691 return $this->NameList->alwaysAvailableLanguage(); 01692 } 01693 01694 /*! 01695 Wrapper for eZContentClassNameList::alwaysAvailableLanguageLocale. 01696 01697 \return 'language' object. 01698 */ 01699 function alwaysAvailableLanguageLocale() 01700 { 01701 $language = $this->NameList->alwaysAvailableLanguageLocale(); 01702 return $language; 01703 } 01704 01705 /*! 01706 Removes translated name for specified by \a $languageID language. 01707 */ 01708 function removeTranslation( $languageID ) 01709 { 01710 $language = eZContentLanguage::fetch( $languageID ); 01711 01712 if ( !$language ) 01713 { 01714 return false; 01715 } 01716 01717 // check if it is not the initial language 01718 $classInitialLanguageID = $this->attribute( 'initial_language_id' ); 01719 if ( $classInitialLanguageID == $languageID ) 01720 { 01721 return false; 01722 } 01723 01724 $db = eZDB::instance(); 01725 $db->begin(); 01726 01727 $classID = $this->attribute( 'id' ); 01728 $languageID = $language->attribute( 'id' ); 01729 01730 // change language_mask of the object 01731 $languageMask = (int) $this->attribute( 'language_mask' ); 01732 $languageMask = (int) $languageMask & ~ (int) $languageID; 01733 $this->setAttribute( 'language_mask', $languageMask ); 01734 01735 // Remove all names in the language 01736 $db->query( "DELETE FROM ezcontentclass_name 01737 WHERE contentclass_id='$classID' 01738 AND language_id='$languageID'" ); 01739 01740 $languageLocale = $language->attribute( 'locale' ); 01741 $this->NameList->removeName( $languageLocale ); 01742 $this->DescriptionList->removeName( $languageLocale ); 01743 01744 $this->store(); 01745 01746 // Remove names for attributes in the language 01747 $attributes = $this->fetchAttributes(); 01748 foreach ( $attributes as $attribute ) 01749 { 01750 $attribute->removeTranslation( $languageLocale ); 01751 $attribute->store(); 01752 } 01753 01754 $db->commit(); 01755 01756 return true; 01757 } 01758 01759 /** 01760 * Resolves the string class identifier $identifier to its numeric value 01761 * Use {@link eZContentObjectTreeNode::classIDByIdentifier()} for < 4.1. 01762 * If multiple classes have the same identifier, the first found is returned. 01763 * 01764 * @static 01765 * @since Version 4.1 01766 * @param string|array $identifier identifier string or array of identifiers (array support added in 4.1.1) 01767 * @return int|false Returns classid or false 01768 */ 01769 public static function classIDByIdentifier( $identifier ) 01770 { 01771 $identifierHash = self::classIdentifiersHash(); 01772 01773 if ( is_array( $identifier ) ) 01774 { 01775 $idList = array(); 01776 foreach( $identifier as $identifierItem ) 01777 { 01778 if ( isset( $identifierHash[$identifierItem] ) ) 01779 $idList[] = $identifierHash[$identifierItem]; 01780 else if ( is_numeric( $identifierItem ) ) // to be able to pass mixed arrays 01781 $idList[] = $identifierItem; 01782 } 01783 return $idList; 01784 } 01785 else if ( isset( $identifierHash[$identifier] ) ) 01786 return $identifierHash[$identifier]; 01787 else 01788 return false; 01789 } 01790 01791 /** 01792 * Resolves the numeric class identifier $id to its string value 01793 * 01794 * @static 01795 * @since Version 4.1 01796 * @return string|false Returns classidentifier or false 01797 */ 01798 public static function classIdentifierByID( $id ) 01799 { 01800 $identifierHash = array_flip( self::classIdentifiersHash() ); 01801 01802 if ( isset( $identifierHash[$id] ) ) 01803 return $identifierHash[$id]; 01804 else 01805 return false; 01806 } 01807 01808 /** 01809 * Returns the class identifier hash for the current database. 01810 * If it is outdated or non-existent, the method updates/generates the file 01811 * 01812 * @static 01813 * @since Version 4.1 01814 * @access protected 01815 * @return array Returns hash of classidentifier => classid 01816 */ 01817 protected static function classIdentifiersHash() 01818 { 01819 if ( self::$identifierHash === null ) 01820 { 01821 $db = eZDB::instance(); 01822 $dbName = md5( $db->DB ); 01823 01824 $cacheDir = eZSys::cacheDirectory(); 01825 $phpCache = new eZPHPCreator( $cacheDir, 01826 'classidentifiers_' . $dbName . '.php', 01827 '', 01828 array( 'clustering' => 'classidentifiers' ) ); 01829 01830 eZExpiryHandler::registerShutdownFunction(); 01831 $handler = eZExpiryHandler::instance(); 01832 $expiryTime = 0; 01833 if ( $handler->hasTimestamp( 'class-identifier-cache' ) ) 01834 { 01835 $expiryTime = $handler->timestamp( 'class-identifier-cache' ); 01836 } 01837 01838 if ( $phpCache->canRestore( $expiryTime ) ) 01839 { 01840 $var = $phpCache->restore( array( 'identifierHash' => 'identifier_hash' ) ); 01841 self::$identifierHash = $var['identifierHash']; 01842 } 01843 else 01844 { 01845 // Fetch identifier/id pair from db 01846 $query = "SELECT id, identifier FROM ezcontentclass where version=0"; 01847 $identifierArray = $db->arrayQuery( $query ); 01848 01849 self::$identifierHash = array(); 01850 foreach ( $identifierArray as $identifierRow ) 01851 { 01852 self::$identifierHash[$identifierRow['identifier']] = $identifierRow['id']; 01853 } 01854 01855 // Store identifier list to cache file 01856 $phpCache->addVariable( 'identifier_hash', self::$identifierHash ); 01857 $phpCache->store(); 01858 } 01859 } 01860 return self::$identifierHash; 01861 } 01862 01863 /*! 01864 Returns an array of IDs of classes containing a specified datatype 01865 01866 \param $dataTypeString a datatype identification string 01867 */ 01868 static function fetchIDListContainingDatatype( $dataTypeString ) 01869 { 01870 $db = eZDB::instance(); 01871 01872 $version = self::VERSION_STATUS_DEFINED; 01873 $escapedDataTypeString = $db->escapeString( $dataTypeString ); 01874 01875 $sql = "SELECT DISTINCT contentclass_id 01876 FROM ezcontentclass_attribute 01877 WHERE version=$version 01878 AND data_type_string='$escapedDataTypeString'"; 01879 01880 $classIDArray = $db->arrayQuery( $sql, array( 'column' => 'contentclass_id' ) ); 01881 return $classIDArray; 01882 } 01883 01884 /** 01885 * Expires in-memory cache for eZContentClass. 01886 * 01887 * Clears cache for fetched eZContentClass objects, 01888 * class identifiers and class attributes. 01889 * 01890 * @since 4.2 01891 */ 01892 public static function expireCache() 01893 { 01894 unset( $GLOBALS['eZContentClassObjectCache'] ); 01895 self::$identifierHash = null; 01896 eZContentClassAttribute::expireCache(); 01897 } 01898 01899 /** 01900 * Computes the version history limit for a content class 01901 * 01902 * @param mixed $class 01903 * Content class ID, content class identifier or content class object 01904 * @return int 01905 * @since 4.2 01906 */ 01907 public static function versionHistoryLimit( $class ) 01908 { 01909 // default version limit 01910 $contentINI = eZINI::instance( 'content.ini' ); 01911 $versionLimit = $contentINI->variable( 'VersionManagement', 'DefaultVersionHistoryLimit' ); 01912 01913 // version limit can't be < 2 01914 if ( $versionLimit < 2 ) 01915 { 01916 eZDebug::writeWarning( "Global version history limit must be equal to or higher than 2", __METHOD__ ); 01917 $versionLimit = 2; 01918 } 01919 01920 // we need to take $class down to a class ID 01921 if ( is_numeric( $class ) ) 01922 { 01923 if (!eZContentClass::classIdentifierByID( $class ) ) 01924 { 01925 eZDebug::writeWarning( "class integer parameter doesn't match any content class ID", __METHOD__ ); 01926 return $versionLimit; 01927 } 01928 $classID = (int)$class; 01929 } 01930 // literal identifier 01931 elseif ( is_string( $class ) ) 01932 { 01933 $classID = eZContentClass::classIDByIdentifier( $class ); 01934 if ( !$classID ) 01935 { 01936 eZDebug::writeWarning( "class string parameter doesn't match any content class identifier", __METHOD__ ); 01937 return $versionLimit; 01938 } 01939 } 01940 // eZContentClass object 01941 elseif ( is_object( $class ) ) 01942 { 01943 if ( !$class instanceof eZContentClass ) 01944 { 01945 eZDebug::writeWarning( "class object parameter is not an eZContentClass", __METHOD__ ); 01946 return $versionLimit; 01947 } 01948 else 01949 { 01950 $classID = $class->attribute( 'id' ); 01951 } 01952 } 01953 01954 $classLimitSetting = $contentINI->variable( 'VersionManagement', 'VersionHistoryClass' ); 01955 $classArray = array_keys( $classLimitSetting ); 01956 $limitsArray = array_values( $classLimitSetting ); 01957 01958 $classArray = eZContentClass::classIDByIdentifier( $classArray ); 01959 01960 foreach ( $classArray as $index => $id ) 01961 { 01962 if ( $id == $classID ) 01963 { 01964 $limit = $limitsArray[$index]; 01965 // version limit can't be < 2 01966 if ( $limit < 2 ) 01967 { 01968 $classIdentifier = eZContentClass::classIdentifierByID( $classID ); 01969 eZDebug::writeWarning( "Version history limit for class {$classIdentifier} must be equal to or higher than 2", __METHOD__ ); 01970 $limit = 2; 01971 } 01972 $versionLimit = $limit; 01973 } 01974 } 01975 01976 return $versionLimit; 01977 } 01978 01979 /// \privatesection 01980 public $ID; 01981 // serialized array of translated class names 01982 public $SerializedNameList; 01983 // unserialized class names 01984 public $NameList; 01985 // unserialized class description 01986 public $DescriptionList; 01987 public $Identifier; 01988 public $ContentObjectName; 01989 public $Version; 01990 public $VersionCount; 01991 public $CreatorID; 01992 public $ModifierID; 01993 public $Created; 01994 public $Modified; 01995 public $InGroups; 01996 public $AllGroups; 01997 public $IsContainer; 01998 public $CanInstantiateLanguages; 01999 public $LanguageMask; 02000 02001 /** 02002 * In-memory cache for class identifiers / id matching 02003 */ 02004 private static $identifierHash = null; 02005 } 02006 02007 ?>