eZ Publish  [trunk]
ezcontentclass.php
Go to the documentation of this file.
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 ?>