PageRenderTime 57ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 1ms

/kernel/classes/ezcontentobject.php

http://github.com/ezsystems/ezpublish
PHP | 6749 lines | 4665 code | 620 blank | 1464 comment | 641 complexity | ba99b8ac2d292de877c0dd752e7090bc MD5 | raw file
Possible License(s): GPL-2.0, LGPL-2.1

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

  1. <?php
  2. /**
  3. * File containing the eZContentObject class.
  4. *
  5. * @copyright Copyright (C) eZ Systems AS. All rights reserved.
  6. * @license For full copyright and license information view LICENSE file distributed with this source code.
  7. * @version //autogentag//
  8. * @package kernel
  9. */
  10. /**
  11. * Encapsulates data about and methods to work with content objects
  12. *
  13. * @package kernel
  14. */
  15. class eZContentObject extends eZPersistentObject
  16. {
  17. const STATUS_DRAFT = 0;
  18. const STATUS_PUBLISHED = 1;
  19. const STATUS_ARCHIVED = 2;
  20. const PACKAGE_ERROR_NO_CLASS = 1;
  21. const PACKAGE_ERROR_EXISTS = 2;
  22. const PACKAGE_ERROR_NODE_EXISTS = 3;
  23. const PACKAGE_ERROR_MODIFIED = 101;
  24. const PACKAGE_ERROR_HAS_CHILDREN = 102;
  25. const PACKAGE_REPLACE = 1;
  26. const PACKAGE_SKIP = 2;
  27. const PACKAGE_NEW = 3;
  28. const PACKAGE_UPDATE = 6;
  29. const PACKAGE_DELETE = 4;
  30. const PACKAGE_KEEP = 5;
  31. const RELATION_COMMON = 1;
  32. const RELATION_EMBED = 2;
  33. const RELATION_LINK = 4;
  34. const RELATION_ATTRIBUTE = 8;
  35. /**
  36. * Initializes the object with $row.
  37. *
  38. * If $row is an integer, it will try to fetch it from the database using it as the unique ID.
  39. *
  40. * @param int|array $row
  41. */
  42. public function __construct( $row )
  43. {
  44. parent::__construct( $row );
  45. $this->ClassIdentifier = false;
  46. if ( isset( $row['contentclass_identifier'] ) )
  47. $this->ClassIdentifier = $row['contentclass_identifier'];
  48. if ( isset( $row['class_identifier'] ) )
  49. $this->ClassIdentifier = $row['class_identifier'];
  50. $this->ClassName = false;
  51. // Depending on how the information is retrieved, the "serialized_name_list" is sometimes available in "class_serialized_name_list" key
  52. if ( isset( $row['class_serialized_name_list'] ) )
  53. $row['serialized_name_list'] = $row['class_serialized_name_list'];
  54. // Depending on how the information is retrieved, the "contentclass_name" is sometimes available in "class_name" key
  55. if ( isset( $row['class_name'] ) )
  56. $row['contentclass_name'] = $row['class_name'];
  57. if ( isset( $row['contentclass_name'] ) )
  58. $this->ClassName = $row['contentclass_name'];
  59. if ( isset( $row['serialized_name_list'] ) )
  60. $this->ClassName = eZContentClass::nameFromSerializedString( $row['serialized_name_list'] );
  61. $this->CurrentLanguage = false;
  62. if ( isset( $row['content_translation'] ) )
  63. {
  64. $this->CurrentLanguage = $row['content_translation'];
  65. }
  66. else if ( isset( $row['real_translation'] ) )
  67. {
  68. $this->CurrentLanguage = $row['real_translation'];
  69. }
  70. else if ( isset( $row['language_mask'] ) )
  71. {
  72. $topPriorityLanguage = eZContentLanguage::topPriorityLanguageByMask( $row['language_mask'] );
  73. if ( $topPriorityLanguage )
  74. {
  75. $this->CurrentLanguage = $topPriorityLanguage->attribute( 'locale' );
  76. }
  77. }
  78. // Initialize the permission array cache
  79. $this->Permissions = array();
  80. }
  81. /**
  82. * @deprecated Use eZContentObject::__construct() instead
  83. * @param int|array $row
  84. */
  85. function eZContentObject( $row )
  86. {
  87. self::__construct( $row );
  88. }
  89. static function definition()
  90. {
  91. static $definition = array( "fields" => array( "id" => array( 'name' => 'ID',
  92. 'datatype' => 'integer',
  93. 'default' => 0,
  94. 'required' => true ),
  95. "section_id" => array( 'name' => "SectionID",
  96. 'datatype' => 'integer',
  97. 'default' => 0,
  98. 'required' => true,
  99. 'foreign_class' => 'eZSection',
  100. 'foreign_attribute' => 'id',
  101. 'multiplicity' => '1..*' ),
  102. "owner_id" => array( 'name' => "OwnerID",
  103. 'datatype' => 'integer',
  104. 'default' => 0,
  105. 'required' => true,
  106. 'foreign_class' => 'eZUser',
  107. 'foreign_attribute' => 'contentobject_id',
  108. 'multiplicity' => '1..*'),
  109. "contentclass_id" => array( 'name' => "ClassID",
  110. 'datatype' => 'integer',
  111. 'default' => 0,
  112. 'required' => true,
  113. 'foreign_class' => 'eZContentClass',
  114. 'foreign_attribute' => 'id',
  115. 'multiplicity' => '1..*' ),
  116. "name" => array( 'name' => "Name",
  117. 'datatype' => 'string',
  118. 'default' => '',
  119. 'required' => true ),
  120. "published" => array( 'name' => "Published",
  121. 'datatype' => 'integer',
  122. 'default' => 0,
  123. 'required' => true ),
  124. "modified" => array( 'name' => "Modified",
  125. 'datatype' => 'integer',
  126. 'default' => 0,
  127. 'required' => true ),
  128. "current_version" => array( 'name' => "CurrentVersion",
  129. 'datatype' => 'integer',
  130. 'default' => 0,
  131. 'required' => true ),
  132. "status" => array( 'name' => "Status",
  133. 'datatype' => 'integer',
  134. 'default' => 0,
  135. 'required' => true ),
  136. 'remote_id' => array( 'name' => "RemoteID",
  137. 'datatype' => 'string',
  138. 'default' => '',
  139. 'required' => true ),
  140. 'language_mask' => array( 'name' => 'LanguageMask',
  141. 'datatype' => 'integer',
  142. 'default' => 0,
  143. 'required' => true ),
  144. 'initial_language_id' => array( 'name' => 'InitialLanguageID',
  145. 'datatype' => 'integer',
  146. 'default' => 0,
  147. 'required' => true,
  148. 'foreign_class' => 'eZContentLanguage',
  149. 'foreign_attribute' => 'id',
  150. 'multiplicity' => '1..*' ) ),
  151. "keys" => array( "id" ),
  152. "function_attributes" => array( "current" => "currentVersion",
  153. "published_version" => "publishedVersion",
  154. 'versions' => 'versions',
  155. 'author_array' => 'authorArray',
  156. "class_name" => "className",
  157. "content_class" => "contentClass",
  158. "contentobject_attributes" => "contentObjectAttributes",
  159. "owner" => "owner",
  160. "related_contentobject_array" => "relatedContentObjectList",
  161. "related_contentobject_count" => "relatedContentObjectCount",
  162. 'reverse_related_contentobject_array' => 'reverseRelatedObjectList',
  163. 'reverse_related_contentobject_count' => 'reverseRelatedObjectCount',
  164. "linked_contentobject_array" => "linkedContentObjectList",
  165. "linked_contentobject_count" => "linkedContentObjectCount",
  166. 'reverse_linked_contentobject_array' => 'reverseLinkedObjectList',
  167. 'reverse_linked_contentobject_count' => 'reverseLinkedObjectCount',
  168. "embedded_contentobject_array" => "embeddedContentObjectList",
  169. "embedded_contentobject_count" => "embeddedContentObjectCount",
  170. 'reverse_embedded_contentobject_array' => 'reverseEmbeddedObjectList',
  171. 'reverse_embedded_contentobject_count' => 'reverseEmbeddedObjectCount',
  172. "can_read" => "canRead",
  173. "can_pdf" => "canPdf",
  174. "can_diff" => "canDiff",
  175. "can_create" => "canCreate",
  176. "can_create_class_list" => "canCreateClassList",
  177. "can_edit" => "canEdit",
  178. "can_translate" => "canTranslate",
  179. "can_remove" => "canRemove",
  180. "can_move" => "canMoveFrom",
  181. "can_move_from" => "canMoveFrom",
  182. 'can_view_embed' => 'canViewEmbed',
  183. "data_map" => "dataMap",
  184. "grouped_data_map" => "groupedDataMap",
  185. "main_parent_node_id" => "mainParentNodeID",
  186. "assigned_nodes" => "assignedNodes",
  187. "visible_nodes" => "visibleNodes",
  188. "has_visible_node" => "hasVisibleNode",
  189. "parent_nodes" => "parentNodeIDArray",
  190. "main_node_id" => "mainNodeID",
  191. "main_node" => "mainNode",
  192. "default_language" => "defaultLanguage",
  193. "content_action_list" => "contentActionList",
  194. "class_identifier" => "contentClassIdentifier",
  195. 'class_group_id_list' => 'contentClassGroupIDList',
  196. 'name' => 'name',
  197. 'match_ingroup_id_list' => 'matchIngroupIDList',
  198. 'remote_id' => 'remoteID',
  199. 'current_language' => 'currentLanguage',
  200. 'current_language_object' => 'currentLanguageObject',
  201. 'initial_language' => 'initialLanguage',
  202. 'initial_language_code' => 'initialLanguageCode',
  203. 'available_languages' => 'availableLanguages',
  204. 'language_codes' => 'availableLanguages',
  205. 'language_js_array' => 'availableLanguagesJsArray',
  206. 'languages' => 'languages',
  207. 'all_languages' => 'allLanguages',
  208. 'can_edit_languages' => 'canEditLanguages',
  209. 'can_create_languages' => 'canCreateLanguages',
  210. 'always_available' => 'isAlwaysAvailable',
  211. 'allowed_assign_section_list' => 'allowedAssignSectionList',
  212. 'allowed_assign_state_id_list' => 'allowedAssignStateIDList',
  213. 'allowed_assign_state_list' => 'allowedAssignStateList',
  214. 'state_id_array' => 'stateIDArray',
  215. 'state_identifier_array' => 'stateIdentifierArray',
  216. 'section_identifier' => 'sectionIdentifier' ),
  217. "increment_key" => "id",
  218. "class_name" => "eZContentObject",
  219. "sort" => array( "id" => "asc" ),
  220. "name" => "ezcontentobject" );
  221. return $definition;
  222. }
  223. /**
  224. * Get class groups this object's class belongs to if match for class groups is enabled, otherwise false
  225. *
  226. * @return array|bool
  227. */
  228. function matchIngroupIDList()
  229. {
  230. $contentINI = eZINI::instance( 'content.ini' );
  231. $inList = false;
  232. if( $contentINI->variable( 'ContentOverrideSettings', 'EnableClassGroupOverride' ) == 'true' )
  233. {
  234. $contentClass = $this->contentClass();
  235. $inList = $contentClass->attribute( 'ingroup_id_list' );
  236. }
  237. return $inList;
  238. }
  239. /**
  240. * Stores the object
  241. *
  242. * Transaction unsafe. If you call several transaction unsafe methods you must enclose
  243. * the calls within a db transaction; thus within db->begin and db->commit.
  244. *
  245. * @param array $fieldFilters
  246. */
  247. function store( $fieldFilters = null )
  248. {
  249. // Unset the cache
  250. global $eZContentObjectContentObjectCache;
  251. unset( $eZContentObjectContentObjectCache[$this->ID] );
  252. global $eZContentObjectDataMapCache;
  253. unset( $eZContentObjectDataMapCache[$this->ID] );
  254. global $eZContentObjectVersionCache;
  255. unset( $eZContentObjectVersionCache[$this->ID] );
  256. $db = eZDB::instance();
  257. $db->begin();
  258. $this->storeNodeModified();
  259. parent::store( $fieldFilters );
  260. $db->commit();
  261. }
  262. /**
  263. * Clear in-memory caches.
  264. *
  265. * If $idArray is ommitted, the caches are cleared for all objects.
  266. *
  267. * @param array $idArray Objects to clear caches for.
  268. */
  269. static function clearCache( $idArray = array() )
  270. {
  271. if ( is_numeric( $idArray ) )
  272. $idArray = array( $idArray );
  273. // clear in-memory cache for all objects
  274. if ( count( $idArray ) == 0 )
  275. {
  276. unset( $GLOBALS['eZContentObjectContentObjectCache'] );
  277. unset( $GLOBALS['eZContentObjectDataMapCache'] );
  278. unset( $GLOBALS['eZContentObjectVersionCache'] );
  279. return;
  280. }
  281. // clear in-memory cache for specified object(s)
  282. global $eZContentObjectContentObjectCache;
  283. global $eZContentObjectDataMapCache;
  284. global $eZContentObjectVersionCache;
  285. foreach ( $idArray as $objectID )
  286. {
  287. unset( $eZContentObjectContentObjectCache[$objectID] );
  288. unset( $eZContentObjectDataMapCache[$objectID] );
  289. unset( $eZContentObjectVersionCache[$objectID] );
  290. }
  291. }
  292. /**
  293. * Update all nodes to set modified_subnode value
  294. *
  295. * Transaction unsafe. If you call several transaction unsafe methods you must enclose
  296. * the calls within a db transaction; thus within db->begin and db->commit.
  297. */
  298. function storeNodeModified()
  299. {
  300. if ( is_numeric( $this->ID ) )
  301. {
  302. $nodeArray = $this->assignedNodes();
  303. $db = eZDB::instance();
  304. $db->begin();
  305. foreach ( array_keys( $nodeArray ) as $key )
  306. {
  307. $nodeArray[$key]->updateAndStoreModified();
  308. }
  309. $db->commit();
  310. }
  311. }
  312. /**
  313. * Returns an object's name for the version given by $version in the language given by $lang
  314. *
  315. * @param int|bool $version If omitted, the current version will be used
  316. * @param bool $lang If omitted, the initial object language will be used
  317. * @return bool|string
  318. */
  319. function name( $version = false , $lang = false )
  320. {
  321. // if the object id is null, we can't read data from the database
  322. // and return the locally known name
  323. if ( $this->attribute( 'id' ) === null )
  324. {
  325. return $this->Name;
  326. }
  327. if ( !$version )
  328. {
  329. $version = $this->attribute( 'current_version' );
  330. }
  331. if ( !$lang && $this->CurrentLanguage )
  332. {
  333. $lang = $this->CurrentLanguage;
  334. }
  335. return $this->versionLanguageName( $version, $lang );
  336. }
  337. /**
  338. * Returns all translations of the current object's name
  339. *
  340. * @return string[]
  341. */
  342. function names()
  343. {
  344. $version = $this->attribute( 'current_version' );
  345. $id = $this->attribute( 'id' );
  346. $db = eZDB::instance();
  347. $rows = $db->arrayQuery( "SELECT name, real_translation FROM ezcontentobject_name WHERE contentobject_id = '$id' AND content_version='$version'" );
  348. $names = array();
  349. foreach ( $rows as $row )
  350. {
  351. $names[$row['real_translation']] = $row['name'];
  352. }
  353. return $names;
  354. }
  355. /**
  356. * Returns the object name for version $version in the language $lang
  357. *
  358. * @param int $version
  359. * @param string|bool $lang If omitted, the initial language of the object is used
  360. * @return string|bool
  361. */
  362. function versionLanguageName( $version, $lang = false )
  363. {
  364. $name = false;
  365. if ( !$version > 0 )
  366. {
  367. eZDebug::writeNotice( "There is no object name for version($version) of the content object ($contentObjectID) in language($lang)", __METHOD__ );
  368. return $name;
  369. }
  370. $db = eZDB::instance();
  371. $contentObjectID = $this->attribute( 'id' );
  372. if ( !$lang )
  373. {
  374. // If $lang not given we will use the initial language of the object
  375. $query = "SELECT initial_language_id FROM ezcontentobject WHERE id='$contentObjectID'";
  376. $rows = $db->arrayQuery( $query );
  377. if ( $rows )
  378. {
  379. $languageID = $rows[0]['initial_language_id'];
  380. $language = eZContentLanguage::fetch( $languageID );
  381. if ( $language )
  382. {
  383. $lang = $language->attribute( 'locale' );
  384. }
  385. else
  386. {
  387. return $name;
  388. }
  389. }
  390. else
  391. {
  392. return $name;
  393. }
  394. }
  395. $lang = $db->escapeString( $lang );
  396. $version = (int) $version;
  397. $languageID = $this->attribute( 'initial_language_id' );
  398. if ( $this->attribute( 'always_available' ) )
  399. {
  400. $languageID = (int) $languageID | 1;
  401. }
  402. $query= "SELECT name, content_translation
  403. FROM ezcontentobject_name
  404. WHERE contentobject_id = '$contentObjectID'
  405. AND content_version = '$version'
  406. AND ( content_translation = '$lang' OR language_id = '$languageID' )";
  407. $result = $db->arrayQuery( $query );
  408. $resCount = count( $result );
  409. if( $resCount < 1 )
  410. {
  411. eZDebug::writeNotice( "There is no object name for version($version) of the content object ($contentObjectID) in language($lang)", __METHOD__ );
  412. }
  413. else if( $resCount > 1 )
  414. {
  415. // we have name in requested language => find and return it
  416. foreach( $result as $row )
  417. {
  418. if( $row['content_translation'] == $lang )
  419. {
  420. $name = $row['name'];
  421. break;
  422. }
  423. }
  424. }
  425. else
  426. {
  427. // we don't have name in requested language(or requested language is the same as initial language) => use name in initial language
  428. $name = $result[0]['name'];
  429. }
  430. return $name;
  431. }
  432. /**
  433. * Sets the name of the object, in memory only. Use {@see setName()} to change it permanently
  434. *
  435. * @param string $name
  436. */
  437. function setCachedName( $name )
  438. {
  439. $this->Name = $name;
  440. }
  441. /**
  442. * Sets the name of the object in all translations.
  443. *
  444. * Transaction unsafe. If you call several transaction unsafe methods you must enclose
  445. * the calls within a db transaction; thus within db->begin and db->commit.
  446. *
  447. * @param string $objectName
  448. * @param int|bool $versionNum
  449. * @param int|bool $languageCode
  450. */
  451. function setName( $objectName, $versionNum = false, $languageCode = false )
  452. {
  453. $initialLanguageCode = false;
  454. if ( $initialLanguage = $this->initialLanguage() )
  455. {
  456. $initialLanguageCode = $initialLanguage->attribute( 'locale' );
  457. }
  458. $db = eZDB::instance();
  459. if ( $languageCode == false )
  460. {
  461. $languageCode = $initialLanguageCode;
  462. }
  463. $languageCode = $db->escapeString( $languageCode );
  464. if ( $languageCode == $initialLanguageCode )
  465. {
  466. $this->Name = $objectName;
  467. }
  468. if ( !$versionNum )
  469. {
  470. $versionNum = $this->attribute( 'current_version' );
  471. }
  472. $objectID =(int) $this->attribute( 'id' );
  473. $versionNum =(int) $versionNum;
  474. $languageID =(int) eZContentLanguage::idByLocale( $languageCode );
  475. $objectName = $db->escapeString( $objectName );
  476. $db->begin();
  477. // Check if name is already set before setting/changing it.
  478. // This helps to avoid deadlocks in mysql: a pair of DELETE/INSERT might cause deadlock here
  479. // in case of concurrent execution.
  480. $rows = $db->arrayQuery( "SELECT COUNT(*) AS count FROM ezcontentobject_name WHERE contentobject_id = '$objectID'
  481. AND content_version = '$versionNum' AND content_translation ='$languageCode'" );
  482. if ( $rows[0]['count'] )
  483. {
  484. $db->query( "UPDATE ezcontentobject_name SET name='$objectName'
  485. WHERE
  486. contentobject_id = '$objectID' AND
  487. content_version = '$versionNum' AND
  488. content_translation ='$languageCode'" );
  489. }
  490. else
  491. {
  492. $db->query( "INSERT INTO ezcontentobject_name( contentobject_id,
  493. name,
  494. content_version,
  495. content_translation,
  496. real_translation,
  497. language_id )
  498. VALUES( '$objectID',
  499. '$objectName',
  500. '$versionNum',
  501. '$languageCode',
  502. '$languageCode',
  503. '$languageID' )" );
  504. }
  505. $db->commit();
  506. }
  507. /**
  508. * Return a map with all the content object attributes where the keys are the attribute identifiers.
  509. *
  510. * @return eZContentObjectAttribute[]
  511. */
  512. function dataMap()
  513. {
  514. return $this->fetchDataMap();
  515. }
  516. /**
  517. * Generates a map with all the content object attributes where the keys are
  518. * the attribute identifiers grouped by class attribute category.
  519. *
  520. * Result is not cached, so make sure you don't call this over and over.
  521. *
  522. * @return array
  523. */
  524. public function groupedDataMap()
  525. {
  526. return self::createGroupedDataMap( $this->fetchDataMap() );
  527. }
  528. /**
  529. * Generates a map with all the content object attributes where the keys are
  530. * the attribute identifiers grouped by class attribute category.
  531. *
  532. * Result is not cached, so make sure you don't call this over and over.
  533. *
  534. * @param eZContentObjectAttribute[] $contentObjectAttributes Array of eZContentObjectAttribute objects
  535. * @return array
  536. */
  537. public static function createGroupedDataMap( $contentObjectAttributes )
  538. {
  539. $groupedDataMap = array();
  540. $contentINI = eZINI::instance( 'content.ini' );
  541. $categorys = $contentINI->variable( 'ClassAttributeSettings', 'CategoryList' );
  542. $defaultCategory = $contentINI->variable( 'ClassAttributeSettings', 'DefaultCategory' );
  543. foreach( $contentObjectAttributes as $attribute )
  544. {
  545. $classAttribute = $attribute->contentClassAttribute();
  546. $attributeCategory = $classAttribute->attribute('category');
  547. $attributeIdentifier = $classAttribute->attribute( 'identifier' );
  548. if ( !isset( $categorys[ $attributeCategory ] ) || !$attributeCategory )
  549. $attributeCategory = $defaultCategory;
  550. if ( !isset( $groupedDataMap[ $attributeCategory ] ) )
  551. $groupedDataMap[ $attributeCategory ] = array();
  552. $groupedDataMap[ $attributeCategory ][$attributeIdentifier] = $attribute;
  553. }
  554. return $groupedDataMap;
  555. }
  556. /**
  557. * Returns a map with all the content object attributes where the keys are the attribute identifiers.
  558. *
  559. * @param int|bool $version
  560. * @param string|bool $language
  561. * @return eZContentObjectAttribute[]
  562. */
  563. function fetchDataMap( $version = false, $language = false )
  564. {
  565. // Global variable to cache datamaps
  566. global $eZContentObjectDataMapCache;
  567. if ( $version == false )
  568. $version = $this->attribute( 'current_version' );
  569. if ( $language == false )
  570. {
  571. $language = $this->CurrentLanguage;
  572. }
  573. if ( !$language || !isset( $eZContentObjectDataMapCache[$this->ID][$version][$language] ) )
  574. {
  575. $data = $this->contentObjectAttributes( true, $version, $language );
  576. if ( !$language )
  577. {
  578. $language = $this->CurrentLanguage;
  579. }
  580. // Store the attributes for later use
  581. $this->ContentObjectAttributeArray[$version][$language] = $data;
  582. $eZContentObjectDataMapCache[$this->ID][$version][$language] = $data;
  583. }
  584. else
  585. {
  586. $data = $eZContentObjectDataMapCache[$this->ID][$version][$language];
  587. }
  588. if ( !isset( $this->DataMap[$version][$language] ) )
  589. {
  590. $ret = array();
  591. /* @var eZContentObjectAttribute[] $data */
  592. foreach( $data as $key => $item )
  593. {
  594. $identifier = $item->contentClassAttributeIdentifier();
  595. $ret[$identifier] = $data[$key];
  596. }
  597. $this->DataMap[$version][$language] = $ret;
  598. }
  599. else
  600. {
  601. $ret = $this->DataMap[$version][$language];
  602. }
  603. return $ret;
  604. }
  605. /**
  606. * Resets (empties) the current object's data map
  607. *
  608. * @return array
  609. */
  610. function resetDataMap()
  611. {
  612. $this->ContentObjectAttributeArray = array();
  613. $this->ContentObjectAttributes = array();
  614. $this->DataMap = array();
  615. return $this->DataMap;
  616. }
  617. /**
  618. * Fetches a set of content object attributes by their class identifiers.
  619. *
  620. * @param string[] $identifierArray
  621. * @param int|bool $version
  622. * @param string[]|bool $languageArray
  623. * @param bool $asObject If true, returns an array of eZContentObjectAttributes, a normal array otherwise
  624. *
  625. * @return eZContentObjectAttribute[]|array|null
  626. */
  627. function fetchAttributesByIdentifier( $identifierArray, $version = false, $languageArray = false, $asObject = true )
  628. {
  629. if ( count( $identifierArray ) === 0 )
  630. {
  631. return null;
  632. }
  633. $db = eZDB::instance();
  634. $identifierQuotedString = array();
  635. foreach ( $identifierArray as $identifier )
  636. {
  637. $identifierQuotedString[] = "'$identifier'";
  638. }
  639. if ( !$version or !is_numeric( $version ) )
  640. {
  641. $version = $this->CurrentVersion;
  642. }
  643. if ( is_array( $languageArray ) )
  644. {
  645. $langCodeQuotedString = array();
  646. foreach ( $languageArray as $langCode )
  647. {
  648. if ( is_string( $langCode ) )
  649. $langCodeQuotedString[] = "'$langCode'";
  650. }
  651. if ( !empty( $langCodeQuotedString ) )
  652. {
  653. $languageText = "AND ";
  654. $languageText .= $db->generateSQLINStatement( $langCodeQuotedString, 'ezcontentobject_attribute.language_code' );
  655. }
  656. }
  657. if ( !isset( $languageText ) )
  658. {
  659. $languageText = "AND " . eZContentLanguage::sqlFilter( 'ezcontentobject_attribute', 'ezcontentobject_version' );
  660. }
  661. $versionText = "AND ezcontentobject_attribute.version = '$version'";
  662. $query = "SELECT ezcontentobject_attribute.*, ezcontentclass_attribute.identifier as identifier
  663. FROM ezcontentobject_attribute, ezcontentclass_attribute, ezcontentobject_version
  664. WHERE
  665. ezcontentclass_attribute.version = ". eZContentClass::VERSION_STATUS_DEFINED . " AND
  666. ezcontentclass_attribute.id = ezcontentobject_attribute.contentclassattribute_id AND
  667. ezcontentobject_version.contentobject_id = {$this->ID} AND
  668. ezcontentobject_version.version = {$version} AND
  669. ezcontentobject_attribute.contentobject_id = {$this->ID}
  670. {$languageText}
  671. {$versionText}
  672. AND
  673. ";
  674. $query .= $db->generateSQLINStatement( $identifierQuotedString, 'identifier' );
  675. $rows = $db->arrayQuery( $query );
  676. if ( count( $rows ) > 0 )
  677. {
  678. if ( $asObject )
  679. {
  680. $returnArray = array();
  681. foreach( $rows as $row )
  682. {
  683. $returnArray[$row['id']] = new eZContentObjectAttribute( $row );
  684. }
  685. return $returnArray;
  686. }
  687. else
  688. {
  689. return $rows;
  690. }
  691. }
  692. return null;
  693. }
  694. /**
  695. * Returns the owner of the object as a content object.
  696. *
  697. * @return eZContentObject|null
  698. */
  699. function owner()
  700. {
  701. if ( $this->OwnerID != 0 )
  702. {
  703. return eZContentObject::fetch( $this->OwnerID );
  704. }
  705. return null;
  706. }
  707. /**
  708. * Returns the content class group identifiers for the current content object
  709. *
  710. * @return array
  711. */
  712. function contentClassGroupIDList()
  713. {
  714. $contentClass = $this->contentClass();
  715. return $contentClass->attribute( 'ingroup_id_list' );
  716. }
  717. /**
  718. * Returns the content class identifer for the current content object
  719. *
  720. * The object will cache the class name information so multiple calls will be fast.
  721. *
  722. * @return string|bool|null
  723. */
  724. function contentClassIdentifier()
  725. {
  726. if ( !is_numeric( $this->ClassID ) )
  727. {
  728. $retValue = null;
  729. return $retValue;
  730. }
  731. if ( $this->ClassIdentifier !== false )
  732. return $this->ClassIdentifier;
  733. $this->ClassIdentifier = eZContentClass::classIdentifierByID( $this->ClassID );
  734. return $this->ClassIdentifier;
  735. }
  736. /**
  737. * Returns the content class for the current content object
  738. *
  739. * @return eZContentClass|null
  740. */
  741. function contentClass()
  742. {
  743. if ( !is_numeric( $this->ClassID ) )
  744. {
  745. $retValue = null;
  746. return $retValue;
  747. }
  748. return eZContentClass::fetch( $this->ClassID );
  749. }
  750. /**
  751. * Returns the remote id of the current content object
  752. *
  753. * @return string
  754. */
  755. function remoteID()
  756. {
  757. $remoteID = $this->attribute( 'remote_id', true );
  758. if ( !$remoteID )
  759. {
  760. $this->setAttribute( 'remote_id', eZRemoteIdUtility::generate( 'object' ) );
  761. if ( $this->attribute( 'id' ) !== null )
  762. $this->sync( array( 'remote_id' ) );
  763. $remoteID = $this->attribute( 'remote_id', true );
  764. }
  765. return $remoteID;
  766. }
  767. /**
  768. * Returns the ID of the the current object's main node
  769. *
  770. * @return int|null
  771. */
  772. function mainParentNodeID()
  773. {
  774. $list = eZContentObjectTreeNode::getParentNodeIdListByContentObjectID( $this->ID, false, true );
  775. return isset( $list[0] ) ? $list[0] : null;
  776. }
  777. /**
  778. * Returns a contentobject by remote ID
  779. *
  780. * @param string $remoteID
  781. * @param bool $asObject
  782. * @return eZContentObject|array|null
  783. */
  784. static function fetchByRemoteID( $remoteID, $asObject = true )
  785. {
  786. $db = eZDB::instance();
  787. $remoteID =$db->escapeString( $remoteID );
  788. $resultArray = $db->arrayQuery( 'SELECT id FROM ezcontentobject WHERE remote_id=\'' . $remoteID . '\'' );
  789. if ( count( $resultArray ) != 1 )
  790. $object = null;
  791. else
  792. $object = eZContentObject::fetch( $resultArray[0]['id'], $asObject );
  793. return $object;
  794. }
  795. /**
  796. * Fetches a content object by ID
  797. *
  798. * @param int $id ID of the content object to fetch
  799. * @param bool $asObject Return the result as an object (true) or an assoc. array (false)
  800. *
  801. * @return eZContentObject
  802. */
  803. static function fetch( $id, $asObject = true )
  804. {
  805. global $eZContentObjectContentObjectCache;
  806. // If the object given by its id is not cached or should be returned as array
  807. // then we fetch it from the DB (objects are always cached as arrays).
  808. if ( !isset( $eZContentObjectContentObjectCache[$id] ) or $asObject === false )
  809. {
  810. $db = eZDB::instance();
  811. $resArray = $db->arrayQuery( eZContentObject::createFetchSQLString( $id ) );
  812. $objectArray = array();
  813. if ( count( $resArray ) == 1 && $resArray !== false )
  814. {
  815. $objectArray = $resArray[0];
  816. }
  817. else
  818. {
  819. eZDebug::writeError( "Object not found ($id)", __METHOD__ );
  820. $retValue = null;
  821. return $retValue;
  822. }
  823. if ( $asObject )
  824. {
  825. $obj = new eZContentObject( $objectArray );
  826. $eZContentObjectContentObjectCache[$id] = $obj;
  827. }
  828. else
  829. {
  830. return $objectArray;
  831. }
  832. return $obj;
  833. }
  834. else
  835. {
  836. return $eZContentObjectContentObjectCache[$id];
  837. }
  838. }
  839. /**
  840. * Fetches a content object by ID, using SELECT ... FOR UPDATE
  841. *
  842. * Ensures the table row is locked, blocking other transactions from locking it (read or write).
  843. * Usage must be within a transaction, or it will be locked for the current session.
  844. *
  845. * @param int $id ID of the content object to fetch
  846. * @param bool $asObject Return the result as an object (true) or an assoc. array (false)
  847. *
  848. * @return eZContentObject|mixed|null
  849. */
  850. static function fetchForUpdate( $id, $asObject = true )
  851. {
  852. global $eZContentObjectContentObjectCache;
  853. $db = eZDB::instance();
  854. $id = (int) $id;
  855. // Select for update, to lock the row
  856. $resArray = $db->arrayQuery( "SELECT * FROM ezcontentobject WHERE id='$id' FOR UPDATE" );
  857. if ( !is_array( $resArray ) || count( $resArray ) !== 1 )
  858. {
  859. eZDebug::writeError( "Object not found ($id)", __METHOD__ );
  860. return null;
  861. }
  862. $objectArray = $resArray[0];
  863. $classId = $objectArray['contentclass_id'];
  864. $contentClassResArray = $db->arrayQuery(
  865. "SELECT
  866. ezcontentclass.serialized_name_list as serialized_name_list,
  867. ezcontentclass.identifier as contentclass_identifier,
  868. ezcontentclass.is_container as is_container
  869. FROM
  870. ezcontentclass
  871. WHERE
  872. ezcontentclass.id='$classId' AND
  873. ezcontentclass.version=0"
  874. );
  875. $objectArray = array_merge($objectArray, $contentClassResArray[0]);
  876. if ( !$asObject )
  877. {
  878. return $objectArray;
  879. }
  880. $obj = new eZContentObject( $objectArray );
  881. $eZContentObjectContentObjectCache[$id] = $obj;
  882. return $obj;
  883. }
  884. /**
  885. * Returns true, if a content object with the ID $id exists, false otherwise
  886. *
  887. * @param int $id
  888. * @return bool
  889. */
  890. static function exists( $id )
  891. {
  892. global $eZContentObjectContentObjectCache;
  893. // Check the global cache
  894. if ( isset( $eZContentObjectContentObjectCache[$id] ) )
  895. return true;
  896. // If the object is not cached we need to check the DB
  897. $db = eZDB::instance();
  898. $resArray = $db->arrayQuery( eZContentObject::createFetchSQLString( $id ) );
  899. if ( $resArray !== false and count( $resArray ) == 1 )
  900. {
  901. return true;
  902. }
  903. return false;
  904. }
  905. /**
  906. * Creates the SQL for fetching the object with ID $id and returns the string.
  907. *
  908. * @param int $id
  909. * @return string
  910. */
  911. static function createFetchSQLString( $id )
  912. {
  913. $id = (int) $id;
  914. $fetchSQLString = "SELECT ezcontentobject.*,
  915. ezcontentclass.serialized_name_list as serialized_name_list,
  916. ezcontentclass.identifier as contentclass_identifier,
  917. ezcontentclass.is_container as is_container
  918. FROM
  919. ezcontentobject,
  920. ezcontentclass
  921. WHERE
  922. ezcontentobject.id='$id' AND
  923. ezcontentclass.id = ezcontentobject.contentclass_id AND
  924. ezcontentclass.version=0";
  925. return $fetchSQLString;
  926. }
  927. /**
  928. * Creates the SQL for filtering objects by visibility, used by IgnoreVisibility on some fetches.
  929. * The object is visible if 1 or more assigned nodes are visible.
  930. *
  931. * @since Version 4.1
  932. * @param bool $IgnoreVisibility ignores visibility if true
  933. * @param string $ezcontentobjectTable name of ezcontentobject table used in sql
  934. * @return string with sql condition for node filtering by visibility
  935. */
  936. static function createFilterByVisibilitySQLString( $IgnoreVisibility = false, $ezcontentobjectTable = 'ezcontentobject' )
  937. {
  938. if ( $IgnoreVisibility )
  939. return '';
  940. return " AND ( SELECT MIN( ezct.is_invisible ) FROM ezcontentobject_tree ezct WHERE ezct.contentobject_id = $ezcontentobjectTable.id ) = 0 ";
  941. }
  942. /**
  943. * Fetches the contentobject which has a node with ID $nodeID
  944. *
  945. * $nodeID can also be an array of NodeIDs. In this case, an array of content objects will be returned
  946. *
  947. * @param int|array $nodeID Single nodeID or array of NodeIDs
  948. * @param bool $asObject If results have to be returned as eZContentObject instances or not
  949. * @return eZContentObject|eZContentObject[]|array|null Content object or array of content objects.
  950. * Content objects can be eZContentObject instances or array result sets
  951. */
  952. static function fetchByNodeID( $nodeID, $asObject = true )
  953. {
  954. global $eZContentObjectContentObjectCache;
  955. $resultAsArray = is_array( $nodeID );
  956. $nodeID = (array)$nodeID;
  957. $db = eZDB::instance();
  958. $resArray = $db->arrayQuery(
  959. "SELECT co.*, con.name as name, con.real_translation, cot.node_id
  960. FROM ezcontentobject co
  961. JOIN ezcontentobject_tree cot ON co.id = cot.contentobject_id AND co.current_version = cot.contentobject_version
  962. JOIN ezcontentobject_name con ON co.id = con.contentobject_id AND co.current_version = con.content_version
  963. WHERE " .
  964. $db->generateSQLINStatement( $nodeID, 'cot.node_id', false, true, 'int' ) . " AND " .
  965. eZContentLanguage::sqlFilter( 'con', 'co' )
  966. );
  967. if ( $resArray === false || empty( $resArray ) )
  968. {
  969. eZDebug::writeError( 'A problem occured while fetching objects with following NodeIDs : ' . implode( ', ', $nodeID ), __METHOD__ );
  970. return $resultAsArray ? array() : null;
  971. }
  972. $objectArray = array();
  973. if ( $asObject )
  974. {
  975. foreach ( $resArray as $res )
  976. {
  977. $objectArray[$res['node_id']] = $eZContentObjectContentObjectCache[$res['id']] = new self( $res );
  978. }
  979. }
  980. else
  981. {
  982. foreach ( $resArray as $res )
  983. {
  984. $objectArray[$res['node_id']] = $res;
  985. }
  986. }
  987. if ( !$resultAsArray )
  988. return $objectArray[$res['node_id']];
  989. return $objectArray;
  990. }
  991. /**
  992. * Fetches a content object list based on an array of content object ids
  993. *
  994. * @param array $idArray array of content object ids
  995. * @param bool $asObject
  996. * Wether to get the result as an array of eZContentObject or an
  997. * array of associative arrays
  998. * @param bool|string $lang A language code to put at the top of the prioritized
  999. * languages list.
  1000. *
  1001. * @return array(contentObjectID => eZContentObject|array)
  1002. * array of eZContentObject (if $asObject = true) or array of
  1003. * associative arrays (if $asObject = false)
  1004. */
  1005. static function fetchIDArray( $idArray, $asObject = true , $lang = false )
  1006. {
  1007. global $eZContentObjectContentObjectCache;
  1008. $db = eZDB::instance();
  1009. $resRowArray = $db->arrayQuery(
  1010. "SELECT ezcontentclass.serialized_name_list as class_serialized_name_list, ezcontentobject.*, ezcontentobject_name.name as name, ezcontentobject_name.real_translation
  1011. FROM
  1012. ezcontentclass,
  1013. ezcontentobject,
  1014. ezcontentobject_name
  1015. WHERE
  1016. ezcontentclass.id=ezcontentobject.contentclass_id AND " .
  1017. // All elements from $idArray should be casted to (int)
  1018. $db->generateSQLINStatement( $idArray, 'ezcontentobject.id', false, true, 'int' ) . " AND
  1019. ezcontentobject.id = ezcontentobject_name.contentobject_id AND
  1020. ezcontentobject.current_version = ezcontentobject_name.content_version AND " .
  1021. eZContentLanguage::sqlFilter( 'ezcontentobject_name', 'ezcontentobject', 'language_id', 'language_mask', $lang )
  1022. );
  1023. $objectRetArray = array();
  1024. foreach ( $resRowArray as $resRow )
  1025. {
  1026. $objectID = $resRow['id'];
  1027. $resRow['class_name'] = eZContentClass::nameFromSerializedString( $resRow['class_serialized_name_list'] );
  1028. if ( $asObject )
  1029. {
  1030. $obj = new eZContentObject( $resRow );
  1031. $obj->ClassName = $resRow['class_name'];
  1032. if ( $lang !== false )
  1033. {
  1034. $eZContentObjectContentObjectCache[$objectID] = $obj;
  1035. }
  1036. $objectRetArray[$objectID] = $obj;
  1037. }
  1038. else
  1039. {
  1040. $objectRetArray[$objectID] = $resRow;
  1041. }
  1042. }
  1043. return $objectRetArray;
  1044. }
  1045. /**
  1046. * Returns an array of content objects.
  1047. *
  1048. * @param bool $asObject Whether to return objects or not
  1049. * @param array|null $conditions Optional conditions to limit the fetch
  1050. * @param int|bool $offset Where to start fetch from, set to false to skip it.
  1051. * @param int|bool $limit Maximum number of objects to fetch, set false to skip it.
  1052. * @return eZContentObject[]|array|null
  1053. */
  1054. static function fetchList( $asObject = true, $conditions = null, $offset = false, $limit = false )
  1055. {
  1056. $limitation = null;
  1057. if ( $offset !== false or
  1058. $limit !== false )
  1059. $limitation = array( 'offset' => $offset,
  1060. 'length' => $limit );
  1061. return eZPersistentObject::fetchObjectList( eZContentObject::definition(),
  1062. null,
  1063. $conditions, null, $limitation,
  1064. $asObject );
  1065. }
  1066. /**
  1067. * Returns a filtered array of content objects.
  1068. *
  1069. * @param array|null $conditions Optional conditions to limit the fetch
  1070. * @param int|bool $offset Where to start fetch from, set to false to skip it.
  1071. * @param int|bool $limit Maximum number of objects to fetch, set false to skip it.
  1072. * @param bool $asObject Whether to return objects or not
  1073. * @return array|eZPersistentObject[]|null
  1074. */
  1075. static function fetchFilteredList( $conditions = null, $offset = false, $limit = false, $asObject = true )
  1076. {
  1077. $limits = null;
  1078. if ( $offset or $limit )
  1079. $limits = array( 'offset' => $offset,
  1080. 'length' => $limit );
  1081. return eZPersistentObject::fetchObjectList( eZContentObject::definition(),
  1082. null,
  1083. $conditions, null, $limits,
  1084. $asObject );
  1085. }
  1086. /**
  1087. * Returns the number of objects in the database. Optionally \a $conditions can be used to limit the list count.
  1088. * @param array|null $conditions
  1089. * @return int
  1090. */
  1091. static function fetchListCount( $conditions = null )
  1092. {
  1093. $rows = eZPersistentObject::fetchObjectList( eZContentObject::definition(),
  1094. array(),
  1095. $conditions,
  1096. false/* we don't want any sorting when counting. Sorting leads to error on postgresql 8.x */,
  1097. null,
  1098. false, false,
  1099. array( array( 'operation' => 'count( * )',
  1100. 'name' => 'count' ) ) );
  1101. return $rows[0]['count'];
  1102. }
  1103. /**
  1104. * Returns an array of content objects with the content class id $contentClassID
  1105. *
  1106. * @param int $contentClassID
  1107. * @param bool $asObject Whether to return objects or not
  1108. * @param int|bool $offset Where to start fetch from, set to false to skip it.
  1109. * @param int|bool $limit Maximum number of objects to fetch, set false to skip it.
  1110. * @return eZCā€¦

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