PageRenderTime 69ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/kernel/classes/ezcontentclass.php

https://github.com/granitegreg/ezpublish
PHP | 2017 lines | 1429 code | 221 blank | 367 comment | 175 complexity | f66e314d69358035ce6717cc0c434652 MD5 | raw file
Possible License(s): GPL-2.0

Large files files are truncated, but you can click here to view the full file

  1. <?php
  2. //
  3. // Definition of eZContentClass class
  4. //
  5. // Created on: <16-Apr-2002 11:08:14 amos>
  6. //
  7. // ## BEGIN COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
  8. // SOFTWARE NAME: eZ Publish
  9. // SOFTWARE RELEASE: 4.1.x
  10. // COPYRIGHT NOTICE: Copyright (C) 1999-2011 eZ Systems AS
  11. // SOFTWARE LICENSE: GNU General Public License v2.0
  12. // NOTICE: >
  13. // This program is free software; you can redistribute it and/or
  14. // modify it under the terms of version 2.0 of the GNU General
  15. // Public License as published by the Free Software Foundation.
  16. //
  17. // This program is distributed in the hope that it will be useful,
  18. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  19. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  20. // GNU General Public License for more details.
  21. //
  22. // You should have received a copy of version 2.0 of the GNU General
  23. // Public License along with this program; if not, write to the Free
  24. // Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
  25. // MA 02110-1301, USA.
  26. //
  27. //
  28. // ## END COPYRIGHT, LICENSE AND WARRANTY NOTICE ##
  29. //
  30. /*!
  31. \class eZContentClass ezcontentclass.php
  32. \ingroup eZKernel
  33. \brief Handles eZ Publish content classes
  34. \sa eZContentObject
  35. */
  36. class eZContentClass extends eZPersistentObject
  37. {
  38. const VERSION_STATUS_DEFINED = 0;
  39. const VERSION_STATUS_TEMPORARY = 1;
  40. const VERSION_STATUS_MODIFIED = 2;
  41. /**
  42. * Max length of content object name.
  43. * @var int
  44. */
  45. const CONTENT_OBJECT_NAME_MAX_LENGTH = 255;
  46. function eZContentClass( $row )
  47. {
  48. if ( is_array( $row ) )
  49. {
  50. $this->eZPersistentObject( $row );
  51. $this->VersionCount = false;
  52. $this->InGroups = null;
  53. $this->AllGroups = null;
  54. if ( isset( $row["version_count"] ) )
  55. $this->VersionCount = $row["version_count"];
  56. $this->NameList = new eZContentClassNameList();
  57. if ( isset( $row['serialized_name_list'] ) )
  58. $this->NameList->initFromSerializedList( $row['serialized_name_list'] );
  59. else
  60. $this->NameList->initDefault();
  61. $this->DescriptionList = new eZSerializedObjectNameList();
  62. if ( isset( $row['serialized_description_list'] ) )
  63. $this->DescriptionList->initFromSerializedList( $row['serialized_description_list'] );
  64. else
  65. $this->DescriptionList->initDefault();
  66. }
  67. $this->DataMap = false;
  68. }
  69. static function definition()
  70. {
  71. static $definition = array( "fields" => array( "id" => array( 'name' => 'ID',
  72. 'datatype' => 'integer',
  73. 'default' => 0,
  74. 'required' => true ),
  75. "version" => array( 'name' => 'Version',
  76. 'datatype' => 'integer',
  77. 'default' => 0,
  78. 'required' => true ),
  79. "serialized_name_list" => array( 'name' => 'SerializedNameList',
  80. 'datatype' => 'string',
  81. 'default' => '',
  82. 'required' => true ),
  83. 'serialized_description_list' => array( 'name' => 'SerializedDescriptionList',
  84. 'datatype' => 'string',
  85. 'default' => '',
  86. 'required' => true ),
  87. "identifier" => array( 'name' => "Identifier",
  88. 'datatype' => 'string',
  89. 'default' => '',
  90. 'required' => true ),
  91. "contentobject_name" => array( 'name' => "ContentObjectName",
  92. 'datatype' => 'string',
  93. 'default' => '',
  94. 'required' => true ),
  95. "url_alias_name" => array( 'name' => "URLAliasName",
  96. 'datatype' => 'string',
  97. 'default' => '',
  98. 'required' => false ),
  99. "creator_id" => array( 'name' => "CreatorID",
  100. 'datatype' => 'integer',
  101. 'default' => 0,
  102. 'required' => true,
  103. 'foreign_class' => 'eZUser',
  104. 'foreign_attribute' => 'contentobject_id',
  105. 'multiplicity' => '1..*' ),
  106. "modifier_id" => array( 'name' => "ModifierID",
  107. 'datatype' => 'integer',
  108. 'default' => 0,
  109. 'required' => true,
  110. 'foreign_class' => 'eZUser',
  111. 'foreign_attribute' => 'contentobject_id',
  112. 'multiplicity' => '1..*' ),
  113. "created" => array( 'name' => "Created",
  114. 'datatype' => 'integer',
  115. 'default' => 0,
  116. 'required' => true ),
  117. "remote_id" => array( 'name' => "RemoteID",
  118. 'datatype' => 'string',
  119. 'default' => '',
  120. 'required' => true ),
  121. "modified" => array( 'name' => "Modified",
  122. 'datatype' => 'integer',
  123. 'default' => 0,
  124. 'required' => true ),
  125. "is_container" => array( 'name' => "IsContainer",
  126. 'datatype' => 'integer',
  127. 'default' => 0,
  128. 'required' => true ),
  129. 'always_available' => array( 'name' => "AlwaysAvailable",
  130. 'datatype' => 'integer',
  131. 'default' => 0,
  132. 'required' => true ),
  133. 'language_mask' => array( 'name' => "LanguageMask",
  134. 'datatype' => 'integer',
  135. 'default' => 0,
  136. 'required' => true ),
  137. 'initial_language_id' => array( 'name' => "InitialLanguageID",
  138. 'datatype' => 'integer',
  139. 'default' => 0,
  140. 'required' => true,
  141. 'foreign_class' => 'eZContentLanguage',
  142. 'foreign_attribute' => 'id',
  143. 'multiplicity' => '1..*' ),
  144. 'sort_field' => array( 'name' => 'SortField',
  145. 'datatype' => 'integer',
  146. 'default' => 1,
  147. 'required' => true ),
  148. 'sort_order' => array( 'name' => 'SortOrder',
  149. 'datatype' => 'integer',
  150. 'default' => 1,
  151. 'required' => true ) ),
  152. "keys" => array( "id", "version" ),
  153. "function_attributes" => array( "data_map" => "dataMap",
  154. 'object_count' => 'objectCount',
  155. 'object_list' => 'objectList',
  156. 'version_count' => 'versionCount',
  157. 'version_status' => 'versionStatus',
  158. 'remote_id' => 'remoteID', // Note: This overrides remote_id field
  159. 'ingroup_list' => 'fetchGroupList',
  160. 'ingroup_id_list' => 'fetchGroupIDList',
  161. 'match_ingroup_id_list' => 'fetchMatchGroupIDList',
  162. 'group_list' => 'fetchAllGroups',
  163. 'creator' => 'creator',
  164. 'modifier' => 'modifier',
  165. 'can_instantiate_languages' => 'canInstantiateLanguages',
  166. 'name' => 'name',
  167. 'nameList' => 'nameList',
  168. 'description' => 'description',
  169. 'descriptionList' => 'descriptionList',
  170. 'languages' => 'languages',
  171. 'prioritized_languages' => 'prioritizedLanguages',
  172. 'prioritized_languages_js_array' => 'prioritizedLanguagesJsArray',
  173. 'can_create_languages' => 'canCreateLanguages',
  174. 'top_priority_language_locale' => 'topPriorityLanguageLocale',
  175. 'always_available_language' => 'alwaysAvailableLanguage' ),
  176. 'set_functions' => array( 'name' => 'setName' ),
  177. "increment_key" => "id",
  178. "class_name" => "eZContentClass",
  179. "sort" => array( "id" => "asc" ),
  180. "name" => "ezcontentclass" );
  181. return $definition;
  182. }
  183. function __clone()
  184. {
  185. unset( $this->Version );
  186. unset( $this->InGroups );
  187. unset( $this->AllGroups );
  188. unset( $this->CanInstantiateLanguages );
  189. unset( $this->VersionCount );
  190. $this->ID = null;
  191. $this->RemoteID = eZRemoteIdUtility::generate( 'class' );
  192. }
  193. /*!
  194. Creates an 'eZContentClass' object.
  195. To specify contentclass name use either $optionalValues['serialized_name_list'] or
  196. combination of $optionalValues['name'] and/or $languageLocale.
  197. In case of conflict(when both 'serialized_name_list' and 'name' with/without $languageLocale
  198. are specified) 'serialized_name_list' has top priority. This means that 'name' and
  199. $languageLocale will be ingnored because 'serialized_name_list' already has all needed info
  200. about names and languages.
  201. If 'name' is specified then the contentclass will have a name in $languageLocale(if specified) or
  202. in default language.
  203. If neither of 'serialized_name_list' or 'name' isn't specified then the contentclass will have an empty
  204. name in 'languageLocale'(if specified) or in default language.
  205. 'language_mask' and 'initial_language_id' attributes will be set according to specified(either
  206. in 'serialized_name_list' or by $languageLocale) languages.
  207. \return 'eZContentClass' object.
  208. */
  209. static function create( $userID = false, $optionalValues = array(), $languageLocale = false )
  210. {
  211. $dateTime = time();
  212. if ( !$userID )
  213. $userID = eZUser::currentUserID();
  214. $nameList = new eZContentClassNameList();
  215. if ( isset( $optionalValues['serialized_name_list'] ) )
  216. $nameList->initFromSerializedList( $optionalValues['serialized_name_list'] );
  217. else if ( isset( $optionalValues['name'] ) )
  218. $nameList->initFromString( $optionalValues['name'], $languageLocale );
  219. else
  220. $nameList->initFromString( '', $languageLocale );
  221. $descriptionList = new eZSerializedObjectNameList();
  222. if ( isset( $optionalValues['serialized_description_list'] ) )
  223. $descriptionList->initFromSerializedList( $optionalValues['serialized_description_list'] );
  224. else if ( isset( $optionalValues['description'] ) )
  225. $descriptionList->initFromString( $optionalValues['description'], $languageLocale );
  226. else
  227. $descriptionList->initFromString( '', $languageLocale );
  228. $languageMask = $nameList->languageMask();
  229. $initialLanguageID = $nameList->alwaysAvailableLanguageID();
  230. $contentClassDefinition = eZContentClass::definition();
  231. $row = array(
  232. "id" => null,
  233. "version" => 1,
  234. "serialized_name_list" => $nameList->serializeNames(),
  235. 'serialized_description_list' => $descriptionList->serializeNames(),
  236. "identifier" => "",
  237. "contentobject_name" => "",
  238. "creator_id" => $userID,
  239. "modifier_id" => $userID,
  240. "created" => $dateTime,
  241. 'remote_id' => eZRemoteIdUtility::generate( 'class' ),
  242. "modified" => $dateTime,
  243. "is_container" => $contentClassDefinition[ 'fields' ][ 'is_container' ][ 'default' ],
  244. "always_available" => $contentClassDefinition[ 'fields' ][ 'always_available' ][ 'default' ],
  245. 'language_mask' => $languageMask,
  246. 'initial_language_id' => $initialLanguageID,
  247. "sort_field" => $contentClassDefinition[ 'fields' ][ 'sort_field' ][ 'default' ],
  248. "sort_order" => $contentClassDefinition[ 'fields' ][ 'sort_order' ][ 'default' ] );
  249. $row = array_merge( $row, $optionalValues );
  250. $contentClass = new eZContentClass( $row );
  251. // setting 'dirtyData' to make sure the 'NameList' will be stored into db.
  252. $contentClass->NameList->setHasDirtyData( true );
  253. return $contentClass;
  254. }
  255. function instantiateIn( $lang, $userID = false, $sectionID = 1, $versionNumber = false, $versionStatus = eZContentObjectVersion::STATUS_INTERNAL_DRAFT )
  256. {
  257. return eZContentClass::instantiate( $userID, $sectionID, $versionNumber, $lang, $versionStatus );
  258. }
  259. /*!
  260. Creates a new content object instance and stores it.
  261. \param userID user ID (optional), current user if not set (also store object id in session if $userID = false)
  262. \param sectionID section ID (optional), 1 if not set (Standard section)
  263. \param versionNumber version number, create initial version if not set
  264. \note Transaction unsafe. If you call several transaction unsafe methods you must enclose
  265. the calls within a db transaction; thus within db->begin and db->commit.
  266. */
  267. function instantiate( $userID = false, $sectionID = 1, $versionNumber = false, $languageCode = false, $versionStatus = eZContentObjectVersion::STATUS_INTERNAL_DRAFT )
  268. {
  269. $attributes = $this->fetchAttributes();
  270. if ( $userID === false )
  271. {
  272. $user = eZUser::currentUser();
  273. $userID = $user->attribute( 'contentobject_id' );
  274. }
  275. if ( $languageCode == false )
  276. {
  277. $languageCode = eZContentObject::defaultLanguage();
  278. }
  279. $object = eZContentObject::create( ezpI18n::tr( "kernel/contentclass", "New %1", null, array( $this->name( $languageCode ) ) ),
  280. $this->attribute( "id" ),
  281. $userID,
  282. $sectionID,
  283. 1,
  284. $languageCode );
  285. if ( $this->attribute( 'always_available' ) )
  286. {
  287. $object->setAttribute( 'language_mask', (int)$object->attribute( 'language_mask') | 1 );
  288. }
  289. $db = eZDB::instance();
  290. $db->begin();
  291. $object->store();
  292. $object->assignDefaultStates();
  293. $object->setName( ezpI18n::tr( "kernel/contentclass", "New %1", null, array( $this->name( $languageCode ) ) ), false, $languageCode );
  294. if ( !$versionNumber )
  295. {
  296. $version = $object->createInitialVersion( $userID, $languageCode );
  297. }
  298. else
  299. {
  300. $version = eZContentObjectVersion::create( $object->attribute( "id" ), $userID, $versionNumber, $languageCode );
  301. }
  302. if ( $versionStatus !== false )
  303. {
  304. $version->setAttribute( 'status', $versionStatus );
  305. }
  306. $version->store();
  307. foreach ( $attributes as $attribute )
  308. {
  309. $attribute->instantiate( $object->attribute( 'id' ), $languageCode );
  310. }
  311. if ( isset( $user ) && $user instanceof eZUser && $user->isAnonymous() )
  312. {
  313. $createdObjectIDList = eZPreferences::value( 'ObjectCreationIDList' );
  314. if ( !$createdObjectIDList )
  315. {
  316. $createdObjectIDList = array( $object->attribute( 'id' ) );
  317. }
  318. else
  319. {
  320. $createdObjectIDList = unserialize( $createdObjectIDList );
  321. $createdObjectIDList[] = $object->attribute( 'id' );
  322. }
  323. eZPreferences::setValue( 'ObjectCreationIDList', serialize( $createdObjectIDList ) );
  324. }
  325. $db->commit();
  326. return $object;
  327. }
  328. function canInstantiateClasses()
  329. {
  330. $accessResult = eZUser::currentUser()->hasAccessTo( 'content' , 'create' );
  331. $canInstantiateClasses = 1;
  332. if ( $accessResult['accessWord'] == 'no' )
  333. {
  334. $canInstantiateClasses = 0;
  335. }
  336. return $canInstantiateClasses;
  337. }
  338. // code-template::create-block: can-instantiate-class-list, group-filter, role-caching, class-policy-list, name-instantiate, object-creation, class-sql-creation, static-method
  339. // code-template::auto-generated:START can-instantiate-class-list
  340. // This code is automatically generated from templates/classcreatelist.ctpl
  341. // DO NOT EDIT THIS CODE DIRECTLY, CHANGE THE TEMPLATE FILE INSTEAD
  342. /*!
  343. \static
  344. Finds all classes that the current user can create objects from and returns.
  345. It is also possible to filter the list event more with \a $includeFilter and \a $groupList.
  346. \param $asObject If \c true then it return eZContentClass objects, if not it will
  347. be an associative array with \c name and \c id keys.
  348. \param $includeFilter If \c true then it will include only from class groups defined in
  349. \a $groupList, if not it will exclude those groups.
  350. \param $groupList An array with class group IDs that should be used in filtering, use
  351. \c false if you do not wish to filter at all.
  352. \param $fetchID A unique name for the current fetch, this must be supplied when filtering is
  353. used if you want caching to work.
  354. */
  355. static function canInstantiateClassList( $asObject = false, $includeFilter = true, $groupList = false, $fetchID = false )
  356. {
  357. $ini = eZINI::instance();
  358. $groupArray = array();
  359. $enableCaching = ( $ini->variable( 'RoleSettings', 'EnableCaching' ) == 'true' );
  360. if ( is_array( $groupList ) )
  361. {
  362. if ( $fetchID == false )
  363. $enableCaching = false;
  364. }
  365. if ( $enableCaching )
  366. {
  367. $http = eZHTTPTool::instance();
  368. eZExpiryHandler::registerShutdownFunction();
  369. $handler = eZExpiryHandler::instance();
  370. $expiredTimeStamp = 0;
  371. if ( $handler->hasTimestamp( 'user-class-cache' ) )
  372. $expiredTimeStamp = $handler->timestamp( 'user-class-cache' );
  373. $classesCachedForUser = $http->sessionVariable( 'ClassesCachedForUser' );
  374. $classesCachedTimestamp = $http->sessionVariable( 'ClassesCachedTimestamp' );
  375. $cacheVar = 'CanInstantiateClassList';
  376. if ( is_array( $groupList ) and $fetchID !== false )
  377. {
  378. $cacheVar = 'CanInstantiateClassListGroup';
  379. }
  380. $user = eZUser::currentUser();
  381. $userID = $user->id();
  382. if ( ( $classesCachedTimestamp >= $expiredTimeStamp ) && $classesCachedForUser == $userID )
  383. {
  384. if ( $http->hasSessionVariable( $cacheVar ) )
  385. {
  386. if ( $fetchID !== false )
  387. {
  388. // Check if the group contains our ID, if not we need to fetch from DB
  389. $groupArray = $http->sessionVariable( $cacheVar );
  390. if ( isset( $groupArray[$fetchID] ) )
  391. {
  392. return $groupArray[$fetchID];
  393. }
  394. }
  395. else
  396. {
  397. return $http->sessionVariable( $cacheVar );
  398. }
  399. }
  400. }
  401. else
  402. {
  403. $http->setSessionVariable( 'ClassesCachedForUser' , $userID );
  404. $http->setSessionVariable( 'ClassesCachedTimestamp', time() );
  405. }
  406. }
  407. $languageCodeList = eZContentLanguage::fetchLocaleList();
  408. $allowedLanguages = array( '*' => array() );
  409. $user = eZUser::currentUser();
  410. $accessResult = $user->hasAccessTo( 'content' , 'create' );
  411. $accessWord = $accessResult['accessWord'];
  412. $classIDArray = array();
  413. $classList = array();
  414. $fetchAll = false;
  415. if ( $accessWord == 'yes' )
  416. {
  417. $fetchAll = true;
  418. $allowedLanguages['*'] = $languageCodeList;
  419. }
  420. else if ( $accessWord == 'no' )
  421. {
  422. // Cannot create any objects, return empty list.
  423. return $classList;
  424. }
  425. else
  426. {
  427. $policies = $accessResult['policies'];
  428. foreach ( $policies as $policyKey => $policy )
  429. {
  430. $classIDArrayPart = '*';
  431. if ( isset( $policy['Class'] ) )
  432. {
  433. $classIDArrayPart = $policy['Class'];
  434. }
  435. $languageCodeArrayPart = $languageCodeList;
  436. if ( isset( $policy['Language'] ) )
  437. {
  438. $languageCodeArrayPart = array_intersect( $policy['Language'], $languageCodeList );
  439. }
  440. if ( $classIDArrayPart == '*' )
  441. {
  442. $fetchAll = true;
  443. $allowedLanguages['*'] = array_unique( array_merge( $allowedLanguages['*'], $languageCodeArrayPart ) );
  444. }
  445. else
  446. {
  447. foreach( $classIDArrayPart as $class )
  448. {
  449. if ( isset( $allowedLanguages[$class] ) )
  450. {
  451. $allowedLanguages[$class] = array_unique( array_merge( $allowedLanguages[$class], $languageCodeArrayPart ) );
  452. }
  453. else
  454. {
  455. $allowedLanguages[$class] = $languageCodeArrayPart;
  456. }
  457. }
  458. $classIDArray = array_merge( $classIDArray, array_diff( $classIDArrayPart, $classIDArray ) );
  459. }
  460. }
  461. }
  462. $db = eZDB::instance();
  463. $filterTableSQL = '';
  464. $filterSQL = '';
  465. // Create extra SQL statements for the class group filters.
  466. if ( is_array( $groupList ) )
  467. {
  468. if ( count( $groupList ) == 0 )
  469. {
  470. return $classList;
  471. }
  472. $filterTableSQL = ', ezcontentclass_classgroup ccg';
  473. $filterSQL = ( " AND" .
  474. " cc.id = ccg.contentclass_id AND" .
  475. " " );
  476. $filterSQL .= $db->generateSQLINStatement( $groupList, 'ccg.group_id', !$includeFilter, true, 'int' );
  477. }
  478. $classNameFilter = eZContentClassName::sqlFilter( 'cc' );
  479. $filterSQL .= " AND cc.id=" . $classNameFilter['from'] . ".contentclass_id";
  480. if ( $fetchAll )
  481. {
  482. // If $asObject is true we fetch all fields in class
  483. $fields = $asObject ? "cc.*, $classNameFilter[nameField]" : "cc.id, $classNameFilter[nameField]";
  484. $rows = $db->arrayQuery( "SELECT DISTINCT $fields " .
  485. "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from] " .
  486. "WHERE cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . " $filterSQL " .
  487. "ORDER BY $classNameFilter[nameField] ASC" );
  488. $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject );
  489. }
  490. else
  491. {
  492. // If the constrained class list is empty we are not allowed to create any class
  493. if ( count( $classIDArray ) == 0 )
  494. {
  495. return $classList;
  496. }
  497. $classIDCondition = $db->generateSQLINStatement( $classIDArray, 'cc.id' );
  498. // If $asObject is true we fetch all fields in class
  499. $fields = $asObject ? "cc.*, $classNameFilter[nameField]" : "cc.id, $classNameFilter[nameField]";
  500. $rows = $db->arrayQuery( "SELECT DISTINCT $fields " .
  501. "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from] " .
  502. "WHERE $classIDCondition AND" .
  503. " cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . " $filterSQL " .
  504. "ORDER BY $classNameFilter[nameField] ASC" );
  505. $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject );
  506. }
  507. if ( $asObject )
  508. {
  509. foreach ( $classList as $key => $class )
  510. {
  511. $id = $class->attribute( 'id' );
  512. if ( isset( $allowedLanguages[$id] ) )
  513. {
  514. $languageCodes = array_unique( array_merge( $allowedLanguages['*'], $allowedLanguages[$id] ) );
  515. }
  516. else
  517. {
  518. $languageCodes = $allowedLanguages['*'];
  519. }
  520. $classList[$key]->setCanInstantiateLanguages( $languageCodes );
  521. }
  522. }
  523. eZDebugSetting::writeDebug( 'kernel-content-class', $classList, "class list fetched from db" );
  524. if ( $enableCaching )
  525. {
  526. if ( $fetchID !== false )
  527. {
  528. $groupArray[$fetchID] = $classList;
  529. $http->setSessionVariable( $cacheVar, $groupArray );
  530. }
  531. else
  532. {
  533. $http->setSessionVariable( $cacheVar, $classList );
  534. }
  535. }
  536. return $classList;
  537. }
  538. // This code is automatically generated from templates/classcreatelist.ctpl
  539. // code-template::auto-generated:END can-instantiate-class-list
  540. /*!
  541. \return The creator of the class as an eZUser object by using the $CreatorID as user ID.
  542. */
  543. function creator()
  544. {
  545. if ( isset( $this->CreatorID ) and $this->CreatorID )
  546. {
  547. return eZUser::fetch( $this->CreatorID );
  548. }
  549. return null;
  550. }
  551. /*!
  552. \return The modifier of the class as an eZUser object by using the $ModifierID as user ID.
  553. */
  554. function modifier()
  555. {
  556. if ( isset( $this->ModifierID ) and $this->ModifierID )
  557. {
  558. return eZUser::fetch( $this->ModifierID );
  559. }
  560. return null;
  561. }
  562. /*!
  563. Find all groups the current class is placed in and returns a list of group objects.
  564. \return An array with eZContentClassGroup objects.
  565. \sa fetchGroupIDList()
  566. */
  567. function fetchGroupList()
  568. {
  569. $this->InGroups = eZContentClassClassGroup::fetchGroupList( $this->attribute( "id" ),
  570. $this->attribute( "version" ),
  571. true );
  572. return $this->InGroups;
  573. }
  574. /*!
  575. Find all groups the current class is placed in and returns a list of group IDs.
  576. \return An array with integers (ids).
  577. \sa fetchGroupList()
  578. */
  579. function fetchGroupIDList()
  580. {
  581. $list = eZContentClassClassGroup::fetchGroupList( $this->attribute( "id" ),
  582. $this->attribute( "version" ),
  583. false );
  584. $this->InGroupIDs = array();
  585. foreach ( $list as $item )
  586. {
  587. $this->InGroupIDs[] = $item['group_id'];
  588. }
  589. return $this->InGroupIDs;
  590. }
  591. /*!
  592. Returns the result from fetchGroupIDList() if class group overrides is
  593. enabled in content.ini.
  594. \return An array with eZContentClassGroup objects or \c false if disabled.
  595. \note \c EnableClassGroupOverride in group \c ContentOverrideSettings from INI file content.ini
  596. controls this behaviour.
  597. */
  598. function fetchMatchGroupIDList()
  599. {
  600. $contentINI = eZINI::instance( 'content.ini' );
  601. if( $contentINI->variable( 'ContentOverrideSettings', 'EnableClassGroupOverride' ) == 'true' )
  602. {
  603. return $this->attribute( 'ingroup_id_list' );
  604. }
  605. return false;
  606. }
  607. /*!
  608. Finds all Classes in the system and returns them.
  609. \return An array with eZContentClass objects.
  610. */
  611. static function fetchAllClasses( $asObject = true, $includeFilter = true, $groupList = false )
  612. {
  613. $filterTableSQL = '';
  614. $filterSQL = '';
  615. if ( is_array( $groupList ) )
  616. {
  617. $filterTableSQL = ', ezcontentclass_classgroup ccg';
  618. $filterSQL = ( " AND" .
  619. " cc.id = ccg.contentclass_id AND" .
  620. " ccg.group_id " );
  621. $groupText = implode( ', ', $groupList );
  622. if ( $includeFilter )
  623. $filterSQL .= "IN ( $groupText )";
  624. else
  625. $filterSQL .= "NOT IN ( $groupText )";
  626. }
  627. $classNameFilter = eZContentClassName::sqlFilter( 'cc' );
  628. $classList = array();
  629. $db = eZDb::instance();
  630. // If $asObject is true we fetch all fields in class
  631. $fields = $asObject ? "cc.*" : "cc.id, $classNameFilter[nameField]";
  632. $rows = $db->arrayQuery( "SELECT DISTINCT $fields " .
  633. "FROM ezcontentclass cc$filterTableSQL, $classNameFilter[from] " .
  634. "WHERE cc.version = " . eZContentClass::VERSION_STATUS_DEFINED . "$filterSQL AND $classNameFilter[where]" .
  635. "ORDER BY $classNameFilter[nameField] ASC" );
  636. $classList = eZPersistentObject::handleRows( $rows, 'eZContentClass', $asObject );
  637. return $classList;
  638. }
  639. /*!
  640. Finds all Class groups in the system and returns them.
  641. \return An array with eZContentClassGroup objects.
  642. \sa fetchGroupList(), fetchGroupIDList()
  643. */
  644. function fetchAllGroups()
  645. {
  646. $this->AllGroups = eZContentClassGroup::fetchList();
  647. return $this->AllGroups;
  648. }
  649. /*!
  650. \return true if the class is part of the group \a $groupID
  651. */
  652. function inGroup( $groupID )
  653. {
  654. return eZContentClassClassGroup::classInGroup( $this->attribute( 'id' ),
  655. $this->attribute( 'version' ),
  656. $groupID );
  657. }
  658. /*!
  659. \static
  660. Will remove all temporary classes from the database.
  661. */
  662. static function removeTemporary()
  663. {
  664. $version = eZContentClass::VERSION_STATUS_TEMPORARY;
  665. $temporaryClasses = eZContentClass::fetchList( $version, true );
  666. $db = eZDB::instance();
  667. $db->begin();
  668. foreach ( $temporaryClasses as $class )
  669. {
  670. $class->remove( true, $version );
  671. }
  672. eZPersistentObject::removeObject( eZContentClassAttribute::definition(),
  673. array( 'version' => $version ) );
  674. $db->commit();
  675. }
  676. /*!
  677. Get remote id of content node
  678. */
  679. function remoteID()
  680. {
  681. $remoteID = eZPersistentObject::attribute( 'remote_id', true );
  682. if ( !$remoteID &&
  683. $this->Version == eZContentClass::VERSION_STATUS_DEFINED )
  684. {
  685. $this->setAttribute( 'remote_id', eZRemoteIdUtility::generate( 'class' ) );
  686. $this->sync( array( 'remote_id' ) );
  687. $remoteID = eZPersistentObject::attribute( 'remote_id', true );
  688. }
  689. return $remoteID;
  690. }
  691. /*!
  692. \note If you want to remove a class with all data associated with it (objects/classMembers)
  693. you should use eZContentClassOperations::remove()
  694. */
  695. function remove( $removeAttributes = false, $version = eZContentClass::VERSION_STATUS_DEFINED )
  696. {
  697. // If we are not allowed to remove just return false
  698. if ( $this->Version == eZContentClass::VERSION_STATUS_DEFINED && !$this->isRemovable() )
  699. return false;
  700. if ( is_array( $removeAttributes ) or $removeAttributes )
  701. $this->removeAttributes( $removeAttributes );
  702. $this->NameList->remove( $this );
  703. eZPersistentObject::remove();
  704. }
  705. /*!
  706. Checks if the class can be removed and returns \c true if it can, \c false otherwise.
  707. \sa removableInformation()
  708. */
  709. function isRemovable()
  710. {
  711. $info = $this->removableInformation( false );
  712. return count( $info['list'] ) == 0;
  713. }
  714. /*!
  715. Returns information on why the class cannot be removed,
  716. it does the same checks as in isRemovable() but generates
  717. some text in the return array.
  718. \return An array which contains:
  719. - text - Plain text description why this cannot be removed
  720. - list - An array with reasons why this failed, each entry contains:
  721. - text - Plain text description of the reason.
  722. - list - A sublist of reason (e.g from an attribute), is optional.
  723. \param $includeAll Controls whether the returned information will contain all
  724. sources for not being to remove or just the first that it finds.
  725. */
  726. function removableInformation( $includeAll = true )
  727. {
  728. $result = array( 'text' => ezpI18n::tr( 'kernel/contentclass', "Cannot remove class '%class_name':",
  729. null, array( '%class_name' => $this->attribute( 'name' ) ) ),
  730. 'list' => array() );
  731. $db = eZDB::instance();
  732. // Check top-level nodes
  733. $rows = $db->arrayQuery( "SELECT ezcot.node_id
  734. FROM ezcontentobject_tree ezcot, ezcontentobject ezco
  735. WHERE ezcot.depth = 1 AND
  736. ezco.contentclass_id = $this->ID AND
  737. ezco.id=ezcot.contentobject_id" );
  738. if ( count( $rows ) > 0 )
  739. {
  740. $result['list'][] = array( 'text' => ezpI18n::tr( 'kernel/contentclass', 'The class is used by a top-level node and cannot be removed.
  741. You will need to change the class of the node by using the swap functionality.' ) );
  742. if ( !$includeAll )
  743. return $result;
  744. }
  745. // Check class attributes
  746. foreach ( $this->fetchAttributes() as $attribute )
  747. {
  748. $dataType = $attribute->dataType();
  749. if ( !$dataType->isClassAttributeRemovable( $attribute ) )
  750. {
  751. $info = $dataType->classAttributeRemovableInformation( $attribute, $includeAll );
  752. $result['list'][] = $info;
  753. if ( !$includeAll )
  754. return $result;
  755. }
  756. }
  757. return $result;
  758. }
  759. /*!
  760. \note Removes class attributes
  761. \param removeAttributes Array of attributes to remove
  762. \param version Version to remove( optional )
  763. */
  764. function removeAttributes( $removeAttributes = false, $version = false )
  765. {
  766. if ( is_array( $removeAttributes ) )
  767. {
  768. $db = eZDB::instance();
  769. $db->begin();
  770. foreach( $removeAttributes as $attribute )
  771. {
  772. $attribute->removeThis();
  773. }
  774. $db->commit();
  775. }
  776. else
  777. {
  778. $contentClassID = $this->ID;
  779. if ( $version === false )
  780. {
  781. $version = $this->Version;
  782. }
  783. $classAttributes = $this->fetchAttributes( );
  784. $db = eZDB::instance();
  785. $db->begin();
  786. foreach ( $classAttributes as $classAttribute )
  787. {
  788. $dataType = $classAttribute->dataType();
  789. $dataType->deleteStoredClassAttribute( $classAttribute, $version );
  790. }
  791. eZPersistentObject::removeObject( eZContentClassAttribute::definition(),
  792. array( 'contentclass_id' => $contentClassID,
  793. 'version' => $version ) );
  794. $db->commit();
  795. }
  796. }
  797. function compareAttributes( $attr1, $attr2 )
  798. {
  799. return ( $attr1->attribute( "placement" ) > $attr2->attribute( "placement" ) ) ? 1 : -1;
  800. }
  801. function adjustAttributePlacements( $attributes )
  802. {
  803. if ( !is_array( $attributes ) )
  804. return;
  805. usort( $attributes, array( $this, "compareAttributes" ) );
  806. $i = 0;
  807. foreach( $attributes as $attribute )
  808. {
  809. $attribute->setAttribute( "placement", ++$i );
  810. }
  811. }
  812. function store( $store_childs = false, $fieldFilters = null )
  813. {
  814. self::expireCache();
  815. $db = eZDB::instance();
  816. $db->begin();
  817. if ( is_array( $store_childs ) ||
  818. $store_childs )
  819. {
  820. if ( is_array( $store_childs ) )
  821. {
  822. $attributes = $store_childs;
  823. }
  824. else
  825. {
  826. $attributes = $this->fetchAttributes();
  827. }
  828. foreach( $attributes as $attribute )
  829. {
  830. if ( is_object ( $attribute ) )
  831. $attribute->store();
  832. }
  833. }
  834. eZExpiryHandler::registerShutdownFunction();
  835. $handler = eZExpiryHandler::instance();
  836. $handler->setTimestamp( 'user-class-cache', time() );
  837. $handler->store();
  838. $this->setAttribute( 'serialized_name_list', $this->NameList->serializeNames() );
  839. $this->setAttribute( 'serialized_description_list', $this->DescriptionList->serializeNames() );
  840. eZPersistentObject::store( $fieldFilters );
  841. $this->NameList->store( $this );
  842. $db->commit();
  843. }
  844. function sync( $fieldFilters = null )
  845. {
  846. if ( $this->hasDirtyData() )
  847. $this->store( false, $fieldFilters );
  848. }
  849. /*!
  850. Initializes this class as a copy of \a $originalClass by
  851. creating new a new name and identifier.
  852. It will check if there are other classes already with this name
  853. in which case it will append a unique number to the name and identifier.
  854. */
  855. function initializeCopy( &$originalClass )
  856. {
  857. $name = ezpI18n::tr( 'kernel/class', 'Copy of %class_name', null,
  858. array( '%class_name' => $originalClass->attribute( 'name' ) ) );
  859. $identifier = 'copy_of_' . $originalClass->attribute( 'identifier' );
  860. $db = eZDB::instance();
  861. $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 ) . "%'";
  862. $rows = $db->arrayQuery( $sql );
  863. $count = $rows[0]['count'];
  864. if ( $count > 0 )
  865. {
  866. ++$count;
  867. $name .= $count;
  868. $identifier .= $count;
  869. }
  870. $this->setName( $name );
  871. $this->setAttribute( 'identifier', $identifier );
  872. $this->setAttribute( 'created', time() );
  873. $user = eZUser::currentUser();
  874. $userID = $user->attribute( "contentobject_id" );
  875. $this->setAttribute( 'creator_id', $userID );
  876. }
  877. /**
  878. * Stores the current class as a defined version, updates the contentobject_name
  879. * attribute and recreates the class group entries.
  880. *
  881. * @note It will remove any existing temporary or defined classes before storing.
  882. *
  883. * @param array $attributes array of attributes of the content class
  884. */
  885. public function storeDefined( $attributes )
  886. {
  887. $this->storeVersioned( $attributes, self::VERSION_STATUS_DEFINED );
  888. }
  889. /**
  890. * Stores the current class as a modified version, updates the contentobject_name
  891. * attribute and recreates the class group entries.
  892. *
  893. * @note It will remove classes in the previous and specified version before storing.
  894. *
  895. * @param array $attributes array of attributes
  896. * @param int $version version status
  897. * @since Version 4.3
  898. */
  899. public function storeVersioned( $attributes, $version )
  900. {
  901. $previousVersion = $this->attribute( 'version' );
  902. $db = eZDB::instance();
  903. $db->begin();
  904. $this->removeAttributes( false, $version );
  905. $this->removeAttributes( false, $previousVersion );
  906. $this->remove( false );
  907. $this->setVersion( $version, $attributes );
  908. $this->setAttribute( "modifier_id", eZUser::currentUser()->attribute( "contentobject_id" ) );
  909. $this->setAttribute( "modified", time() );
  910. $this->adjustAttributePlacements( $attributes );
  911. foreach( $attributes as $attribute )
  912. {
  913. $attribute->storeVersioned( $version );
  914. }
  915. // Set contentobject_name to something sensible if it is missing
  916. if ( count( $attributes ) > 0 && trim( $this->attribute( 'contentobject_name' ) ) == '' )
  917. {
  918. $this->setAttribute( 'contentobject_name', '<' . $attributes[0]->attribute( 'identifier' ) . '>' );
  919. }
  920. // Recreate class member entries
  921. eZContentClassClassGroup::removeClassMembers( $this->ID, $version );
  922. foreach( eZContentClassClassGroup::fetchGroupList( $this->ID, $previousVersion ) as $classgroup )
  923. {
  924. $classgroup->setAttribute( 'contentclass_version', $version );
  925. $classgroup->store();
  926. }
  927. eZContentClassClassGroup::removeClassMembers( $this->ID, $previousVersion );
  928. eZExpiryHandler::registerShutdownFunction();
  929. $handler = eZExpiryHandler::instance();
  930. $time = time();
  931. $handler->setTimestamp( 'user-class-cache', $time );
  932. $handler->setTimestamp( 'class-identifier-cache', $time );
  933. $handler->setTimestamp( 'sort-key-cache', $time );
  934. $handler->store();
  935. eZContentCacheManager::clearAllContentCache();
  936. $this->setAttribute( 'serialized_name_list', $this->NameList->serializeNames() );
  937. $this->setAttribute( 'serialized_description_list', $this->DescriptionList->serializeNames() );
  938. eZPersistentObject::store();
  939. $this->NameList->store( $this );
  940. $db->commit();
  941. }
  942. function setVersion( $version, $set_childs = false )
  943. {
  944. if ( is_array( $set_childs ) or $set_childs )
  945. {
  946. if ( is_array( $set_childs ) )
  947. {
  948. $attributes = $set_childs;
  949. }
  950. else
  951. {
  952. $attributes = $this->fetchAttributes();
  953. }
  954. foreach( $attributes as $attribute )
  955. {
  956. $attribute->setAttribute( "version", $version );
  957. }
  958. }
  959. if ( $this->Version != $version )
  960. $this->NameList->setHasDirtyData();
  961. $this->setAttribute( "version", $version );
  962. }
  963. static function exists( $id, $version = eZContentClass::VERSION_STATUS_DEFINED, $userID = false, $useIdentifier = false )
  964. {
  965. $conds = array( "version" => $version );
  966. if ( $useIdentifier )
  967. $conds["identifier"] = $id;
  968. else
  969. $conds["id"] = $id;
  970. if ( $userID !== false and is_numeric( $userID ) )
  971. $conds["creator_id"] = $userID;
  972. $version_sort = "desc";
  973. if ( $version == eZContentClass::VERSION_STATUS_DEFINED )
  974. $conds['version'] = $version;
  975. $rows = eZPersistentObject::fetchObjectList( eZContentClass::definition(),
  976. null,
  977. $conds,
  978. null,
  979. array( "offset" => 0,
  980. "length" => 1 ),
  981. false );
  982. if ( count( $rows ) > 0 )
  983. return $rows[0]['id'];
  984. return false;
  985. }
  986. static function fetch( $id, $asObject = true, $version = eZContentClass::VERSION_STATUS_DEFINED, $user_id = false ,$parent_id = null )
  987. {
  988. global $eZContentClassObjectCache;
  989. // If the object given by its id is not cached or should be returned as array
  990. // then we fetch it from the DB (objects are always cached as arrays).
  991. if ( !isset( $eZContentClassObjectCache[$id] ) or $asObject === false or $version != eZContentClass::VERSION_STATUS_DEFINED )
  992. {
  993. $conds = array( "id" => $id,
  994. "version" => $version );
  995. if ( $user_id !== false and is_numeric( $user_id ) )
  996. $conds["creator_id"] = $user_id;
  997. $version_sort = "desc";
  998. if ( $version == eZContentClass::VERSION_STATUS_DEFINED )
  999. $version_sort = "asc";
  1000. $rows = eZPersistentObject::fetchObjectList( eZContentClass::definition(),
  1001. null,
  1002. $conds,
  1003. array( "version" => $version_sort ),
  1004. array( "offset" => 0,
  1005. "length" => 2 ),
  1006. false );
  1007. if ( count( $rows ) == 0 )
  1008. {
  1009. $contentClass = null;
  1010. return $contentClass;
  1011. }
  1012. $row = $rows[0];
  1013. $row["version_count"] = count( $rows );
  1014. if ( $asObject )
  1015. {
  1016. $contentClass = new eZContentClass( $row );
  1017. if ( $version == eZContentClass::VERSION_STATUS_DEFINED )
  1018. {
  1019. $eZContentClassObjectCache[$id] = $contentClass;
  1020. }
  1021. return $contentClass;
  1022. }
  1023. else
  1024. $contentClass = $row;
  1025. }
  1026. else
  1027. {
  1028. $contentClass = $eZContentClassObjectCache[$id];
  1029. }
  1030. return $contentClass;
  1031. }
  1032. static function fetchByRemoteID( $remoteID, $asObject = true, $version = eZContentClass::VERSION_STATUS_DEFINED, $user_id = false ,$parent_id = null )
  1033. {
  1034. $conds = array( "remote_id" => $remoteID,

Large files files are truncated, but you can click here to view the full file