|
eZ Publish
[trunk]
|
00001 <?php 00002 /** 00003 * File containing the eZContentClassAttribute 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 eZContentClassAttribute ezcontentclassattribute.php 00013 \ingroup eZKernel 00014 \brief Encapsulates data for a class attribute 00015 00016 */ 00017 00018 class eZContentClassAttribute extends eZPersistentObject 00019 { 00020 function eZContentClassAttribute( $row ) 00021 { 00022 $this->eZPersistentObject( $row ); 00023 00024 $this->Content = null; 00025 $this->DisplayInfo = null; 00026 $this->Module = null; 00027 00028 $this->NameList = new eZSerializedObjectNameList(); 00029 if ( isset( $row['serialized_name_list'] ) ) 00030 $this->NameList->initFromSerializedList( $row['serialized_name_list'] ); 00031 else 00032 $this->NameList->initDefault(); 00033 00034 $this->DescriptionList = new eZSerializedObjectNameList(); 00035 if ( isset( $row['serialized_description_list'] ) ) 00036 $this->DescriptionList->initFromSerializedList( $row['serialized_description_list'] ); 00037 else 00038 $this->DescriptionList->initDefault(); 00039 00040 $this->DataTextI18nList = new eZSerializedObjectNameList(); 00041 if ( isset( $row['serialized_data_text'] ) ) 00042 $this->DataTextI18nList->initFromSerializedList( $row['serialized_data_text'] ); 00043 else 00044 $this->DataTextI18nList->initDefault(); 00045 00046 // Make sure datatype gets final say if attribute should be translatable 00047 if ( isset( $row['can_translate'] ) && $row['can_translate'] ) 00048 { 00049 $datatype = $this->dataType(); 00050 if ( $datatype instanceof eZDataType ) 00051 { 00052 if ( !$datatype->isTranslatable() ) 00053 $this->setAttribute('can_translate', 0); 00054 } 00055 else 00056 { 00057 eZDebug::writeError( 'Could not get instance of datatype: ' . $row['data_type_string'], __METHOD__ ); 00058 } 00059 } 00060 } 00061 00062 static function definition() 00063 { 00064 static $definition = array( 'fields' => array( 'id' => array( 'name' => 'ID', 00065 'datatype' => 'integer', 00066 'default' => 0, 00067 'required' => true ), 00068 'serialized_name_list' => array( 'name' => 'SerializedNameList', 00069 'datatype' => 'string', 00070 'default' => '', 00071 'required' => true ), 00072 'serialized_description_list' => array( 'name' => 'SerializedDescriptionList', 00073 'datatype' => 'string', 00074 'default' => '', 00075 'required' => true ), 00076 'version' => array( 'name' => 'Version', 00077 'datatype' => 'integer', 00078 'default' => 0, 00079 'required' => true ), 00080 'contentclass_id' => array( 'name' => 'ContentClassID', 00081 'datatype' => 'integer', 00082 'default' => 0, 00083 'required' => true, 00084 'foreign_class' => 'eZContentClass', 00085 'foreign_attribute' => 'id', 00086 'multiplicity' => '1..*' ), 00087 'identifier' => array( 'name' => 'Identifier', 00088 'datatype' => 'string', 00089 'default' => '', 00090 'required' => true ), 00091 'placement' => array( 'name' => 'Position', 00092 'datatype' => 'integer', 00093 'default' => 0, 00094 'required' => true ), 00095 'is_searchable' => array( 'name' => 'IsSearchable', 00096 'datatype' => 'integer', 00097 'default' => 0 00098 ), 00099 'is_required' => array( 'name' => 'IsRequired', 00100 'datatype' => 'integer', 00101 'default' => 0, 00102 'required' => true ), 00103 'can_translate' => array( 'name' => 'CanTranslate', 00104 'datatype' => 'integer', 00105 'default' => 0 00106 ), 00107 'is_information_collector' => array( 'name' => 'IsInformationCollector', 00108 'datatype' => 'integer', 00109 'default' => 0, 00110 'required' => true ), 00111 'data_type_string' => array( 'name' => 'DataTypeString', 00112 'datatype' => 'string', 00113 'default' => '', 00114 'required' => true ), 00115 'data_int1' => array( 'name' => 'DataInt1', 00116 'datatype' => 'integer', 00117 'default' => 0, 00118 'required' => true ), 00119 'data_int2' => array( 'name' => 'DataInt2', 00120 'datatype' => 'integer', 00121 'default' => 0, 00122 'required' => true ), 00123 'data_int3' => array( 'name' => 'DataInt3', 00124 'datatype' => 'integer', 00125 'default' => 0, 00126 'required' => true ), 00127 'data_int4' => array( 'name' => 'DataInt4', 00128 'datatype' => 'integer', 00129 'default' => 0, 00130 'required' => true ), 00131 'data_float1' => array( 'name' => 'DataFloat1', 00132 'datatype' => 'float', 00133 'default' => 0, 00134 'required' => true ), 00135 'data_float2' => array( 'name' => 'DataFloat2', 00136 'datatype' => 'float', 00137 'default' => 0, 00138 'required' => true ), 00139 'data_float3' => array( 'name' => 'DataFloat3', 00140 'datatype' => 'float', 00141 'default' => 0, 00142 'required' => true ), 00143 'data_float4' => array( 'name' => 'DataFloat4', 00144 'datatype' => 'float', 00145 'default' => 0, 00146 'required' => true ), 00147 'data_text1' => array( 'name' => 'DataText1', 00148 'datatype' => 'text', 00149 'default' => '', 00150 'required' => true ), 00151 'data_text2' => array( 'name' => 'DataText2', 00152 'datatype' => 'text', 00153 'default' => '', 00154 'required' => true ), 00155 'data_text3' => array( 'name' => 'DataText3', 00156 'datatype' => 'text', 00157 'default' => '', 00158 'required' => true ), 00159 'data_text4' => array( 'name' => 'DataText4', 00160 'datatype' => 'text', 00161 'default' => '', 00162 'required' => true ), 00163 'data_text5' => array( 'name' => 'DataText5', 00164 'datatype' => 'text', 00165 'default' => '', 00166 'required' => true ), 00167 'serialized_data_text' => array( 'name' => 'SerializedDataText', 00168 'datatype' => 'string', 00169 'default' => '', 00170 'required' => true ), 00171 'category' => array( 'name' => 'Category', 00172 'datatype' => 'text', 00173 'default' => '', 00174 'required' => true )), 00175 'keys' => array( 'id', 'version' ), 00176 "function_attributes" => array( "content" => "content", 00177 'temporary_object_attribute' => 'instantiateTemporary', 00178 'data_type' => 'dataType', 00179 'display_info' => 'displayInfo', 00180 'name' => 'name', 00181 'nameList' => 'nameList', 00182 'description' => 'description', 00183 'descriptionList' => 'descriptionList', 00184 'data_text_i18n' => 'dataTextI18n', 00185 'data_text_i18n_list' => 'dataTextI18nList' ), 00186 'set_functions' => array( 'name' => 'setName', 00187 'description' => 'setDescription', 00188 'data_text_i18n' => 'setDataTextI18n' ), 00189 'increment_key' => 'id', 00190 'sort' => array( 'placement' => 'asc' ), 00191 'class_name' => 'eZContentClassAttribute', 00192 'name' => 'ezcontentclass_attribute' ); 00193 return $definition; 00194 } 00195 00196 function __clone() 00197 { 00198 $this->ID = null; 00199 } 00200 00201 /*! 00202 Creates an 'eZContentClassAttribute' object. 00203 00204 To specify contentclassattribute name use either $optionalValues['serialized_name_list'] or 00205 combination of $optionalValues['name'] and/or $languageLocale. 00206 00207 In case of conflict(when both 'serialized_name_list' and 'name' with/without $languageLocale 00208 are specified) 'serialized_name_list' has top priority. This means that 'name' and 00209 $languageLocale will be ingnored because 'serialized_name_list' already has all needed info 00210 about names and languages. 00211 00212 If 'name' is specified then the contentclassattribute will have a name in $languageLocale(if specified) or 00213 in default language. 00214 00215 If neither of 'serialized_name_list' or 'name' isn't specified then the contentclassattribute will have an empty 00216 name in 'languageLocale'(if specified) or in default language. 00217 00218 \return 'eZContentClassAttribute' object. 00219 */ 00220 static function create( $class_id, $data_type_string, $optionalValues = array(), $languageLocale = false ) 00221 { 00222 $nameList = new eZSerializedObjectNameList(); 00223 if ( isset( $optionalValues['serialized_name_list'] ) ) 00224 $nameList->initFromSerializedList( $optionalValues['serialized_name_list'] ); 00225 else if ( isset( $optionalValues['name'] ) ) 00226 $nameList->initFromString( $optionalValues['name'], $languageLocale ); 00227 else 00228 $nameList->initFromString( '', $languageLocale ); 00229 00230 $descriptionList = new eZSerializedObjectNameList(); 00231 if ( isset( $optionalValues['serialized_description_list'] ) ) 00232 $descriptionList->initFromSerializedList( $optionalValues['serialized_description_list'] ); 00233 else if ( isset( $optionalValues['description'] ) ) 00234 $descriptionList->initFromString( $optionalValues['description'], $languageLocale ); 00235 else 00236 $descriptionList->initFromString( '', $languageLocale ); 00237 00238 if ( isset( $optionalValues['data_text_i18n'] ) ) 00239 { 00240 $dataTextI18nList = new eZSerializedObjectNameList( $optionalValues['data_text_i18n'] ); 00241 $optionalValues['serialized_data_text'] = $dataTextI18nList->serializeNames(); 00242 } 00243 00244 $row = array( 00245 'id' => null, 00246 'version' => eZContentClass::VERSION_STATUS_TEMPORARY, 00247 'contentclass_id' => $class_id, 00248 'identifier' => '', 00249 'serialized_name_list' => $nameList->serializeNames(), 00250 'serialized_description_list' => $descriptionList->serializeNames(), 00251 'is_searchable' => 1, 00252 'is_required' => 0, 00253 'can_translate' => 1, 00254 'is_information_collector' => 0, 00255 'data_type_string' => $data_type_string, 00256 'placement' => eZPersistentObject::newObjectOrder( eZContentClassAttribute::definition(), 00257 'placement', 00258 array( 'version' => 1, 00259 'contentclass_id' => $class_id ) ) ); 00260 $row = array_merge( $row, $optionalValues ); 00261 $attribute = new eZContentClassAttribute( $row ); 00262 00263 return $attribute; 00264 } 00265 00266 function instantiate( $contentobjectID, $languageCode = false, $version = 1 ) 00267 { 00268 $attribute = eZContentObjectAttribute::create( $this->attribute( 'id' ), $contentobjectID, $version, $languageCode ); 00269 $attribute->initialize(); 00270 $attribute->store(); 00271 $attribute->postInitialize(); 00272 } 00273 00274 function instantiateTemporary( $contentobjectID = false ) 00275 { 00276 return eZContentObjectAttribute::create( $this->attribute( 'id' ), $contentobjectID ); 00277 } 00278 00279 function store( $fieldFilters = null ) 00280 { 00281 $dataType = $this->dataType(); 00282 if ( !$dataType ) 00283 { 00284 return false; 00285 } 00286 00287 self::expireCache( $this->ID, $this->attribute( 'contentclass_id' ) ); 00288 00289 $dataType->preStoreClassAttribute( $this, $this->attribute( 'version' ) ); 00290 00291 $this->setAttribute( 'serialized_name_list', $this->NameList->serializeNames() ); 00292 $this->setAttribute( 'serialized_description_list', $this->DescriptionList->serializeNames() ); 00293 $this->setAttribute( 'serialized_data_text', $this->DataTextI18nList->serializeNames() ); 00294 00295 $stored = eZPersistentObject::store( $fieldFilters ); 00296 00297 // store the content data for this attribute 00298 $dataType->storeClassAttribute( $this, $this->attribute( 'version' ) ); 00299 00300 return $stored; 00301 } 00302 00303 /** 00304 * Store the content class in the version status "defined". 00305 * 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 * @return null|false false if the operation failed 00310 */ 00311 function storeDefined() 00312 { 00313 return $this->storeVersioned( eZContentClass::VERSION_STATUS_DEFINED ); 00314 } 00315 00316 /** 00317 * Store the content class in the specified version status. 00318 * 00319 * @note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00320 * the calls within a db transaction; thus within db->begin and db->commit. 00321 * 00322 * @param int $version version status 00323 * @since Version 4.3 00324 * @return null|false false if the operation failed 00325 */ 00326 function storeVersioned( $version ) 00327 { 00328 $dataType = $this->dataType(); 00329 if ( !$dataType ) 00330 { 00331 return false; 00332 } 00333 00334 self::expireCache( $this->ID, $this->attribute( 'contentclass_id' ) ); 00335 00336 $db = eZDB::instance(); 00337 $db->begin(); 00338 $dataType->preStoreVersionedClassAttribute( $this, $version ); 00339 00340 $this->setAttribute( 'serialized_name_list', $this->NameList->serializeNames() ); 00341 $this->setAttribute( 'serialized_description_list', $this->DescriptionList->serializeNames() ); 00342 $this->setAttribute( 'serialized_data_text', $this->DataTextI18nList->serializeNames() ); 00343 00344 eZPersistentObject::store(); 00345 00346 // store the content data for this attribute 00347 $dataType->storeVersionedClassAttribute( $this, $version ); 00348 $db->commit(); 00349 } 00350 00351 /*! 00352 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00353 the calls within a db transaction; thus within db->begin and db->commit. 00354 */ 00355 function removeThis( $quiet = false ) 00356 { 00357 $dataType = $this->dataType(); 00358 if ( $dataType->isClassAttributeRemovable( $this ) ) 00359 { 00360 self::expireCache( $this->ID, $this->attribute( 'contentclass_id' ) ); 00361 00362 $db = eZDB::instance(); 00363 $db->begin(); 00364 $dataType->deleteStoredClassAttribute( $this, $this->Version ); 00365 eZPersistentObject::remove(); 00366 $db->commit(); 00367 return true; 00368 } 00369 else 00370 { 00371 if ( !$quiet ) 00372 { 00373 eZDebug::writeError( 'Datatype [' . $dataType->attribute( 'name' ) . '] can not be deleted to avoid system crash' ); 00374 } 00375 return false; 00376 } 00377 } 00378 00379 static function fetch( $id, $asObject = true, $version = eZContentClass::VERSION_STATUS_DEFINED, $field_filters = null ) 00380 { 00381 $object = null; 00382 if ( $field_filters === null and $asObject and 00383 isset( $GLOBALS['eZContentClassAttributeCache'][$id][$version] ) ) 00384 { 00385 $object = $GLOBALS['eZContentClassAttributeCache'][$id][$version]; 00386 } 00387 if ( $object === null ) 00388 { 00389 $object = eZPersistentObject::fetchObject( eZContentClassAttribute::definition(), 00390 $field_filters, 00391 array( 'id' => $id, 00392 'version' => $version ), 00393 $asObject ); 00394 if ( $field_filters === null and $asObject ) 00395 { 00396 $GLOBALS['eZContentClassAttributeCache'][$id][$version] = $object; 00397 } 00398 } 00399 return $object; 00400 } 00401 00402 static function fetchList( $asObject = true, $parameters = array() ) 00403 { 00404 $parameters = array_merge( array( 'data_type' => false, 00405 'version' => false ), 00406 $parameters ); 00407 $dataType = $parameters['data_type']; 00408 $version = $parameters['version']; 00409 $objects = null; 00410 if ( $asObject && 00411 $dataType === false && 00412 $version === false ) 00413 { 00414 $objects = $GLOBALS['eZContentClassAttributeCacheListFull']; 00415 } 00416 if ( !isset( $objects ) or 00417 $objects === null ) 00418 { 00419 $conditions = null; 00420 if ( $dataType !== false or 00421 $version !== false ) 00422 { 00423 $conditions = array(); 00424 if ( $dataType !== false ) 00425 $conditions['data_type_string'] = $dataType; 00426 if ( $version !== false ) 00427 $conditions['version'] = $version; 00428 } 00429 $objects = eZPersistentObject::fetchObjectList( eZContentClassAttribute::definition(), 00430 null, $conditions, null, null, 00431 $asObject ); 00432 if ( $asObject ) 00433 { 00434 foreach ( $objects as $objectItem ) 00435 { 00436 $objectID = $objectItem->ID; 00437 $objectVersion = $objectItem->Version; 00438 $GLOBALS['eZContentClassAttributeCache'][$objectID][$objectVersion] = $objectItem; 00439 } 00440 if ( $dataType === false && $version === false ) 00441 { 00442 $GLOBALS['eZContentClassAttributeCacheListFull'] = $objects; 00443 } 00444 } 00445 } 00446 return $objects; 00447 } 00448 00449 static function fetchListByClassID( $classID, $version = eZContentClass::VERSION_STATUS_DEFINED, $asObject = true ) 00450 { 00451 $objects = null; 00452 if ( $asObject ) 00453 { 00454 if ( isset( $GLOBALS['eZContentClassAttributeCacheList'][$classID][$version] ) ) 00455 $objects = $GLOBALS['eZContentClassAttributeCacheList'][$classID][$version]; 00456 } 00457 if ( !isset( $objects ) or 00458 $objects === null ) 00459 { 00460 $cond = array( 'contentclass_id' => $classID, 00461 'version' => $version ); 00462 $objects = eZPersistentObject::fetchObjectList( eZContentClassAttribute::definition(), 00463 null, $cond, null, null, 00464 $asObject ); 00465 if ( $asObject ) 00466 { 00467 foreach ( $objects as $objectItem ) 00468 { 00469 $objectID = $objectItem->ID; 00470 $objectVersion = $objectItem->Version; 00471 if ( !isset( $GLOBALS['eZContentClassAttributeCache'][$objectID][$objectVersion] ) ) 00472 $GLOBALS['eZContentClassAttributeCache'][$objectID][$objectVersion] = $objectItem; 00473 } 00474 $GLOBALS['eZContentClassAttributeCacheList'][$classID][$version] = $objects; 00475 } 00476 } 00477 return $objects; 00478 } 00479 00480 static function fetchFilteredList( $cond, $asObject = true ) 00481 { 00482 $objectList = eZPersistentObject::fetchObjectList( eZContentClassAttribute::definition(), 00483 null, $cond, null, null, 00484 $asObject ); 00485 if ( $asObject ) 00486 { 00487 foreach ( $objectList as $objectItem ) 00488 { 00489 $objectID = $objectItem->ID; 00490 $objectVersion = $objectItem->Version; 00491 if ( !isset( $GLOBALS['eZContentClassAttributeCache'][$objectID][$objectVersion] ) ) 00492 $GLOBALS['eZContentClassAttributeCache'][$objectID][$objectVersion] = $objectItem; 00493 } 00494 } 00495 return $objectList; 00496 } 00497 00498 /*! 00499 Moves the object down if $down is true, otherwise up. 00500 If object is at either top or bottom it is wrapped around. 00501 \note Transaction unsafe. If you call several transaction unsafe methods you must enclose 00502 the calls within a db transaction; thus within db->begin and db->commit. 00503 */ 00504 function move( $down, $params = null ) 00505 { 00506 if ( is_array( $params ) ) 00507 { 00508 $pos = $params['placement']; 00509 $cid = $params['contentclass_id']; 00510 $version = $params['version']; 00511 } 00512 else 00513 { 00514 $pos = $this->Position; 00515 $cid = $this->ContentClassID; 00516 $version = $this->Version; 00517 } 00518 eZPersistentObject::reorderObject( eZContentClassAttribute::definition(), 00519 array( 'placement' => $pos ), 00520 array( 'contentclass_id' => $cid, 00521 'version' => $version ), 00522 $down ); 00523 } 00524 00525 function dataType() 00526 { 00527 return eZDataType::create( $this->DataTypeString ); 00528 } 00529 00530 /*! 00531 \return The content for this attribute. 00532 */ 00533 function content() 00534 { 00535 if ( $this->Content === null ) 00536 { 00537 $dataType = $this->dataType(); 00538 $this->Content = $dataType->classAttributeContent( $this ); 00539 } 00540 00541 return $this->Content; 00542 } 00543 00544 /*! 00545 Sets the content for the current attribute 00546 */ 00547 function setContent( $content ) 00548 { 00549 $this->Content = $content; 00550 } 00551 00552 /*! 00553 \return Information on how to display the class attribute. 00554 See eZDataType::classDisplayInformation() for more information on what is returned. 00555 */ 00556 function displayInfo() 00557 { 00558 if ( !$this->DisplayInfo ) 00559 { 00560 $dataType = $this->dataType(); 00561 if ( is_object( $dataType ) ) 00562 { 00563 $this->DisplayInfo = $dataType->classDisplayInformation( $this, false ); 00564 } 00565 } 00566 return $this->DisplayInfo; 00567 } 00568 00569 /*! 00570 Executes the custom HTTP action 00571 */ 00572 function customHTTPAction( $module, $http, $action ) 00573 { 00574 $dataType = $this->dataType(); 00575 $this->Module = $module; 00576 $dataType->customClassAttributeHTTPAction( $http, $action, $this ); 00577 unset( $this->Module ); 00578 $this->Module = null; 00579 } 00580 00581 /*! 00582 \return the module which uses this attribute or \c null if no module set. 00583 \note Currently only customHTTPAction sets this. 00584 */ 00585 function currentModule() 00586 { 00587 return $this->Module; 00588 } 00589 00590 static function cachedInfo() 00591 { 00592 eZExpiryHandler::registerShutdownFunction(); 00593 00594 $info = array(); 00595 $db = eZDB::instance(); 00596 $dbName = md5( $db->DB ); 00597 00598 $cacheDir = eZSys::cacheDirectory(); 00599 $phpCache = new eZPHPCreator( "$cacheDir", "sortkey_$dbName.php", '', array( 'clustering' => 'sortkey' ) ); 00600 $handler = eZExpiryHandler::instance(); 00601 $expiryTime = 0; 00602 00603 if ( $handler->hasTimestamp( 'sort-key-cache' ) ) 00604 { 00605 $expiryTime = $handler->timestamp( 'sort-key-cache' ); 00606 } 00607 00608 if ( $phpCache->canRestore( $expiryTime ) ) 00609 { 00610 $info = $phpCache->restore( array( 'sortkey_type_array' => 'sortKeyTypeArray', 00611 'attribute_type_array' => 'attributeTypeArray' ) ); 00612 } 00613 else 00614 { 00615 // Fetch all datatypes and id's used 00616 $query = "SELECT id, data_type_string FROM ezcontentclass_attribute"; 00617 $attributeArray = $db->arrayQuery( $query ); 00618 00619 $attributeTypeArray = array(); 00620 $sortKeyTypeArray = array(); 00621 foreach ( $attributeArray as $attribute ) 00622 { 00623 $attributeTypeArray[$attribute['id']] = $attribute['data_type_string']; 00624 $sortKeyTypeArray[$attribute['data_type_string']] = 0; 00625 } 00626 00627 // Fetch datatype for every unique datatype 00628 foreach ( array_keys( $sortKeyTypeArray ) as $key ) 00629 { 00630 unset( $dataType ); 00631 $dataType = eZDataType::create( $key ); 00632 if( is_object( $dataType ) ) 00633 $sortKeyTypeArray[$key] = $dataType->sortKeyType(); 00634 } 00635 unset( $dataType ); 00636 00637 // Store identifier list to cache file 00638 $phpCache->addVariable( 'sortKeyTypeArray', $sortKeyTypeArray ); 00639 $phpCache->addVariable( 'attributeTypeArray', $attributeTypeArray ); 00640 $phpCache->store(); 00641 00642 $info['sortkey_type_array'] = $sortKeyTypeArray; 00643 $info['attribute_type_array'] = $attributeTypeArray; 00644 } 00645 00646 return $info; 00647 } 00648 00649 /*! 00650 \static 00651 */ 00652 static function sortKeyTypeByID( $classAttributeID ) 00653 { 00654 $sortKeyType = false; 00655 00656 $info = eZContentClassAttribute::cachedInfo(); 00657 if ( isset( $info['attribute_type_array'][$classAttributeID] ) ) 00658 { 00659 $classAttributeType = $info['attribute_type_array'][$classAttributeID]; 00660 $sortKeyType = $info['sortkey_type_array'][$classAttributeType]; 00661 } 00662 00663 return $sortKeyType; 00664 } 00665 00666 /*! 00667 \static 00668 */ 00669 static function dataTypeByID( $classAttributeID ) 00670 { 00671 $dataTypeString = false; 00672 $info = eZContentClassAttribute::cachedInfo(); 00673 00674 if ( isset( $info['attribute_type_array'][$classAttributeID] ) ) 00675 $dataTypeString = $info['attribute_type_array'][$classAttributeID]; 00676 00677 return $dataTypeString; 00678 } 00679 00680 /*! 00681 This methods relay calls to the diff method inside the datatype. 00682 */ 00683 function diff( $old, $new ) 00684 { 00685 $datatype = $this->dataType(); 00686 $result = $datatype->diff( $old, $new ); 00687 return $result; 00688 } 00689 00690 /** 00691 * Returns name from serialized string, can be used for serialized description and data_text as well. 00692 * 00693 * @param string $serializedNameList 00694 * @param string|false $languageLocale Uses AlwaysAvailable language if false 00695 * @return string 00696 */ 00697 static function nameFromSerializedString( $serializedNameList, $languageLocale = false ) 00698 { 00699 return eZSerializedObjectNameList::nameFromSerializedString( $serializedNameList, $languageLocale ); 00700 } 00701 00702 /** 00703 * Returns name of attribute based on serialized_name_list 00704 * 00705 * @param string|false $languageLocale Uses AlwaysAvailable language if false 00706 * @return string 00707 */ 00708 function name( $languageLocale = false ) 00709 { 00710 return $this->NameList->name( $languageLocale ); 00711 } 00712 00713 /** 00714 * Sets name of attribute, store() will take care of writing back to serialized_name_list 00715 * 00716 * @param string $name 00717 * @param string|false $languageLocale Uses AlwaysAvailable language if false 00718 * @return string Return old value 00719 */ 00720 function setName( $name, $languageLocale = false ) 00721 { 00722 return $this->NameList->setName( $name, $languageLocale ); 00723 } 00724 00725 /** 00726 * Returns name list for all locales for attribute 00727 * 00728 * @return array 00729 */ 00730 function nameList() 00731 { 00732 return $this->NameList->nameList(); 00733 } 00734 00735 /** 00736 * Returns description of attribute based on serialized_description_list 00737 * 00738 * @param string|false $languageLocale Uses AlwaysAvailable language if false 00739 * @return string 00740 */ 00741 function description( $languageLocale = false ) 00742 { 00743 return $this->DescriptionList->name( $languageLocale ); 00744 } 00745 00746 /** 00747 * Sets description of attribute, store() will take care of writing back to serialized_description_list 00748 * 00749 * @param string $description 00750 * @param string|false $languageLocale Uses AlwaysAvailable language if false 00751 * @return string Return old value 00752 */ 00753 function setDescription( $description, $languageLocale = false ) 00754 { 00755 return $this->DescriptionList->setName( $description, $languageLocale ); 00756 } 00757 00758 /** 00759 * Returns description list for all locales for attribute 00760 * 00761 * @return array 00762 */ 00763 function descriptionList() 00764 { 00765 return $this->DescriptionList->nameList(); 00766 } 00767 00768 /** 00769 * Returns data_text_i18n of attribute based on serialized_data_text 00770 * 00771 * @param string|false $languageLocale Uses AlwaysAvailable language if false 00772 * @return string 00773 */ 00774 function dataTextI18n( $languageLocale = false ) 00775 { 00776 return $this->DataTextI18nList->name( $languageLocale ); 00777 } 00778 00779 /** 00780 * Sets data_text_i18n of attribute, store() will take care of writing back to serialized_data_text 00781 * 00782 * @param string $string 00783 * @param string|false $languageLocale Uses AlwaysAvailable language if false 00784 * @return string Return old value 00785 */ 00786 function setDataTextI18n( $string, $languageLocale = false ) 00787 { 00788 return $this->DataTextI18nList->setName( $string, $languageLocale ); 00789 } 00790 00791 /** 00792 * Returns data_text_i18n list for all locales for attribute 00793 * 00794 * @return array 00795 */ 00796 function dataTextI18nList() 00797 { 00798 return $this->DataTextI18nList->nameList(); 00799 } 00800 00801 /** 00802 * Returns locale code as set with {@link self::setEditLocale()} 00803 * 00804 * @return string|false 00805 */ 00806 function editLocale() 00807 { 00808 return $this->EditLocale; 00809 } 00810 00811 /** 00812 * Sets locale code of attribute for use by datatypes in class/edit storing process. 00813 * 00814 * @param string|false $languageLocale Uses AlwaysAvailable language if false 00815 */ 00816 function setEditLocale( $languageLocale = false ) 00817 { 00818 $this->EditLocale = $languageLocale; 00819 } 00820 00821 /** 00822 * Specify AlwaysAvailableLanguage (for name, description or data_text_i18n) 00823 * 00824 * @param string|false $languageLocale 00825 */ 00826 function setAlwaysAvailableLanguage( $languageLocale ) 00827 { 00828 if ( $languageLocale ) 00829 { 00830 $this->NameList->setAlwaysAvailableLanguage( $languageLocale ); 00831 $this->DescriptionList->setAlwaysAvailableLanguage( $languageLocale ); 00832 $this->DataTextI18nList->setAlwaysAvailableLanguage( $languageLocale ); 00833 } 00834 else 00835 { 00836 $this->NameList->setAlwaysAvailableLanguage( false ); 00837 $this->DescriptionList->setAlwaysAvailableLanguage( false ); 00838 $this->DataTextI18nList->setAlwaysAvailableLanguage( false ); 00839 } 00840 } 00841 00842 /** 00843 * Removes an translation (as in the serilized strings for name, description or data_text_i18n) 00844 * 00845 * @param string $languageLocale 00846 */ 00847 function removeTranslation( $languageLocale ) 00848 { 00849 $this->NameList->removeName( $languageLocale ); 00850 $this->DescriptionList->removeName( $languageLocale ); 00851 $this->DataTextI18nList->removeName( $languageLocale ); 00852 } 00853 00854 /** 00855 * Resolves the string class attribute identifier $identifier to its numeric value 00856 * Use {@link eZContentObjectTreeNode::classAttributeIDByIdentifier()} for < 4.1. 00857 * If multiple classes have the same identifier, the first found is returned. 00858 * 00859 * @static 00860 * @since Version 4.1 00861 * @return int|false Returns classattributeid or false 00862 */ 00863 public static function classAttributeIDByIdentifier( $identifier ) 00864 { 00865 $identifierHash = self::classAttributeIdentifiersHash(); 00866 00867 if ( isset( $identifierHash[$identifier] ) ) 00868 return $identifierHash[$identifier]; 00869 else 00870 return false; 00871 } 00872 00873 /** 00874 * Resolves the numeric class attribute identifier $id to its string value 00875 * 00876 * @static 00877 * @since Version 4.1 00878 * @return string|false Returns classattributeidentifier or false 00879 */ 00880 public static function classAttributeIdentifierByID( $id ) 00881 { 00882 $identifierHash = array_flip( self::classAttributeIdentifiersHash() ); 00883 00884 if ( isset( $identifierHash[$id] ) ) 00885 { 00886 $classAndClassAttributeIdentifier = explode( '/', $identifierHash[$id] ); 00887 return $classAndClassAttributeIdentifier[1]; 00888 } 00889 else 00890 return false; 00891 } 00892 00893 /** 00894 * Returns the class attribute identifier hash for the current database. 00895 * If it is outdated or non-existent, the method updates/generates the file 00896 * 00897 * @static 00898 * @since Version 4.1 00899 * @access protected 00900 * @return array Returns hash of classattributeidentifier => classattributeid 00901 */ 00902 protected static function classAttributeIdentifiersHash() 00903 { 00904 if ( self::$identifierHash === null ) 00905 { 00906 $db = eZDB::instance(); 00907 $dbName = md5( $db->DB ); 00908 00909 $cacheDir = eZSys::cacheDirectory(); 00910 $phpCache = new eZPHPCreator( $cacheDir, 00911 'classattributeidentifiers_' . $dbName . '.php', 00912 '', 00913 array( 'clustering' => 'classattridentifiers' ) ); 00914 00915 eZExpiryHandler::registerShutdownFunction(); 00916 $handler = eZExpiryHandler::instance(); 00917 $expiryTime = 0; 00918 if ( $handler->hasTimestamp( 'class-identifier-cache' ) ) 00919 { 00920 $expiryTime = $handler->timestamp( 'class-identifier-cache' ); 00921 } 00922 00923 if ( $phpCache->canRestore( $expiryTime ) ) 00924 { 00925 $var = $phpCache->restore( array( 'identifierHash' => 'identifier_hash' ) ); 00926 self::$identifierHash = $var['identifierHash']; 00927 } 00928 else 00929 { 00930 // Fetch identifier/id pair from db 00931 $query = "SELECT ezcontentclass_attribute.id as attribute_id, ezcontentclass_attribute.identifier as attribute_identifier, ezcontentclass.identifier as class_identifier 00932 FROM ezcontentclass_attribute, ezcontentclass 00933 WHERE ezcontentclass.id=ezcontentclass_attribute.contentclass_id"; 00934 $identifierArray = $db->arrayQuery( $query ); 00935 00936 self::$identifierHash = array(); 00937 foreach ( $identifierArray as $identifierRow ) 00938 { 00939 $combinedIdentifier = $identifierRow['class_identifier'] . '/' . $identifierRow['attribute_identifier']; 00940 self::$identifierHash[$combinedIdentifier] = (int) $identifierRow['attribute_id']; 00941 } 00942 00943 // Store identifier list to cache file 00944 $phpCache->addVariable( 'identifier_hash', self::$identifierHash ); 00945 $phpCache->store(); 00946 } 00947 } 00948 return self::$identifierHash; 00949 } 00950 00951 /** 00952 * Initialize the attribute in the existing objects. 00953 * 00954 * @param mixed $objects not used, the existing objects are fetched if 00955 * necessary (depending on the datatype of the attribute). 00956 */ 00957 function initializeObjectAttributes( &$objects = null ) 00958 { 00959 $classAttributeID = $this->ID; 00960 $classID = $this->ContentClassID; 00961 $dataType = $this->attribute( 'data_type' ); 00962 if ( $dataType->supportsBatchInitializeObjectAttribute() ) 00963 { 00964 $db = eZDB::instance(); 00965 00966 $data = array( 'contentobject_id' => 'a.contentobject_id', 00967 'version' => 'a.version', 00968 'contentclassattribute_id' => $classAttributeID, 00969 'data_type_string' => "'" . $db->escapeString( $this->DataTypeString ) . "'", 00970 'language_code' => 'a.language_code', 00971 'language_id' => 'MAX(a.language_id)' ); 00972 00973 $datatypeData = $dataType->batchInitializeObjectAttributeData( $this ); 00974 $data = array_merge( $data, $datatypeData ); 00975 00976 $cols = implode( ', ', array_keys( $data ) ); 00977 $values = implode( ', ', $data ); 00978 00979 $sql = "INSERT INTO ezcontentobject_attribute( $cols ) 00980 SELECT $values 00981 FROM ezcontentobject_attribute a, ezcontentobject o 00982 WHERE o.id = a.contentobject_id AND 00983 o.contentclass_id=$classID 00984 GROUP BY contentobject_id, 00985 version, 00986 language_code"; 00987 00988 $db->query( $sql ); 00989 // update ids to keep them same with one attribute for different versions 00990 if( $db->databaseName() == 'mysql' ) 00991 { 00992 $updateSql = "UPDATE ezcontentobject_attribute, 00993 ( SELECT contentobject_id, language_code, version, contentclassattribute_id, MIN( id ) AS minid 00994 FROM ezcontentobject_attribute WHERE contentclassattribute_id = $classAttributeID 00995 GROUP BY contentobject_id, language_code, version, contentclassattribute_id ) t 00996 SET ezcontentobject_attribute.id = t.minid 00997 WHERE ezcontentobject_attribute.contentobject_id = t.contentobject_id 00998 AND ezcontentobject_attribute.language_code = t.language_code 00999 AND ezcontentobject_attribute.contentclassattribute_id = $classAttributeID"; 01000 } 01001 else if( $db->databaseName() == 'postgresql' ) 01002 { 01003 $updateSql = "UPDATE ezcontentobject_attribute 01004 SET id=t.minid FROM 01005 ( SELECT contentobject_id, language_code, version, contentclassattribute_id, MIN( id ) AS minid 01006 FROM ezcontentobject_attribute WHERE contentclassattribute_id = $classAttributeID 01007 GROUP BY contentobject_id, language_code, version, contentclassattribute_id ) t 01008 WHERE ezcontentobject_attribute.contentobject_id = t.contentobject_id 01009 AND ezcontentobject_attribute.language_code = t.language_code 01010 AND ezcontentobject_attribute.contentclassattribute_id = $classAttributeID"; 01011 } 01012 else if( $db->databaseName() == 'oracle' ) 01013 { 01014 $updateSql = "UPDATE ezcontentobject_attribute a SET a.id = ( 01015 SELECT MIN( id ) FROM ezcontentobject_attribute b 01016 WHERE b.contentclassattribute_id = $classAttributeID 01017 AND b.contentobject_id = a.contentobject_id 01018 AND b.language_code = a.language_code ) 01019 WHERE a.contentclassattribute_id = $classAttributeID"; 01020 } 01021 else 01022 { 01023 $updateSql = ""; 01024 } 01025 $db->query( $updateSql ); 01026 } 01027 else 01028 { 01029 $limit = 1000; 01030 $offset = 0; 01031 while ( true ) 01032 { 01033 $contentObjects = eZContentObject::fetchSameClassList( $classID, true, $offset, $limit ); 01034 if ( empty( $contentObjects ) ) 01035 { 01036 break; 01037 } 01038 01039 foreach ( $contentObjects as $object ) 01040 { 01041 $contentobjectID = $object->attribute( 'id' ); 01042 $objectVersions = $object->versions(); 01043 // the start version ID, to make sure one attribute in different version has same id. 01044 $startAttributeID = array(); 01045 foreach ( $objectVersions as $objectVersion ) 01046 { 01047 $translations = $objectVersion->translations( false ); 01048 $version = $objectVersion->attribute( 'version' ); 01049 foreach ( $translations as $translation ) 01050 { 01051 $objectAttribute = eZContentObjectAttribute::create( $classAttributeID, $contentobjectID, $version, $translation ); 01052 if( array_key_exists( $translation, $startAttributeID ) ) 01053 { 01054 $objectAttribute->setAttribute( 'id', $startAttributeID[$translation] ); 01055 } 01056 $objectAttribute->setAttribute( 'language_code', $translation ); 01057 $objectAttribute->initialize(); 01058 $objectAttribute->store(); 01059 if( !array_key_exists( $translation, $startAttributeID ) ) 01060 { 01061 $startAttributeID[$translation] = $objectAttribute->attribute( 'id' ); 01062 } 01063 $objectAttribute->postInitialize(); 01064 } 01065 } 01066 } 01067 01068 $offset += $limit; 01069 eZContentObject::clearCache(); 01070 } 01071 } 01072 } 01073 01074 /** 01075 * Clears all content class attribute related caches 01076 * 01077 * @param int $contentClassAttributeID Specific attribute ID to clear cache for 01078 * @param int $contentClassID Specific attribute ID to clear cache for 01079 * 01080 * @return void 01081 * @since 4.2 01082 */ 01083 public static function expireCache( $contentClassAttributeID = false, $contentClassID = false) 01084 { 01085 unset( $GLOBALS['eZContentClassAttributeCacheListFull'] ); 01086 if ( $contentClassID !== false ) 01087 { 01088 if ( isset( $GLOBALS['eZContentClassAttributeCacheList'][$contentClassID] ) ) 01089 { 01090 unset( $GLOBALS['eZContentClassAttributeCacheList'][$contentClassID] ); 01091 } 01092 } 01093 else 01094 { 01095 unset( $GLOBALS['eZContentClassAttributeCacheList'] ); 01096 } 01097 if ( $contentClassAttributeID !== false ) 01098 { 01099 if ( isset( $GLOBALS['eZContentClassAttributeCache'][$contentClassAttributeID] ) ) 01100 { 01101 unset( $GLOBALS['eZContentClassAttributeCache'][$contentClassAttributeID] ); 01102 } 01103 } 01104 else 01105 { 01106 unset( $GLOBALS['eZContentClassAttributeCache'] ); 01107 } 01108 01109 // expire cache file by timestamp 01110 $handler = eZExpiryHandler::instance(); 01111 $handler->setTimestamp( 'class-identifier-cache', time() + 1 ); 01112 $handler->store(); 01113 01114 // expire local, in-memory cache 01115 self::$identifierHash = null; 01116 } 01117 01118 /// \privatesection 01119 /// Contains the content for this attribute 01120 public $Content; 01121 /// Contains information on how to display the current attribute in various viewmodes 01122 public $DisplayInfo; 01123 public $ID; 01124 public $Version; 01125 public $ContentClassID; 01126 public $Identifier; 01127 // serialized array of translated names 01128 public $SerializedNameList; 01129 // unserialized attribute names 01130 public $NameList; 01131 // unserialized attribute description 01132 public $DescriptionList; 01133 public $DataTypeString; 01134 public $Position; 01135 public $IsSearchable; 01136 public $IsRequired; 01137 public $IsInformationCollector; 01138 public $Module; 01139 // Used locale for use by datatypes in class/edit when storing data 01140 protected $EditLocale = false; 01141 01142 /** 01143 * In-memory cache for class attributes identifiers / id matching 01144 */ 01145 private static $identifierHash = null; 01146 } 01147 01148 ?>