metadata.php 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413
  1. <?php
  2. /**
  3. * Elgg metadata
  4. * Functions to manage entity metadata.
  5. *
  6. * @package Elgg.Core
  7. * @subpackage DataModel.Metadata
  8. */
  9. /**
  10. * Convert a database row to a new \ElggMetadata
  11. *
  12. * @param \stdClass $row An object from the database
  13. *
  14. * @return \stdClass|\ElggMetadata
  15. * @access private
  16. */
  17. function row_to_elggmetadata($row) {
  18. if (!($row instanceof \stdClass)) {
  19. return $row;
  20. }
  21. return new \ElggMetadata($row);
  22. }
  23. /**
  24. * Get a specific metadata object by its id.
  25. * If you want multiple metadata objects, use
  26. * {@link elgg_get_metadata()}.
  27. *
  28. * @param int $id The id of the metadata object being retrieved.
  29. *
  30. * @return \ElggMetadata|false false if not found
  31. */
  32. function elgg_get_metadata_from_id($id) {
  33. return _elgg_services()->metadataTable->get($id);
  34. }
  35. /**
  36. * Deletes metadata using its ID.
  37. *
  38. * @param int $id The metadata ID to delete.
  39. * @return bool
  40. */
  41. function elgg_delete_metadata_by_id($id) {
  42. return _elgg_services()->metadataTable->delete($id);
  43. }
  44. /**
  45. * Create a new metadata object, or update an existing one.
  46. *
  47. * Metadata can be an array by setting allow_multiple to true, but it is an
  48. * indexed array with no control over the indexing.
  49. *
  50. * @param int $entity_guid The entity to attach the metadata to
  51. * @param string $name Name of the metadata
  52. * @param string $value Value of the metadata
  53. * @param string $value_type 'text', 'integer', or '' for automatic detection
  54. * @param int $owner_guid GUID of entity that owns the metadata. Default is logged in user.
  55. * @param int $access_id Default is ACCESS_PRIVATE
  56. * @param bool $allow_multiple Allow multiple values for one key. Default is false
  57. *
  58. * @return int|false id of metadata or false if failure
  59. */
  60. function create_metadata($entity_guid, $name, $value, $value_type = '', $owner_guid = 0,
  61. $access_id = ACCESS_PRIVATE, $allow_multiple = false) {
  62. return _elgg_services()->metadataTable->create($entity_guid, $name, $value,
  63. $value_type, $owner_guid, $access_id, $allow_multiple);
  64. }
  65. /**
  66. * Update a specific piece of metadata.
  67. *
  68. * @param int $id ID of the metadata to update
  69. * @param string $name Metadata name
  70. * @param string $value Metadata value
  71. * @param string $value_type Value type
  72. * @param int $owner_guid Owner guid
  73. * @param int $access_id Access ID
  74. *
  75. * @return bool
  76. */
  77. function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_id) {
  78. return _elgg_services()->metadataTable->update($id, $name, $value,
  79. $value_type, $owner_guid, $access_id);
  80. }
  81. /**
  82. * This function creates metadata from an associative array of "key => value" pairs.
  83. *
  84. * To achieve an array for a single key, pass in the same key multiple times with
  85. * allow_multiple set to true. This creates an indexed array. It does not support
  86. * associative arrays and there is no guarantee on the ordering in the array.
  87. *
  88. * @param int $entity_guid The entity to attach the metadata to
  89. * @param array $name_and_values Associative array - a value can be a string, number, bool
  90. * @param string $value_type 'text', 'integer', or '' for automatic detection
  91. * @param int $owner_guid GUID of entity that owns the metadata
  92. * @param int $access_id Default is ACCESS_PRIVATE
  93. * @param bool $allow_multiple Allow multiple values for one key. Default is false
  94. *
  95. * @return bool
  96. */
  97. function create_metadata_from_array($entity_guid, array $name_and_values, $value_type, $owner_guid,
  98. $access_id = ACCESS_PRIVATE, $allow_multiple = false) {
  99. return _elgg_services()->metadataTable->createFromArray($entity_guid, $name_and_values,
  100. $value_type, $owner_guid, $access_id, $allow_multiple);
  101. }
  102. /**
  103. * Returns metadata. Accepts all elgg_get_entities() options for entity
  104. * restraints.
  105. *
  106. * @see elgg_get_entities
  107. *
  108. * @warning 1.7's find_metadata() didn't support limits and returned all metadata.
  109. * This function defaults to a limit of 25. There is probably not a reason
  110. * for you to return all metadata unless you're exporting an entity,
  111. * have other restraints in place, or are doing something horribly
  112. * wrong in your code.
  113. *
  114. * @param array $options Array in format:
  115. *
  116. * metadata_names => null|ARR metadata names
  117. * metadata_values => null|ARR metadata values
  118. * metadata_ids => null|ARR metadata ids
  119. * metadata_case_sensitive => BOOL Overall Case sensitive
  120. * metadata_owner_guids => null|ARR guids for metadata owners
  121. * metadata_created_time_lower => INT Lower limit for created time.
  122. * metadata_created_time_upper => INT Upper limit for created time.
  123. * metadata_calculation => STR Perform the MySQL function on the metadata values returned.
  124. * The "metadata_calculation" option causes this function to
  125. * return the result of performing a mathematical calculation on
  126. * all metadata that match the query instead of returning
  127. * \ElggMetadata objects.
  128. *
  129. * @return \ElggMetadata[]|mixed
  130. * @since 1.8.0
  131. */
  132. function elgg_get_metadata(array $options = array()) {
  133. return _elgg_services()->metadataTable->getAll($options);
  134. }
  135. /**
  136. * Deletes metadata based on $options.
  137. *
  138. * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
  139. * This requires at least one constraint: metadata_owner_guid(s),
  140. * metadata_name(s), metadata_value(s), or guid(s) must be set.
  141. *
  142. * @param array $options An options array. {@link elgg_get_metadata()}
  143. * @return bool|null true on success, false on failure, null if no metadata to delete.
  144. * @since 1.8.0
  145. */
  146. function elgg_delete_metadata(array $options) {
  147. return _elgg_services()->metadataTable->deleteAll($options);
  148. }
  149. /**
  150. * Disables metadata based on $options.
  151. *
  152. * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
  153. *
  154. * @param array $options An options array. {@link elgg_get_metadata()}
  155. * @return bool|null true on success, false on failure, null if no metadata disabled.
  156. * @since 1.8.0
  157. */
  158. function elgg_disable_metadata(array $options) {
  159. return _elgg_services()->metadataTable->disableAll($options);
  160. }
  161. /**
  162. * Enables metadata based on $options.
  163. *
  164. * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
  165. *
  166. * @warning In order to enable metadata, you must first use
  167. * {@link access_show_hidden_entities()}.
  168. *
  169. * @param array $options An options array. {@link elgg_get_metadata()}
  170. * @return bool|null true on success, false on failure, null if no metadata enabled.
  171. * @since 1.8.0
  172. */
  173. function elgg_enable_metadata(array $options) {
  174. return _elgg_services()->metadataTable->enableAll($options);
  175. }
  176. /**
  177. * \ElggEntities interfaces
  178. */
  179. /**
  180. * Returns entities based upon metadata. Also accepts all
  181. * options available to elgg_get_entities(). Supports
  182. * the singular option shortcut.
  183. *
  184. * @note Using metadata_names and metadata_values results in a
  185. * "names IN (...) AND values IN (...)" clause. This is subtly
  186. * differently than default multiple metadata_name_value_pairs, which use
  187. * "(name = value) AND (name = value)" clauses.
  188. *
  189. * When in doubt, use name_value_pairs.
  190. *
  191. * To ask for entities that do not have a metadata value, use a custom
  192. * where clause like this:
  193. *
  194. * $options['wheres'][] = "NOT EXISTS (
  195. * SELECT 1 FROM {$dbprefix}metadata md
  196. * WHERE md.entity_guid = e.guid
  197. * AND md.name_id = $name_metastring_id
  198. * AND md.value_id = $value_metastring_id)";
  199. *
  200. * Note the metadata name and value has been denormalized in the above example.
  201. *
  202. * @see elgg_get_entities
  203. *
  204. * @param array $options Array in format:
  205. *
  206. * metadata_names => null|ARR metadata names
  207. *
  208. * metadata_values => null|ARR metadata values
  209. *
  210. * metadata_name_value_pairs => null|ARR (
  211. * name => 'name',
  212. * value => 'value',
  213. * 'operand' => '=',
  214. * 'case_sensitive' => true
  215. * )
  216. * Currently if multiple values are sent via
  217. * an array (value => array('value1', 'value2')
  218. * the pair's operand will be forced to "IN".
  219. * If passing "IN" as the operand and a string as the value,
  220. * the value must be a properly quoted and escaped string.
  221. *
  222. * metadata_name_value_pairs_operator => null|STR The operator to use for combining
  223. * (name = value) OPERATOR (name = value); default AND
  224. *
  225. * metadata_case_sensitive => BOOL Overall Case sensitive
  226. *
  227. * order_by_metadata => null|ARR array(
  228. * 'name' => 'metadata_text1',
  229. * 'direction' => ASC|DESC,
  230. * 'as' => text|integer
  231. * )
  232. * Also supports array('name' => 'metadata_text1')
  233. *
  234. * metadata_owner_guids => null|ARR guids for metadata owners
  235. *
  236. * @return \ElggEntity[]|mixed If count, int. If not count, array. false on errors.
  237. * @since 1.7.0
  238. */
  239. function elgg_get_entities_from_metadata(array $options = array()) {
  240. return _elgg_services()->metadataTable->getEntities($options);
  241. }
  242. /**
  243. * Returns a list of entities filtered by provided metadata.
  244. *
  245. * @see elgg_get_entities_from_metadata
  246. *
  247. * @param array $options Options array
  248. *
  249. * @return array
  250. * @since 1.7.0
  251. */
  252. function elgg_list_entities_from_metadata($options) {
  253. return elgg_list_entities($options, 'elgg_get_entities_from_metadata');
  254. }
  255. /**
  256. * Returns metadata name and value SQL where for entities.
  257. * NB: $names and $values are not paired. Use $pairs for this.
  258. * Pairs default to '=' operand.
  259. *
  260. * This function is reused for annotations because the tables are
  261. * exactly the same.
  262. *
  263. * @param string $e_table Entities table name
  264. * @param string $n_table Normalized metastrings table name (Where entities,
  265. * values, and names are joined. annotations / metadata)
  266. * @param array|null $names Array of names
  267. * @param array|null $values Array of values
  268. * @param array|null $pairs Array of names / values / operands
  269. * @param string $pair_operator ("AND" or "OR") Operator to use to join the where clauses for pairs
  270. * @param bool $case_sensitive Case sensitive metadata names?
  271. * @param array|null $order_by_metadata Array of names / direction
  272. * @param array|null $owner_guids Array of owner GUIDs
  273. *
  274. * @return false|array False on fail, array('joins', 'wheres')
  275. * @since 1.7.0
  276. * @access private
  277. */
  278. function _elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = null, $values = null,
  279. $pairs = null, $pair_operator = 'AND', $case_sensitive = true, $order_by_metadata = null,
  280. $owner_guids = null) {
  281. return _elgg_services()->metadataTable->getEntityMetadataWhereSql($e_table, $n_table, $names,
  282. $values, $pairs, $pair_operator, $case_sensitive, $order_by_metadata, $owner_guids);
  283. }
  284. /**
  285. * Takes a metadata array (which has all kinds of properties)
  286. * and turns it into a simple array of strings
  287. *
  288. * @param array $array Metadata array
  289. *
  290. * @return array Array of strings
  291. */
  292. function metadata_array_to_values($array) {
  293. $valuearray = array();
  294. if (is_array($array)) {
  295. foreach ($array as $element) {
  296. $valuearray[] = $element->value;
  297. }
  298. }
  299. return $valuearray;
  300. }
  301. /**
  302. * Get the URL for this metadata
  303. *
  304. * By default this links to the export handler in the current view.
  305. *
  306. * @param int $id Metadata ID
  307. *
  308. * @return mixed
  309. */
  310. function get_metadata_url($id) {
  311. return _elgg_services()->metadataTable->getUrl($id);
  312. }
  313. /**
  314. * Mark entities with a particular type and subtype as having access permissions
  315. * that can be changed independently from their parent entity
  316. *
  317. * @param string $type The type - object, user, etc
  318. * @param string $subtype The subtype; all subtypes by default
  319. *
  320. * @return void
  321. */
  322. function register_metadata_as_independent($type, $subtype = '*') {
  323. _elgg_services()->metadataTable->registerMetadataAsIndependent($type, $subtype);
  324. }
  325. /**
  326. * Determines whether entities of a given type and subtype should not change
  327. * their metadata in line with their parent entity
  328. *
  329. * @param string $type The type - object, user, etc
  330. * @param string $subtype The entity subtype
  331. *
  332. * @return bool
  333. */
  334. function is_metadata_independent($type, $subtype) {
  335. return _elgg_services()->metadataTable->isMetadataIndependent($type, $subtype);
  336. }
  337. /**
  338. * When an entity is updated, resets the access ID on all of its child metadata
  339. *
  340. * @param string $event The name of the event
  341. * @param string $object_type The type of object
  342. * @param \ElggEntity $object The entity itself
  343. *
  344. * @return true
  345. * @access private Set as private in 1.9.0
  346. */
  347. function metadata_update($event, $object_type, $object) {
  348. return _elgg_services()->metadataTable->handleUpdate($event, $object_type, $object);
  349. }
  350. /**
  351. * Invalidate the metadata cache based on options passed to various *_metadata functions
  352. *
  353. * @param string $action Action performed on metadata. "delete", "disable", or "enable"
  354. * @param array $options Options passed to elgg_(delete|disable|enable)_metadata
  355. * @return void
  356. * @access private
  357. * @todo not used
  358. */
  359. function _elgg_invalidate_metadata_cache($action, array $options) {
  360. _elgg_services()->metadataCache->invalidateByOptions($options);
  361. }
  362. /**
  363. * Metadata unit test
  364. *
  365. * @param string $hook unit_test
  366. * @param string $type system
  367. * @param mixed $value Array of other tests
  368. * @param mixed $params Params
  369. *
  370. * @return array
  371. * @access private
  372. */
  373. function _elgg_metadata_test($hook, $type, $value, $params) {
  374. global $CONFIG;
  375. $value[] = $CONFIG->path . 'engine/tests/ElggCoreMetadataAPITest.php';
  376. $value[] = $CONFIG->path . 'engine/tests/ElggCoreMetadataCacheTest.php';
  377. return $value;
  378. }
  379. return function(\Elgg\EventsService $events, \Elgg\HooksRegistrationService $hooks) {
  380. /** Call a function whenever an entity is updated **/
  381. $events->registerHandler('update', 'all', 'metadata_update');
  382. $hooks->registerHandler('unit_test', 'system', '_elgg_metadata_test');
  383. };