diff options
Diffstat (limited to 'engine/lib/metadata.php')
| -rw-r--r-- | engine/lib/metadata.php | 1158 |
1 files changed, 412 insertions, 746 deletions
diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php index d9b310b15..fdb1b85f6 100644 --- a/engine/lib/metadata.php +++ b/engine/lib/metadata.php @@ -1,132 +1,19 @@ <?php /** * Elgg metadata - * Functions to manage object metadata. + * Functions to manage entity metadata. * - * @package Elgg - * @subpackage Core - * @author Curverider Ltd <info@elgg.com> - * @link http://elgg.org/ + * @package Elgg.Core + * @subpackage DataModel.Metadata */ /** - * ElggMetadata - * This class describes metadata that can be attached to ElggEntities. - * - * @author Curverider Ltd <info@elgg.com> - * @package Elgg - * @subpackage Core - */ -class ElggMetadata extends ElggExtender { - /** - * Construct a new site object, optionally from a given id value or row. - * - * @param mixed $id - */ - function __construct($id = null) { - $this->attributes = array(); - - if (!empty($id)) { - // Create from db row - if ($id instanceof stdClass) { - $metadata = $id; - } else { - $metadata = get_metadata($id); - } - - if ($metadata) { - $objarray = (array) $metadata; - foreach($objarray as $key => $value) { - $this->attributes[$key] = $value; - } - $this->attributes['type'] = "metadata"; - } - } - } - - /** - * Class member get overloading - * - * @param string $name - * @return mixed - */ - function __get($name) { - return $this->get($name); - } - - /** - * Class member set overloading - * - * @param string $name - * @param mixed $value - * @return mixed - */ - function __set($name, $value) { - return $this->set($name, $value); - } - - /** - * Determines whether or not the user can edit this piece of metadata - * - * @return true|false Depending on permissions - */ - function canEdit() { - if ($entity = get_entity($this->get('entity_guid'))) { - return $entity->canEditMetadata($this); - } - return false; - } - - /** - * Save matadata object - * - * @return int the metadata object id - */ - function save() { - if ($this->id > 0) { - return update_metadata($this->id, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id); - } else { - $this->id = create_metadata($this->entity_guid, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id); - if (!$this->id) { - throw new IOException(sprintf(elgg_new('IOException:UnableToSaveNew'), get_class())); - } - return $this->id; - } - } - - /** - * Delete a given metadata. - */ - function delete() { - return delete_metadata($this->id); - } - - /** - * Get a url for this item of metadata. - * - * @return string - */ - public function getURL() { - return get_metadata_url($this->id); - } - - // SYSTEM LOG INTERFACE //////////////////////////////////////////////////////////// - - /** - * For a given ID, return the object associated with it. - * This is used by the river functionality primarily. - * This is useful for checking access permissions etc on objects. - */ - public function getObjectFromID($id) { - return get_metadata($id); - } -} - -/** * Convert a database row to a new ElggMetadata * - * @param stdClass $row - * @return stdClass or ElggMetadata + * @param stdClass $row An object from the database + * + * @return stdClass|ElggMetadata + * @access private */ function row_to_elggmetadata($row) { if (!($row instanceof stdClass)) { @@ -137,64 +24,55 @@ function row_to_elggmetadata($row) { } /** - * Get a specific item of metadata. + * Get a specific metadata object by its id. + * If you want multiple metadata objects, use + * {@link elgg_get_metadata()}. * - * @param $id int The item of metadata being retrieved. + * @param int $id The id of the metadata object being retrieved. + * + * @return ElggMetadata|false FALSE if not found */ -function get_metadata($id) { - global $CONFIG; - - $id = (int)$id; - $access = get_access_sql_suffix("e"); - $md_access = get_access_sql_suffix("m"); - - return row_to_elggmetadata(get_data_row("SELECT m.*, n.string as name, v.string as value from {$CONFIG->dbprefix}metadata m JOIN {$CONFIG->dbprefix}entities e on e.guid = m.entity_guid JOIN {$CONFIG->dbprefix}metastrings v on m.value_id = v.id JOIN {$CONFIG->dbprefix}metastrings n on m.name_id = n.id where m.id=$id and $access and $md_access")); +function elgg_get_metadata_from_id($id) { + return elgg_get_metastring_based_object_from_id($id, 'metadata'); } /** - * Removes metadata on an entity with a particular name, optionally with a given value. + * Deletes metadata using its ID. * - * @param int $entity_guid The entity GUID - * @param string $name The name of the metadata - * @param string $value The optional value of the item (useful for removing a single item in a multiple set) - * @return true|false Depending on success + * @param int $id The metadata ID to delete. + * @return bool */ -function remove_metadata($entity_guid, $name, $value = "") { - global $CONFIG; - $entity_guid = (int) $entity_guid; - $name = sanitise_string($name); - $value = sanitise_string($value); - - $query = "SELECT * from {$CONFIG->dbprefix}metadata WHERE entity_guid = $entity_guid and name_id=" . add_metastring($name); - if ($value!="") { - $query .= " and value_id=" . add_metastring($value); - } - - if ($existing = get_data($query)) { - foreach($existing as $ex) { - delete_metadata($ex->id); - } - return true; +function elgg_delete_metadata_by_id($id) { + $metadata = elgg_get_metadata_from_id($id); + if (!$metadata) { + return false; } - - return false; + return $metadata->delete(); } /** * Create a new metadata object, or update an existing one. * - * @param int $entity_guid The entity to attach the metadata to - * @param string $name Name of the metadata - * @param string $value Value of the metadata (cannot be associative array) - * @param string $value_type - * @param int $owner_guid - * @param int $access_id - * @param bool $allow_multiple + * Metadata can be an array by setting allow_multiple to TRUE, but it is an + * indexed array with no control over the indexing. + * + * @param int $entity_guid The entity to attach the metadata to + * @param string $name Name of the metadata + * @param string $value Value of the metadata + * @param string $value_type 'text', 'integer', or '' for automatic detection + * @param int $owner_guid GUID of entity that owns the metadata + * @param int $access_id Default is ACCESS_PRIVATE + * @param bool $allow_multiple Allow multiple values for one key. Default is FALSE + * + * @return int|false id of metadata or FALSE if failure */ -function create_metadata($entity_guid, $name, $value, $value_type, $owner_guid, $access_id = ACCESS_PRIVATE, $allow_multiple = false) { +function create_metadata($entity_guid, $name, $value, $value_type = '', $owner_guid = 0, + $access_id = ACCESS_PRIVATE, $allow_multiple = false) { + global $CONFIG; $entity_guid = (int)$entity_guid; + // name and value are encoded in add_metastring() //$name = sanitise_string(trim($name)); //$value = sanitise_string(trim($value)); $value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type))); @@ -202,81 +80,85 @@ function create_metadata($entity_guid, $name, $value, $value_type, $owner_guid, $owner_guid = (int)$owner_guid; $allow_multiple = (boolean)$allow_multiple; - if ($owner_guid==0) { - $owner_guid = get_loggedin_userid(); + if (!isset($value)) { + return FALSE; + } + + if ($owner_guid == 0) { + $owner_guid = elgg_get_logged_in_user_guid(); } $access_id = (int)$access_id; - $id = false; + $query = "SELECT * from {$CONFIG->dbprefix}metadata" + . " WHERE entity_guid = $entity_guid and name_id=" . add_metastring($name) . " limit 1"; - $existing = get_data_row("SELECT * from {$CONFIG->dbprefix}metadata WHERE entity_guid = $entity_guid and name_id=" . add_metastring($name) . " limit 1"); - if (($existing) && (!$allow_multiple) && (isset($value))) { - $id = $existing->id; + $existing = get_data_row($query); + if ($existing && !$allow_multiple) { + $id = (int)$existing->id; $result = update_metadata($id, $name, $value, $value_type, $owner_guid, $access_id); if (!$result) { return false; } - } - else if (isset($value)) { + } else { // Support boolean types if (is_bool($value)) { - if ($value) { - $value = 1; - } else { - $value = 0; - } + $value = (int) $value; } // Add the metastrings - $value = add_metastring($value); - if (!$value) { + $value_id = add_metastring($value); + if (!$value_id) { return false; } - $name = add_metastring($name); - if (!$name) { + $name_id = add_metastring($name); + if (!$name_id) { return false; } // If ok then add it - $id = insert_data("INSERT into {$CONFIG->dbprefix}metadata (entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id) VALUES ($entity_guid, '$name','$value','$value_type', $owner_guid, $time, $access_id)"); + $query = "INSERT into {$CONFIG->dbprefix}metadata" + . " (entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id)" + . " VALUES ($entity_guid, '$name_id','$value_id','$value_type', $owner_guid, $time, $access_id)"; + + $id = insert_data($query); + + if ($id !== false) { + $obj = elgg_get_metadata_from_id($id); + if (elgg_trigger_event('create', 'metadata', $obj)) { - if ($id!==false) { - $obj = get_metadata($id); - if (trigger_elgg_event('create', 'metadata', $obj)) { - return true; + elgg_get_metadata_cache()->save($entity_guid, $name, $value, $allow_multiple); + + return $id; } else { - delete_metadata($id); + elgg_delete_metadata_by_id($id); } } - - } else if ($existing) { - // TODO: Check... are you sure you meant to do this Ben? :) - $id = $existing->id; - delete_metadata($id); } return $id; } /** - * Update an item of metadata. - * - * @param int $id - * @param string $name - * @param string $value - * @param string $value_type - * @param int $owner_guid - * @param int $access_id + * Update a specific piece of metadata. + * + * @param int $id ID of the metadata to update + * @param string $name Metadata name + * @param string $value Metadata value + * @param string $value_type Value type + * @param int $owner_guid Owner guid + * @param int $access_id Access ID + * + * @return bool */ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_id) { global $CONFIG; $id = (int)$id; - if (!$md = get_metadata($id)) { + if (!$md = elgg_get_metadata_from_id($id)) { return false; } if (!$md->canEdit()) { @@ -290,51 +172,50 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i } if ($metabyname_memcache) { + // @todo fix memcache (name_id is not a property of ElggMetadata) $metabyname_memcache->delete("{$md->entity_guid}:{$md->name_id}"); } - //$name = sanitise_string(trim($name)); - //$value = sanitise_string(trim($value)); $value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type))); $owner_guid = (int)$owner_guid; - if ($owner_guid==0) { - $owner_guid = get_loggedin_userid(); + if ($owner_guid == 0) { + $owner_guid = elgg_get_logged_in_user_guid(); } $access_id = (int)$access_id; - $access = get_access_sql_suffix(); - // Support boolean types (as integers) if (is_bool($value)) { - if ($value) { - $value = 1; - } else { - $value = 0; - } + $value = (int) $value; } // Add the metastring - $value = add_metastring($value); - if (!$value) { + $value_id = add_metastring($value); + if (!$value_id) { return false; } - $name = add_metastring($name); - if (!$name) { + $name_id = add_metastring($name); + if (!$name_id) { return false; } // If ok then add it - $result = update_data("UPDATE {$CONFIG->dbprefix}metadata set value_id='$value', value_type='$value_type', access_id=$access_id, owner_guid=$owner_guid where id=$id and name_id='$name'"); - if ($result!==false) { - $obj = get_metadata($id); - if (trigger_elgg_event('update', 'metadata', $obj)) { - return true; - } else { - delete_metadata($id); - } + $query = "UPDATE {$CONFIG->dbprefix}metadata" + . " set name_id='$name_id', value_id='$value_id', value_type='$value_type', access_id=$access_id," + . " owner_guid=$owner_guid where id=$id"; + + $result = update_data($query); + if ($result !== false) { + + elgg_get_metadata_cache()->save($md->entity_guid, $name, $value); + + // @todo this event tells you the metadata has been updated, but does not + // let you do anything about it. What is needed is a plugin hook before + // the update that passes old and new values. + $obj = elgg_get_metadata_from_id($id); + elgg_trigger_event('update', 'metadata', $obj); } return $result; @@ -343,16 +224,26 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i /** * This function creates metadata from an associative array of "key => value" pairs. * - * @param int $entity_guid - * @param string $name_and_values - * @param string $value_type - * @param int $owner_guid - * @param int $access_id - * @param bool $allow_multiple + * To achieve an array for a single key, pass in the same key multiple times with + * allow_multiple set to TRUE. This creates an indexed array. It does not support + * associative arrays and there is no guarantee on the ordering in the array. + * + * @param int $entity_guid The entity to attach the metadata to + * @param array $name_and_values Associative array - a value can be a string, number, bool + * @param string $value_type 'text', 'integer', or '' for automatic detection + * @param int $owner_guid GUID of entity that owns the metadata + * @param int $access_id Default is ACCESS_PRIVATE + * @param bool $allow_multiple Allow multiple values for one key. Default is FALSE + * + * @return bool */ -function create_metadata_from_array($entity_guid, array $name_and_values, $value_type, $owner_guid, $access_id = ACCESS_PRIVATE, $allow_multiple = false) { +function create_metadata_from_array($entity_guid, array $name_and_values, $value_type, $owner_guid, +$access_id = ACCESS_PRIVATE, $allow_multiple = false) { + foreach ($name_and_values as $k => $v) { - if (!create_metadata($entity_guid, $k, $v, $value_type, $owner_guid, $access_id, $allow_multiple)) { + $result = create_metadata($entity_guid, $k, $v, $value_type, $owner_guid, + $access_id, $allow_multiple); + if (!$result) { return false; } } @@ -360,289 +251,209 @@ function create_metadata_from_array($entity_guid, array $name_and_values, $value } /** - * Delete an item of metadata, where the current user has access. + * Returns metadata. Accepts all elgg_get_entities() options for entity + * restraints. + * + * @see elgg_get_entities * - * @param $id int The item of metadata to delete. + * @warning 1.7's find_metadata() didn't support limits and returned all metadata. + * This function defaults to a limit of 25. There is probably not a reason + * for you to return all metadata unless you're exporting an entity, + * have other restraints in place, or are doing something horribly + * wrong in your code. + * + * @param array $options Array in format: + * + * metadata_names => NULL|ARR metadata names + * metadata_values => NULL|ARR metadata values + * metadata_ids => NULL|ARR metadata ids + * metadata_case_sensitive => BOOL Overall Case sensitive + * metadata_owner_guids => NULL|ARR guids for metadata owners + * metadata_created_time_lower => INT Lower limit for created time. + * metadata_created_time_upper => INT Upper limit for created time. + * metadata_calculation => STR Perform the MySQL function on the metadata values returned. + * The "metadata_calculation" option causes this function to + * return the result of performing a mathematical calculation on + * all metadata that match the query instead of returning + * ElggMetadata objects. + * + * @return ElggMetadata[]|mixed + * @since 1.8.0 */ -function delete_metadata($id) { - global $CONFIG; - - $id = (int)$id; - $metadata = get_metadata($id); - - if ($metadata) { - // Tidy up if memcache is enabled. - static $metabyname_memcache; - if ((!$metabyname_memcache) && (is_memcache_available())) { - $metabyname_memcache = new ElggMemcache('metabyname_memcache'); - } - - if ($metabyname_memcache) { - $metabyname_memcache->delete("{$metadata->entity_guid}:{$metadata->name_id}"); - } +function elgg_get_metadata(array $options = array()) { - if (($metadata->canEdit()) && (trigger_elgg_event('delete', 'metadata', $metadata))) { - return delete_data("DELETE from {$CONFIG->dbprefix}metadata where id=$id"); - } + // @todo remove support for count shortcut - see #4393 + // support shortcut of 'count' => true for 'metadata_calculation' => 'count' + if (isset($options['count']) && $options['count']) { + $options['metadata_calculation'] = 'count'; + unset($options['count']); } - return false; + $options['metastring_type'] = 'metadata'; + return elgg_get_metastring_based_objects($options); } /** - * Return the metadata values that match your query. + * Deletes metadata based on $options. + * + * @warning Unlike elgg_get_metadata() this will not accept an empty options array! + * This requires at least one constraint: metadata_owner_guid(s), + * metadata_name(s), metadata_value(s), or guid(s) must be set. * - * @param string $meta_name - * @return mixed either a value, an array of ElggMetadata or false. + * @param array $options An options array. {@see elgg_get_metadata()} + * @return bool|null true on success, false on failure, null if no metadata to delete. + * @since 1.8.0 */ -function get_metadata_byname($entity_guid, $meta_name) { - global $CONFIG; - - $meta_name = get_metastring_id($meta_name); - - if (empty($meta_name)) { +function elgg_delete_metadata(array $options) { + if (!elgg_is_valid_options_for_batch_operation($options, 'metadata')) { return false; } + $options['metastring_type'] = 'metadata'; + $result = elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false); - $entity_guid = (int)$entity_guid; - $access = get_access_sql_suffix("e"); - $md_access = get_access_sql_suffix("m"); - - // If memcache is available then cache this (cache only by name for now since this is the most common query) - $meta = null; - static $metabyname_memcache; - if ((!$metabyname_memcache) && (is_memcache_available())) { - $metabyname_memcache = new ElggMemcache('metabyname_memcache'); - } - if ($metabyname_memcache) { - $meta = $metabyname_memcache->load("{$entity_guid}:{$meta_name}"); - } - if ($meta) { - return $meta; - } - - $result = get_data("SELECT m.*, n.string as name, v.string as value from {$CONFIG->dbprefix}metadata m JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.entity_guid JOIN {$CONFIG->dbprefix}metastrings v on m.value_id = v.id JOIN {$CONFIG->dbprefix}metastrings n on m.name_id = n.id where m.entity_guid=$entity_guid and m.name_id='$meta_name' and $access and $md_access ORDER BY m.id ASC", "row_to_elggmetadata"); - if (!$result) { - return false; - } - - // Cache if memcache available - if ($metabyname_memcache) { - if (count($result) == 1) { - $r = $result[0]; - } else { - $r = $result; - } - // This is a bit of a hack - we shorten the expiry on object - // metadata so that it'll be gone in an hour. This means that - // deletions and more importantly updates will filter through eventually. - $metabyname_memcache->setDefaultExpiry(3600); - $metabyname_memcache->save("{$entity_guid}:{$meta_name}", $r); - } - if (count($result) == 1) { - return $result[0]; - } + // This moved last in case an object's constructor sets metadata. Currently the batch + // delete process has to create the entity to delete its metadata. See #5214 + elgg_get_metadata_cache()->invalidateByOptions('delete', $options); return $result; } /** - * Return all the metadata for a given GUID. + * Disables metadata based on $options. + * + * @warning Unlike elgg_get_metadata() this will not accept an empty options array! * - * @param int $entity_guid + * @param array $options An options array. {@See elgg_get_metadata()} + * @return bool|null true on success, false on failure, null if no metadata disabled. + * @since 1.8.0 */ -function get_metadata_for_entity($entity_guid) { - global $CONFIG; +function elgg_disable_metadata(array $options) { + if (!elgg_is_valid_options_for_batch_operation($options, 'metadata')) { + return false; + } - $entity_guid = (int)$entity_guid; - $access = get_access_sql_suffix("e"); - $md_access = get_access_sql_suffix("m"); + elgg_get_metadata_cache()->invalidateByOptions('disable', $options); + + // if we can see hidden (disabled) we need to use the offset + // otherwise we risk an infinite loop if there are more than 50 + $inc_offset = access_get_show_hidden_status(); - return get_data("SELECT m.*, n.string as name, v.string as value from {$CONFIG->dbprefix}metadata m JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.entity_guid JOIN {$CONFIG->dbprefix}metastrings v on m.value_id = v.id JOIN {$CONFIG->dbprefix}metastrings n on m.name_id = n.id where m.entity_guid=$entity_guid and $access and $md_access", "row_to_elggmetadata"); + $options['metastring_type'] = 'metadata'; + return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset); } /** - * Get the metadata where the entities they are referring to match a given criteria. - * - * @param mixed $meta_name - * @param mixed $meta_value - * @param string $entity_type The type of entity to look for, eg 'site' or 'object' - * @param string $entity_subtype The subtype of the entity. - * @param int $limit - * @param int $offset - * @param string $order_by Optional ordering. - * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites. + * Enables metadata based on $options. + * + * @warning Unlike elgg_get_metadata() this will not accept an empty options array! + * + * @warning In order to enable metadata, you must first use + * {@link access_show_hidden_entities()}. + * + * @param array $options An options array. {@See elgg_get_metadata()} + * @return bool|null true on success, false on failure, null if no metadata enabled. + * @since 1.8.0 */ -function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $entity_subtype = "", $limit = 10, $offset = 0, $order_by = "", $site_guid = 0) { - global $CONFIG; - - $meta_n = get_metastring_id($meta_name); - $meta_v = get_metastring_id($meta_value); - - $entity_type = sanitise_string($entity_type); - $entity_subtype = get_subtype_id($entity_type, $entity_subtype); - $limit = (int)$limit; - $offset = (int)$offset; - if ($order_by == "") { - $order_by = "e.time_created desc"; - } - - $order_by = sanitise_string($order_by); - $site_guid = (int) $site_guid; - if ($site_guid == 0) { - $site_guid = $CONFIG->site_guid; - } - - $where = array(); - - if ($entity_type!="") { - $where[] = "e.type='$entity_type'"; - } - - if ($entity_subtype) { - $where[] = "e.subtype=$entity_subtype"; - } - - if ($meta_name!="") { - if (!$meta_v) { - // The value is set, but we didn't get a value... so something went wrong. - return false; - } - $where[] = "m.name_id='$meta_n'"; - } - if ($meta_value!="") { - // The value is set, but we didn't get a value... so something went wrong. - if (!$meta_v) { - return false; - } - $where[] = "m.value_id='$meta_v'"; - } - if ($site_guid > 0) { - $where[] = "e.site_guid = {$site_guid}"; +function elgg_enable_metadata(array $options) { + if (!$options || !is_array($options)) { + return false; } - $query = "SELECT m.*, n.string as name, v.string as value from {$CONFIG->dbprefix}entities e JOIN {$CONFIG->dbprefix}metadata m on e.guid = m.entity_guid JOIN {$CONFIG->dbprefix}metastrings v on m.value_id = v.id JOIN {$CONFIG->dbprefix}metastrings n on m.name_id = n.id where"; - foreach ($where as $w) { - $query .= " $w and "; - } - $query .= get_access_sql_suffix("e"); // Add access controls - $query .= ' and ' . get_access_sql_suffix("m"); // Add access controls - $query .= " order by $order_by limit $offset, $limit"; // Add order and limit + elgg_get_metadata_cache()->invalidateByOptions('enable', $options); - return get_data($query, "row_to_elggmetadata"); + $options['metastring_type'] = 'metadata'; + return elgg_batch_metastring_based_objects($options, 'elgg_batch_enable_callback'); } /** + * ElggEntities interfaces + */ + +/** * Returns entities based upon metadata. Also accepts all * options available to elgg_get_entities(). Supports * the singular option shortcut. * - * NB: Using metadata_names and metadata_values results in a + * @note Using metadata_names and metadata_values results in a * "names IN (...) AND values IN (...)" clause. This is subtly * differently than default multiple metadata_name_value_pairs, which use * "(name = value) AND (name = value)" clauses. * * When in doubt, use name_value_pairs. * + * To ask for entities that do not have a metadata value, use a custom + * where clause like this: + * + * $options['wheres'][] = "NOT EXISTS ( + * SELECT 1 FROM {$dbprefix}metadata md + * WHERE md.entity_guid = e.guid + * AND md.name_id = $name_metastring_id + * AND md.value_id = $value_metastring_id)"; + * + * Note the metadata name and value has been denormalized in the above example. + * * @see elgg_get_entities - * @see elgg_get_entities_from_annotations + * * @param array $options Array in format: * * metadata_names => NULL|ARR metadata names * * metadata_values => NULL|ARR metadata values * - * metadata_name_value_pairs => NULL|ARR (name => 'name', value => 'value', 'operand' => '=', 'case_sensitive' => TRUE) entries. - * Currently if multiple values are sent via an array (value => array('value1', 'value2') the pair's operand will be forced to "IN". - * - * metadata_name_value_pairs_operator => NULL|STR The operator to use for combining (name = value) OPERATOR (name = value); default AND + * metadata_name_value_pairs => NULL|ARR ( + * name => 'name', + * value => 'value', + * 'operand' => '=', + * 'case_sensitive' => TRUE + * ) + * Currently if multiple values are sent via + * an array (value => array('value1', 'value2') + * the pair's operand will be forced to "IN". + * If passing "IN" as the operand and a string as the value, + * the value must be a properly quoted and escaped string. + * + * metadata_name_value_pairs_operator => NULL|STR The operator to use for combining + * (name = value) OPERATOR (name = value); default AND * * metadata_case_sensitive => BOOL Overall Case sensitive * - * order_by_metadata => NULL|ARR (array('name' => 'metadata_text1', 'direction' => ASC|DESC, 'as' => text|integer), - * Also supports array('name' => 'metadata_text1') + * order_by_metadata => NULL|ARR array( + * 'name' => 'metadata_text1', + * 'direction' => ASC|DESC, + * 'as' => text|integer + * ) + * Also supports array('name' => 'metadata_text1') * * metadata_owner_guids => NULL|ARR guids for metadata owners * - * @return array + * @return ElggEntity[]|mixed If count, int. If not count, array. false on errors. + * @since 1.7.0 */ function elgg_get_entities_from_metadata(array $options = array()) { $defaults = array( - 'metadata_names' => ELGG_ENTITIES_ANY_VALUE, - 'metadata_values' => ELGG_ENTITIES_ANY_VALUE, - 'metadata_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, + 'metadata_names' => ELGG_ENTITIES_ANY_VALUE, + 'metadata_values' => ELGG_ENTITIES_ANY_VALUE, + 'metadata_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE, - 'metadata_name_value_pairs_operator'=> 'AND', - 'metadata_case_sensitive' => TRUE, - 'order_by_metadata' => array(), + 'metadata_name_value_pairs_operator' => 'AND', + 'metadata_case_sensitive' => TRUE, + 'order_by_metadata' => array(), - 'metadata_owner_guids' => ELGG_ENTITIES_ANY_VALUE, + 'metadata_owner_guids' => ELGG_ENTITIES_ANY_VALUE, ); $options = array_merge($defaults, $options); - if (!$options = elgg_entities_get_metastrings_options('metadata', $options)) { - return FALSE; - } - - return elgg_get_entities($options); -} - -/** - * Returns options to pass to elgg_get_entities() for metastrings operations. - * - * @param string $type Metastring type: annotations or metadata - * @param array $options Options - * - * @return array - */ -function elgg_entities_get_metastrings_options($type, $options) { - $valid_types = array('metadata', 'annotation'); - if (!in_array($type, $valid_types)) { - return FALSE; - } - - // the options for annotations are singular (annotation_name) but the table - // is plural (elgg_annotations) so rewrite for the table name. - $n_table = ($type == 'annotation') ? 'annotations' : $type; + $singulars = array('metadata_name', 'metadata_value', + 'metadata_name_value_pair', 'metadata_owner_guid'); - $singulars = array("{$type}_name", "{$type}_value", "{$type}_name_value_pair", "{$type}_owner_guid"); $options = elgg_normalise_plural_options_array($options, $singulars); - $clauses = elgg_get_entity_metadata_where_sql('e', $n_table, $options["{$type}_names"], $options["{$type}_values"], - $options["{$type}_name_value_pairs"], $options["{$type}_name_value_pairs_operator"], $options["{$type}_case_sensitive"], - $options["order_by_{$type}"], $options["{$type}_owner_guids"]); - - if ($clauses) { - // merge wheres to pass to get_entities() - if (isset($options['wheres']) && !is_array($options['wheres'])) { - $options['wheres'] = array($options['wheres']); - } elseif (!isset($options['wheres'])) { - $options['wheres'] = array(); - } - - $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']); - - // merge joins to pass to get_entities() - if (isset($options['joins']) && !is_array($options['joins'])) { - $options['joins'] = array($options['joins']); - } elseif (!isset($options['joins'])) { - $options['joins'] = array(); - } - - $options['joins'] = array_merge($options['joins'], $clauses['joins']); - - if ($clauses['orders']) { - $order_by_metadata = implode(", ",$clauses['orders']); - if (isset($options['order_by']) && $options['order_by']) { - $options['order_by'] = "$order_by_metadata, {$options['order_by']}"; - } else { - $options['order_by'] = "$order_by_metadata, e.time_created DESC"; - } - } + if (!$options = elgg_entities_get_metastrings_options('metadata', $options)) { + return FALSE; } - return $options; + return elgg_get_entities($options); } /** @@ -653,17 +464,25 @@ function elgg_entities_get_metastrings_options($type, $options) { * This function is reused for annotations because the tables are * exactly the same. * - * @param string $e_table Entities table name - * @param string $n_table Normalized metastrings table name (Where entities, values, and names are joined. annotations / metadata) - * @param ARR|NULL $names - * @param ARR|NULL $values - * @param ARR|NULL $pairs array of names / values / operands - * @param AND|OR $pair_operator Operator to use to join the where clauses for pairs - * @param BOOL $case_sensitive - * @param ARR|NULL $order_by_metadata array of names / direction - * @return FALSE|array False on fail, array('joins', 'wheres') + * @param string $e_table Entities table name + * @param string $n_table Normalized metastrings table name (Where entities, + * values, and names are joined. annotations / metadata) + * @param array|null $names Array of names + * @param array|null $values Array of values + * @param array|null $pairs Array of names / values / operands + * @param string $pair_operator ("AND" or "OR") Operator to use to join the where clauses for pairs + * @param bool $case_sensitive Case sensitive metadata names? + * @param array|null $order_by_metadata Array of names / direction + * @param array|null $owner_guids Array of owner GUIDs + * + * @return false|array False on fail, array('joins', 'wheres') + * @since 1.7.0 + * @access private */ -function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $values = NULL, $pairs = NULL, $pair_operator = 'AND', $case_sensitive = TRUE, $order_by_metadata = NULL, $owner_guids = NULL) { +function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $values = NULL, +$pairs = NULL, $pair_operator = 'AND', $case_sensitive = TRUE, $order_by_metadata = NULL, +$owner_guids = NULL) { + global $CONFIG; // short circuit if nothing requested @@ -674,7 +493,7 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $ && (!$values && $values !== 0) && (!$pairs && $pairs !== 0) && (!$owner_guids && $owner_guids !== 0) - && !isset($order_by_metadata)) { + && !$order_by_metadata) { return ''; } @@ -695,7 +514,8 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $ ); // will always want to join these tables if pulling metastrings. - $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table on {$e_table}.guid = n_table.entity_guid"; + $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table on + {$e_table}.guid = n_table.entity_guid"; $wheres = array(); @@ -802,6 +622,8 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $ // if the operand is IN don't quote it because quoting should be done already. if (is_numeric($pair['value'])) { $value = sanitise_string($pair['value']); + } else if (is_bool($pair['value'])) { + $value = (int) $pair['value']; } else if (is_array($pair['value'])) { $values_array = array(); @@ -829,16 +651,20 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $ $name = sanitise_string($pair['name']); // @todo The multiple joins are only needed when the operator is AND - $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i} on {$e_table}.guid = n_table{$i}.entity_guid"; - $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} on n_table{$i}.name_id = msn{$i}.id"; - $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} on n_table{$i}.value_id = msv{$i}.id"; + $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i} + on {$e_table}.guid = n_table{$i}.entity_guid"; + $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} + on n_table{$i}.name_id = msn{$i}.id"; + $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} + on n_table{$i}.value_id = msv{$i}.id"; - $pair_wheres[] = "(msn{$i}.string = '$name' AND {$pair_binary}msv{$i}.string $operand $value AND $access)"; + $pair_wheres[] = "(msn{$i}.string = '$name' AND {$pair_binary}msv{$i}.string + $operand $value AND $access)"; $i++; } - if ($where = implode (" $pair_operator ", $pair_wheres)) { + if ($where = implode(" $pair_operator ", $pair_wheres)) { $wheres[] = "($where)"; } } @@ -860,7 +686,7 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $ } if (is_array($order_by_metadata)) { - if ((count($order_by_metadata) > 0) && !is_array($order_by_metadata[0])) { + if ((count($order_by_metadata) > 0) && !isset($order_by_metadata[0])) { // singleton, so fix $order_by_metadata = array($order_by_metadata); } @@ -872,9 +698,12 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $ } else { $direction = 'ASC'; } - $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i} on {$e_table}.guid = n_table{$i}.entity_guid"; - $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} on n_table{$i}.name_id = msn{$i}.id"; - $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} on n_table{$i}.value_id = msv{$i}.id"; + $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i} + on {$e_table}.guid = n_table{$i}.entity_guid"; + $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} + on n_table{$i}.name_id = msn{$i}.id"; + $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} + on n_table{$i}.value_id = msv{$i}.id"; $access = get_access_sql_suffix("n_table{$i}"); @@ -893,272 +722,35 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $ } /** - * Return a list of entities based on the given search criteria. - * - * @deprecated 1.7 use elgg_get_entities_from_metadata(). - * @param mixed $meta_name - * @param mixed $meta_value - * @param string $entity_type The type of entity to look for, eg 'site' or 'object' - * @param string $entity_subtype The subtype of the entity. - * @param int $limit - * @param int $offset - * @param string $order_by Optional ordering. - * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites. - * @param true|false $count If set to true, returns the total number of entities rather than a list. (Default: false) - * @param true|false $case_sensitive If set to false this searches for the meta data without case sensitivity. (Default: true) - * - * @return int|array A list of entities, or a count if $count is set to true - */ -function get_entities_from_metadata($meta_name, $meta_value = "", $entity_type = "", $entity_subtype = "", -$owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, -$count = FALSE, $case_sensitive = TRUE) { - - elgg_deprecated_notice('get_entities_from_metadata() was deprecated by elgg_get_entities_from_metadata()!', 1.7); - - $options = array(); - - $options['metadata_names'] = $meta_name; - - if ($meta_value) { - $options['metadata_values'] = $meta_value; - } - - if ($entity_type) { - $options['types'] = $entity_type; - } - - if ($entity_subtype) { - $options['subtypes'] = $entity_subtype; - } - - if ($owner_guid) { - $options['owner_guid'] = $owner_guid; - } - - if ($limit) { - $options['limit'] = $limit; - } - - if ($offset) { - $options['offset'] = $offset; - } - - if ($order_by) { - $options['order_by']; - } - - if ($site_guid) { - $options['site_guid']; - } - - if ($count) { - $options['count'] = $count; - } - - // need to be able to pass false - $options['metadata_case_sensitive'] = $case_sensitive; - - return elgg_get_entities_from_metadata($options); -} - -/** - * Return a list of entities suitable for display based on the given search criteria. - * - * @see elgg_view_entity_list - * - * @deprecated 1.8 Use elgg_list_entities_from_metadata - * @param mixed $meta_name Metadata name to search on - * @param mixed $meta_value The value to match, optionally - * @param string $entity_type The type of entity to look for, eg 'site' or 'object' - * @param string $entity_subtype The subtype of the entity - * @param int $limit Number of entities to display per page - * @param true|false $fullview Whether or not to display the full view (default: true) - * @param true|false $viewtypetoggle Whether or not to allow users to toggle to the gallery view. Default: true - * @param true|false $pagination Display pagination? Default: true - * - * @return string A list of entities suitable for display - */ -function list_entities_from_metadata($meta_name, $meta_value = "", $entity_type = ELGG_ENTITIES_ANY_VALUE, $entity_subtype = ELGG_ENTITIES_ANY_VALUE, $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = true, $pagination = true, $case_sensitive = true ) { - elgg_deprecated_notice('get_entities_from_metadata_multi() was deprecated by elgg_get_entities_from_metadata()!', 1.8); - - $offset = (int) get_input('offset'); - $limit = (int) $limit; - $options = array( - 'metadata_name' => $meta_name, - 'metadata_value' => $meta_value, - 'types' => $entity_type, - 'subtypes' => $entity_subtype, - 'owner_guid' => $owner_guid, - 'limit' => $limit, - 'offset' => $offset, - 'count' => TRUE, - 'metadata_case_sensitive' => $case_sensitive - ); - $count = elgg_get_entities_from_metadata($options); - - $options['count'] = FALSE; - $entities = elgg_get_entities_from_metadata($options); - - return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination); -} - -/** * Returns a list of entities filtered by provided metadata. * * @see elgg_get_entities_from_metadata * - * @param array $options + * @param array $options Options array + * + * @return array + * @since 1.7.0 */ function elgg_list_entities_from_metadata($options) { - $defaults = array( - 'offset' => (int) max(get_input('offset', 0), 0), - 'limit' => (int) max(get_input('limit', 10), 0), - 'full_view' => TRUE, - 'view_type_toggle' => FALSE, - 'pagination' => TRUE - ); - - $options = array_merge($defaults, $options); - - $count = elgg_get_entities_from_metadata(array_merge(array('count' => TRUE), $options)); - $entities = elgg_get_entities_from_metadata($options); - - return elgg_view_entity_list($entities, $count, $options['offset'], $options['limit'], $options['full_view'], $options['view_type_toggle'], $options['pagination']); + return elgg_list_entities($options, 'elgg_get_entities_from_metadata'); } /** - * @deprecated 1.7. Use elgg_get_entities_from_metadata(). - * @param $meta_array - * @param $entity_type - * @param $entity_subtype - * @param $owner_guid - * @param $limit - * @param $offset - * @param $order_by - * @param $site_guid - * @param $count - * @param $meta_array_operator - * @return unknown_type + * Other functions */ -function get_entities_from_metadata_multi($meta_array, $entity_type = "", $entity_subtype = "", -$owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, -$count = false, $meta_array_operator = 'and') { - elgg_deprecated_notice('get_entities_from_metadata_multi() was deprecated by elgg_get_entities_from_metadata()!', 1.7); - - if (!is_array($meta_array) || sizeof($meta_array) == 0) { - return false; - } - - $options = array(); - - $options['metadata_name_value_pairs'] = $meta_array; - - if ($entity_type) { - $options['types'] = $entity_type; - } - - if ($entity_subtype) { - $options['subtypes'] = $entity_subtype; - } - - if ($owner_guid) { - $options['owner_guid'] = $owner_guid; - } - - if ($limit) { - $options['limit'] = $limit; - } - - if ($offset) { - $options['offset'] = $offset; - } - - if ($order_by) { - $options['order_by']; - } - - if ($site_guid) { - $options['site_guid']; - } - - if ($count) { - $options['count'] = $count; - } - - $options['metadata_name_value_pairs_operator'] = $meta_array_operator; - - return elgg_get_entities_from_metadata($options); -} - -/** - * Returns a viewable list of entities based on the given search criteria. - * - * @see elgg_view_entity_list - * - * @param array $meta_array Array of 'name' => 'value' pairs - * @param string $entity_type The type of entity to look for, eg 'site' or 'object' - * @param string $entity_subtype The subtype of the entity. - * @param int $limit - * @param int $offset - * @param string $order_by Optional ordering. - * @param true|false $fullview Whether or not to display the full view (default: true) - * @param true|false $viewtypetoggle Whether or not to allow users to toggle to the gallery view. Default: true - * @param true|false $pagination Display pagination? Default: true - * @return string List of ElggEntities suitable for display - */ -function list_entities_from_metadata_multi($meta_array, $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = true, $pagination = true) { - $offset = (int) get_input('offset'); - $limit = (int) $limit; - $count = get_entities_from_metadata_multi($meta_array, $entity_type, $entity_subtype, $owner_guid, $limit, $offset, "", $site_guid, true); - $entities = get_entities_from_metadata_multi($meta_array, $entity_type, $entity_subtype, $owner_guid, $limit, $offset, "", $site_guid, false); - - return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination); -} /** - * Clear all the metadata for a given entity, assuming you have access to that metadata. + * Handler called by trigger_plugin_hook on the "export" event. * - * @param int $guid - */ -function clear_metadata($entity_guid) { - global $CONFIG; - - $entity_guid = (int)$entity_guid; - if ($entity = get_entity($entity_guid)) { - if ($entity->canEdit()) { - return delete_data("DELETE from {$CONFIG->dbprefix}metadata where entity_guid={$entity_guid}"); - } - } - return false; -} - -/** - * Clear all annotations belonging to a given owner_guid + * @param string $hook export + * @param string $entity_type all + * @param mixed $returnvalue Value returned from previous hook + * @param mixed $params Params * - * @param int $owner_guid The owner - */ -function clear_metadata_by_owner($owner_guid) { - global $CONFIG; - - $owner_guid = (int)$owner_guid; - - $metas = get_data("SELECT id from {$CONFIG->dbprefix}metadata WHERE owner_guid=$owner_guid"); - $deleted = 0; - - if (is_array($metas)) { - foreach ($metas as $id) { - // Is this the best way? - if (delete_metadata($id->id)) { - $deleted++; - } - } - } - - return $deleted; -} - -/** - * Handler called by trigger_plugin_hook on the "export" event. + * @return array + * @access private + * + * @throws InvalidParameterException */ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params) { // Sanity check values @@ -1170,12 +762,13 @@ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params) throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonArrayReturnValue')); } - $guid = (int)$params['guid']; - $name = $params['name']; - - $result = get_metadata_for_entity($guid); + $result = elgg_get_metadata(array( + 'guid' => (int)$params['guid'], + 'limit' => 0, + )); if ($result) { + /* @var ElggMetadata[] $result */ foreach ($result as $r) { $returnvalue[] = $r->export(); } @@ -1185,34 +778,37 @@ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params) } /** - * Takes in a comma-separated string and returns an array of tags which have been trimmed and set to lower case + * Takes in a comma-separated string and returns an array of tags + * which have been trimmed * * @param string $string Comma-separated tag string + * * @return array|false An array of strings, or false on failure */ function string_to_tag_array($string) { if (is_string($string)) { - $ar = explode(",",$string); - $ar = array_map('trim', $ar); // trim blank spaces - $ar = array_map('elgg_strtolower', $ar); // make lower case : [Marcus Povey 20090605 - Using mb wrapper function using UTF8 safe function where available] - $ar = array_filter($ar, 'is_not_null'); // Remove null values + $ar = explode(",", $string); + $ar = array_map('trim', $ar); + $ar = array_filter($ar, 'is_not_null'); + $ar = array_map('strip_tags', $ar); return $ar; } return false; - } /** - * Takes a metadata array (which has all kinds of properties) and turns it into a simple array of strings + * Takes a metadata array (which has all kinds of properties) + * and turns it into a simple array of strings * * @param array $array Metadata array + * * @return array Array of strings */ function metadata_array_to_values($array) { $valuearray = array(); if (is_array($array)) { - foreach($array as $element) { + foreach ($array as $element) { $valuearray[] = $element->value; } } @@ -1221,14 +817,18 @@ function metadata_array_to_values($array) { } /** - * Get the URL for this item of metadata, by default this links to the export handler in the current view. + * Get the URL for this metadata + * + * By default this links to the export handler in the current view. * - * @param int $id + * @param int $id Metadata ID + * + * @return mixed */ function get_metadata_url($id) { $id = (int)$id; - if ($extender = get_metadata($id)) { + if ($extender = elgg_get_metadata_from_id($id)) { return get_extender_url($extender); } return false; @@ -1238,8 +838,10 @@ function get_metadata_url($id) { * Mark entities with a particular type and subtype as having access permissions * that can be changed independently from their parent entity * - * @param string $type The type - object, user, etc + * @param string $type The type - object, user, etc * @param string $subtype The subtype; all subtypes by default + * + * @return void */ function register_metadata_as_independent($type, $subtype = '*') { global $CONFIG; @@ -1253,9 +855,10 @@ function register_metadata_as_independent($type, $subtype = '*') { * Determines whether entities of a given type and subtype should not change * their metadata in line with their parent entity * - * @param string $type The type - object, user, etc + * @param string $type The type - object, user, etc * @param string $subtype The entity subtype - * @return true|false + * + * @return bool */ function is_metadata_independent($type, $subtype) { global $CONFIG; @@ -1272,17 +875,20 @@ function is_metadata_independent($type, $subtype) { /** * When an entity is updated, resets the access ID on all of its child metadata * - * @param string $event The name of the event - * @param string $object_type The type of object - * @param ElggEntity $object The entity itself + * @param string $event The name of the event + * @param string $object_type The type of object + * @param ElggEntity $object The entity itself + * + * @return true */ function metadata_update($event, $object_type, $object) { if ($object instanceof ElggEntity) { if (!is_metadata_independent($object->getType(), $object->getSubtype())) { - global $CONFIG; + $db_prefix = elgg_get_config('dbprefix'); $access_id = (int) $object->access_id; $guid = (int) $object->getGUID(); - update_data("update {$CONFIG->dbprefix}metadata set access_id = {$access_id} where entity_guid = {$guid}"); + $query = "update {$db_prefix}metadata set access_id = {$access_id} where entity_guid = {$guid}"; + update_data($query); } } return true; @@ -1291,22 +897,82 @@ function metadata_update($event, $object_type, $object) { /** * Register a metadata url handler. * - * @param string $function_name The function. * @param string $extender_name The name, default 'all'. + * @param string $function The function name. + * + * @return bool */ -function register_metadata_url_handler($function_name, $extender_name = "all") { - return register_extender_url_handler($function_name, 'metadata', $extender_name); +function elgg_register_metadata_url_handler($extender_name, $function) { + return elgg_register_extender_url_handler('metadata', $extender_name, $function); +} + +/** + * Get the global metadata cache instance + * + * @return ElggVolatileMetadataCache + * + * @access private + */ +function elgg_get_metadata_cache() { + global $CONFIG; + if (empty($CONFIG->local_metadata_cache)) { + $CONFIG->local_metadata_cache = new ElggVolatileMetadataCache(); + } + return $CONFIG->local_metadata_cache; +} + +/** + * Invalidate the metadata cache based on options passed to various *_metadata functions + * + * @param string $action Action performed on metadata. "delete", "disable", or "enable" + * @param array $options Options passed to elgg_(delete|disable|enable)_metadata + * @return void + */ +function elgg_invalidate_metadata_cache($action, array $options) { + // remove as little as possible, optimizing for common cases + $cache = elgg_get_metadata_cache(); + if (empty($options['guid'])) { + // safest to clear everything unless we want to make this even more complex :( + $cache->flush(); + } else { + if (empty($options['metadata_name'])) { + // safest to clear the whole entity + $cache->clear($options['guid']); + } else { + switch ($action) { + case 'delete': + $cache->markEmpty($options['guid'], $options['metadata_name']); + break; + default: + $cache->markUnknown($options['guid'], $options['metadata_name']); + } + } + } } /** Register the hook */ -register_plugin_hook("export", "all", "export_metadata_plugin_hook", 2); +elgg_register_plugin_hook_handler("export", "all", "export_metadata_plugin_hook", 2); + /** Call a function whenever an entity is updated **/ -register_elgg_event_handler('update','all','metadata_update'); +elgg_register_event_handler('update', 'all', 'metadata_update'); // unit testing -register_plugin_hook('unit_test', 'system', 'metadata_test'); +elgg_register_plugin_hook_handler('unit_test', 'system', 'metadata_test'); + +/** + * Metadata unit test + * + * @param string $hook unit_test + * @param string $type system + * @param mixed $value Array of other tests + * @param mixed $params Params + * + * @return array + * @access private + */ function metadata_test($hook, $type, $value, $params) { global $CONFIG; - $value[] = $CONFIG->path . 'engine/tests/objects/metadata.php'; + $value[] = $CONFIG->path . 'engine/tests/api/metadata.php'; + $value[] = $CONFIG->path . 'engine/tests/api/metadata_cache.php'; return $value; } |
