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