aboutsummaryrefslogtreecommitdiff
path: root/engine/lib/metadata.php
diff options
context:
space:
mode:
Diffstat (limited to 'engine/lib/metadata.php')
-rw-r--r--engine/lib/metadata.php873
1 files changed, 236 insertions, 637 deletions
diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php
index c15a163b7..fdb1b85f6 100644
--- a/engine/lib/metadata.php
+++ b/engine/lib/metadata.php
@@ -12,7 +12,8 @@
*
* @param stdClass $row An object from the database
*
- * @return stdClass or ElggMetadata
+ * @return stdClass|ElggMetadata
+ * @access private
*/
function row_to_elggmetadata($row) {
if (!($row instanceof stdClass)) {
@@ -23,64 +24,30 @@ function row_to_elggmetadata($row) {
}
/**
- * Get a specific metadata object.
+ * Get a specific metadata object by its id.
+ * If you want multiple metadata objects, use
+ * {@link elgg_get_metadata()}.
*
- * @param int $id The id of the metadata being retrieved.
+ * @param int $id The id of the metadata object being retrieved.
*
- * @return mixed False on failure or ElggMetadata
+ * @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");
-
- $query = "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";
-
-
- return row_to_elggmetadata(get_data_row($query));
+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.
- *
- * @param int $entity_guid The entity GUID
- * @param string $name The name of the metadata
- * @param string $value The value of the metadata (useful to remove a single item of a set)
+ * Deletes metadata using its ID.
*
- * @return bool 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_id = get_metastring_id($name);
- if ($name_id === FALSE) {
- // name doesn't exist
- return FALSE;
- }
-
- $query = "SELECT * from {$CONFIG->dbprefix}metadata WHERE entity_guid = '$entity_guid' and name_id = '$name_id'";
- if ($value != "") {
- $value_id = get_metastring_id($value);
- if ($value_id !== FALSE) {
- $query .= " AND value_id = '$value_id'";
- }
- }
-
- 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();
}
/**
@@ -97,9 +64,9 @@ function remove_metadata($entity_guid, $name, $value = "") {
* @param int $access_id Default is ACCESS_PRIVATE
* @param bool $allow_multiple Allow multiple values for one key. Default is FALSE
*
- * @return int/bool id of metadata or FALSE if failure
+ * @return int|false id of metadata or FALSE if failure
*/
-function create_metadata($entity_guid, $name, $value, $value_type, $owner_guid,
+function create_metadata($entity_guid, $name, $value, $value_type = '', $owner_guid = 0,
$access_id = ACCESS_PRIVATE, $allow_multiple = false) {
global $CONFIG;
@@ -118,13 +85,11 @@ function create_metadata($entity_guid, $name, $value, $value_type, $owner_guid,
}
if ($owner_guid == 0) {
- $owner_guid = get_loggedin_userid();
+ $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";
@@ -139,37 +104,36 @@ function create_metadata($entity_guid, $name, $value, $value_type, $owner_guid,
} 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
$query = "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)";
+ . " VALUES ($entity_guid, '$name_id','$value_id','$value_type', $owner_guid, $time, $access_id)";
$id = insert_data($query);
if ($id !== false) {
- $obj = get_metadata($id);
+ $obj = elgg_get_metadata_from_id($id);
if (elgg_trigger_event('create', 'metadata', $obj)) {
+
+ elgg_get_metadata_cache()->save($entity_guid, $name, $value, $allow_multiple);
+
return $id;
} else {
- delete_metadata($id);
+ elgg_delete_metadata_by_id($id);
}
}
}
@@ -180,7 +144,7 @@ function create_metadata($entity_guid, $name, $value, $value_type, $owner_guid,
/**
* Update a specific piece of metadata.
*
- * @param int $id Metadata id
+ * @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
@@ -194,7 +158,7 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i
$id = (int)$id;
- if (!$md = get_metadata($id)) {
+ if (!$md = elgg_get_metadata_from_id($id)) {
return false;
}
if (!$md->canEdit()) {
@@ -208,6 +172,7 @@ 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}");
}
@@ -215,46 +180,42 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i
$owner_guid = (int)$owner_guid;
if ($owner_guid == 0) {
- $owner_guid = get_loggedin_userid();
+ $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
$query = "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'";
+ . " 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) {
- $obj = get_metadata($id);
- if (elgg_trigger_event('update', 'metadata', $obj)) {
- return true;
- } else {
- delete_metadata($id);
- }
+
+ 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;
@@ -268,7 +229,7 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i
* 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 string $name_and_values Associative array - a value can be a string, number, bool
+ * @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
@@ -290,222 +251,148 @@ $access_id = ACCESS_PRIVATE, $allow_multiple = false) {
}
/**
- * Delete a piece of metadata, where the current user has access.
+ * Returns metadata. Accepts all elgg_get_entities() options for entity
+ * restraints.
+ *
+ * @see elgg_get_entities
*
- * @param int $id The id 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.
*
- * @return bool
+ * @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()) && (elgg_trigger_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);
}
/**
- * Get metadata objects by name.
+ * Deletes metadata based on $options.
*
- * @param int $entity_guid Entity GUID
- * @param string $meta_name Metadata name
+ * @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.
*
- * @return mixed ElggMetadata object, 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)) {
- return 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;
- }
-
- $query = "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" ;
-
- $result = get_data($query, "row_to_elggmetadata");
-
- if (!$result) {
+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);
- // 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.
*
- * @param int $entity_guid Entity GUID
+ * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
*
- * @return mixed
+ * @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;
-
- $entity_guid = (int)$entity_guid;
- $access = get_access_sql_suffix("e");
- $md_access = get_access_sql_suffix("m");
+function elgg_disable_metadata(array $options) {
+ if (!elgg_is_valid_options_for_batch_operation($options, 'metadata')) {
+ return false;
+ }
- $query = "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";
+ 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($query, "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.
+ * Enables metadata based on $options.
*
- * @param mixed $meta_name Metadata name
- * @param mixed $meta_value Metadata 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 Limit
- * @param int $offset Offset
- * @param string $order_by Optional ordering.
- * @param int $site_guid Site GUID. 0 for current, -1 for any
+ * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
*
- * @return mixed
+ * @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:
*
@@ -519,9 +406,11 @@ function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $en
* 'operand' => '=',
* 'case_sensitive' => TRUE
* )
- * Currently if multiple values are sent via
+ * 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
@@ -537,20 +426,20 @@ function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $en
*
* 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);
@@ -568,66 +457,6 @@ function elgg_get_entities_from_metadata(array $options = array()) {
}
/**
- * 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
- * @since 1.7.0
- */
-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("{$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";
- }
- }
- }
-
- return $options;
-}
-
-/**
* Returns metadata name and value SQL where for entities.
* NB: $names and $values are not paired. Use $pairs for this.
* Pairs default to '=' operand.
@@ -635,19 +464,20 @@ 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,
+ * @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 Array of names
- * @param arr|null $values Array of 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 Case sensitive metadata names?
- * @param arr|null $order_by_metadata Array of names / direction
- * @param arr|null $owner_guids Array of owner GUIDs
- *
- * @return FALSE|array False on fail, array('joins', 'wheres')
+ * @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,
@@ -792,6 +622,8 @@ $owner_guids = 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();
@@ -832,7 +664,7 @@ $owner_guids = NULL) {
$i++;
}
- if ($where = implode (" $pair_operator ", $pair_wheres)) {
+ if ($where = implode(" $pair_operator ", $pair_wheres)) {
$wheres[] = "($where)";
}
}
@@ -854,7 +686,7 @@ $owner_guids = 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);
}
@@ -890,132 +722,6 @@ $owner_guids = 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 Metadat name
- * @param mixed $meta_value Metadata 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 $owner_guid Owner GUID
- * @param int $limit Limit
- * @param int $offset Offset
- * @param string $order_by Optional ordering.
- * @param int $site_guid Site GUID. 0 for current, -1 for any.
- * @param bool $count Return a count instead of entities
- * @param bool $case_sensitive Metadata names case sensitivity
- *
- * @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) {
- if (is_array($owner_guid)) {
- $options['owner_guids'] = $owner_guid;
- } else {
- $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 $owner_guid Owner GUID
- * @param int $limit Number of entities to display per page
- * @param bool $fullview WDisplay the full view (default: true)
- * @param bool $listtypetoggle Allow users to toggle to the gallery view. Default: true
- * @param bool $pagination Display pagination? Default: true
- * @param bool $case_sensitive Case sensitive metadata names?
- *
- * @return string
- *
- * @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, $listtypetoggle = true,
-$pagination = true, $case_sensitive = true) {
-
- elgg_deprecated_notice('list_entities_from_metadata() was deprecated by elgg_list_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, $listtypetoggle, $pagination);
-}
-
-/**
* Returns a list of entities filtered by provided metadata.
*
* @see elgg_get_entities_from_metadata
@@ -1030,160 +736,8 @@ function elgg_list_entities_from_metadata($options) {
}
/**
- * Return entities from metadata
- *
- * @deprecated 1.7. Use elgg_get_entities_from_metadata().
- *
- * @param mixed $meta_array Metadata name
- * @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 $owner_guid Owner GUID
- * @param int $limit Limit
- * @param int $offset Offset
- * @param string $order_by Optional ordering.
- * @param int $site_guid Site GUID. 0 for current, -1 for any.
- * @param bool $count Return a count instead of entities
- * @param bool $meta_array_operator Operator for metadata values
- *
- * @return int|array A list of entities, or a count if $count is set to true
+ * 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) {
- if (is_array($owner_guid)) {
- $options['owner_guids'] = $owner_guid;
- } else {
- $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 $owner_guid Owner GUID
- * @param int $limit Limit
- * @param bool $fullview WDisplay the full view (default: true)
- * @param bool $listtypetoggle Allow users to toggle to the gallery view. Default: true
- * @param bool $pagination Display pagination? Default: true
- *
- * @return string List of ElggEntities suitable for display
- *
- * @deprecated Use elgg_list_entities_from_metadata() instead
- */
-function list_entities_from_metadata_multi($meta_array, $entity_type = "", $entity_subtype = "",
-$owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = true, $pagination = true) {
- elgg_deprecated_notice(elgg_echo('deprecated:function', array(
- 'list_entities_from_metadata_multi',
- 'elgg_get_entities_from_metadata'
- )), 1.8);
-
-
- $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,
- $listtypetoggle, $pagination);
-}
-
-/**
- * Clear all the metadata for a given entity, assuming you have access to that metadata.
- *
- * @param int $entity_guid Entity GUID
- *
- * @return bool
- */
-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 int $owner_guid The owner
- *
- * @return bool
- */
-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.
@@ -1194,6 +748,9 @@ function clear_metadata_by_owner($owner_guid) {
* @param mixed $params Params
*
* @return array
+ * @access private
+ *
+ * @throws InvalidParameterException
*/
function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params) {
// Sanity check values
@@ -1205,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();
}
@@ -1221,7 +779,7 @@ 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
+ * which have been trimmed
*
* @param string $string Comma-separated tag string
*
@@ -1230,17 +788,12 @@ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params)
function string_to_tag_array($string) {
if (is_string($string)) {
$ar = explode(",", $string);
- // trim blank spaces
$ar = array_map('trim', $ar);
- // make lower case : [Marcus Povey 20090605 - Using mb wrapper function
- // using UTF8 safe function where available]
- $ar = array_map('elgg_strtolower', $ar);
- // Remove null values
$ar = array_filter($ar, 'is_not_null');
+ $ar = array_map('strip_tags', $ar);
return $ar;
}
return false;
-
}
/**
@@ -1275,7 +828,7 @@ function metadata_array_to_values($array) {
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;
@@ -1331,10 +884,10 @@ function is_metadata_independent($type, $subtype) {
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();
- $query = "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);
}
}
@@ -1344,13 +897,57 @@ 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 */
@@ -1371,9 +968,11 @@ elgg_register_plugin_hook_handler('unit_test', 'system', 'metadata_test');
* @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;
}