diff options
Diffstat (limited to 'engine/lib/metastrings.php')
| -rw-r--r-- | engine/lib/metastrings.php | 903 | 
1 files changed, 903 insertions, 0 deletions
| diff --git a/engine/lib/metastrings.php b/engine/lib/metastrings.php new file mode 100644 index 000000000..57d876c06 --- /dev/null +++ b/engine/lib/metastrings.php @@ -0,0 +1,903 @@ +<?php +/** + * Elgg metastrngs + * Functions to manage object metastrings. + * + * @package Elgg.Core + * @subpackage DataModel.MetaStrings + */ + +/** Cache metastrings for a page */ +global $METASTRINGS_CACHE; +$METASTRINGS_CACHE = array(); + +/** Keep a record of strings we know don't exist */ +global $METASTRINGS_DEADNAME_CACHE; +$METASTRINGS_DEADNAME_CACHE = array(); + + + +/** + * Return the meta string id for a given tag, or false. + * + * @param string $string         The value to store + * @param bool   $case_sensitive Do we want to make the query case sensitive? + *                               If not there may be more than one result + * + * @return int|array|false meta   string id, array of ids or false if none found + */ +function get_metastring_id($string, $case_sensitive = TRUE) { +	global $CONFIG, $METASTRINGS_CACHE, $METASTRINGS_DEADNAME_CACHE; + +	$string = sanitise_string($string); + +	// caching doesn't work for case insensitive searches +	if ($case_sensitive) { +		$result = array_search($string, $METASTRINGS_CACHE, true); + +		if ($result !== false) { +			elgg_log("** Returning id for string:$string from cache."); +			return $result; +		} + +		// See if we have previously looked for this and found nothing +		if (in_array($string, $METASTRINGS_DEADNAME_CACHE, true)) { +			return false; +		} + +		// Experimental memcache +		$msfc = null; +		static $metastrings_memcache; +		if ((!$metastrings_memcache) && (is_memcache_available())) { +			$metastrings_memcache = new ElggMemcache('metastrings_memcache'); +		} +		if ($metastrings_memcache) { +			$msfc = $metastrings_memcache->load($string); +		} +		if ($msfc) { +			return $msfc; +		} +	} + +	// Case sensitive +	if ($case_sensitive) { +		$query = "SELECT * from {$CONFIG->dbprefix}metastrings where string= BINARY '$string' limit 1"; +	} else { +		$query = "SELECT * from {$CONFIG->dbprefix}metastrings where string = '$string'"; +	} + +	$row = FALSE; +	$metaStrings = get_data($query); +	if (is_array($metaStrings)) { +		if (sizeof($metaStrings) > 1) { +			$ids = array(); +			foreach ($metaStrings as $metaString) { +				$ids[] = $metaString->id; +			} +			return $ids; +		} else if (isset($metaStrings[0])) { +			$row = $metaStrings[0]; +		} +	} + +	if ($row) { +		$METASTRINGS_CACHE[$row->id] = $row->string; // Cache it + +		// Attempt to memcache it if memcache is available +		if ($metastrings_memcache) { +			$metastrings_memcache->save($row->string, $row->id); +		} + +		elgg_log("** Cacheing string '{$row->string}'"); + +		return $row->id; +	} else { +		$METASTRINGS_DEADNAME_CACHE[$string] = $string; +	} + +	return false; +} + +/** + * When given an ID, returns the corresponding metastring + * + * @param int $id Metastring ID + * + * @return string Metastring + */ +function get_metastring($id) { +	global $CONFIG, $METASTRINGS_CACHE; + +	$id = (int) $id; + +	if (isset($METASTRINGS_CACHE[$id])) { +		elgg_log("** Returning string for id:$id from cache."); + +		return $METASTRINGS_CACHE[$id]; +	} + +	$row = get_data_row("SELECT * from {$CONFIG->dbprefix}metastrings where id='$id' limit 1"); +	if ($row) { +		$METASTRINGS_CACHE[$id] = $row->string; // Cache it +		elgg_log("** Cacheing string '{$row->string}'"); + +		return $row->string; +	} + +	return false; +} + +/** + * Add a metastring. + * It returns the id of the tag, whether by creating it or updating it. + * + * @param string $string         The value (whatever that is) to be stored + * @param bool   $case_sensitive Do we want to make the query case sensitive? + * + * @return mixed Integer tag or false. + */ +function add_metastring($string, $case_sensitive = true) { +	global $CONFIG, $METASTRINGS_CACHE, $METASTRINGS_DEADNAME_CACHE; + +	$sanstring = sanitise_string($string); + +	$id = get_metastring_id($string, $case_sensitive); +	if ($id) { +		return $id; +	} + +	$result = insert_data("INSERT into {$CONFIG->dbprefix}metastrings (string) values ('$sanstring')"); +	if ($result) { +		$METASTRINGS_CACHE[$result] = $string; +		if (isset($METASTRINGS_DEADNAME_CACHE[$string])) { +			unset($METASTRINGS_DEADNAME_CACHE[$string]); +		} +	} + +	return $result; +} + +/** + * Delete any orphaned entries in metastrings. This is run by the garbage collector. + * + * @return bool + * @access private + */ +function delete_orphaned_metastrings() { +	global $CONFIG; + +	// If memcache is enabled then we need to flush it of deleted values +	if (is_memcache_available()) { +		$select_query = " +		SELECT * +		from {$CONFIG->dbprefix}metastrings where +		( +			(id not in (select name_id from {$CONFIG->dbprefix}metadata)) AND +			(id not in (select value_id from {$CONFIG->dbprefix}metadata)) AND +			(id not in (select name_id from {$CONFIG->dbprefix}annotations)) AND +			(id not in (select value_id from {$CONFIG->dbprefix}annotations)) +		)"; + +		$dead = get_data($select_query); +		if ($dead) { +			static $metastrings_memcache; +			if (!$metastrings_memcache) { +				$metastrings_memcache = new ElggMemcache('metastrings_memcache'); +			} + +			foreach ($dead as $d) { +				$metastrings_memcache->delete($d->string); +			} +		} +	} + +	$query = " +		DELETE +		from {$CONFIG->dbprefix}metastrings where +		( +			(id not in (select name_id from {$CONFIG->dbprefix}metadata)) AND +			(id not in (select value_id from {$CONFIG->dbprefix}metadata)) AND +			(id not in (select name_id from {$CONFIG->dbprefix}annotations)) AND +			(id not in (select value_id from {$CONFIG->dbprefix}annotations)) +		)"; + +	return delete_data($query); +} + +/** + * Returns an array of either ElggAnnotation or ElggMetadata objects. + * Accepts all elgg_get_entities() options for entity restraints. + * + * @see elgg_get_entities + * + * @param array $options Array in format: + * + * 	metastring_names              => NULL|ARR metastring names + * + * 	metastring_values             => NULL|ARR metastring values + * + * 	metastring_ids                => NULL|ARR metastring ids + * + * 	metastring_case_sensitive     => BOOL     Overall Case sensitive + * + *  metastring_owner_guids        => NULL|ARR Guids for metadata owners + * + *  metastring_created_time_lower => INT      Lower limit for created time. + * + *  metastring_created_time_upper => INT      Upper limit for created time. + * + *  metastring_calculation        => STR      Perform the MySQL function on the metastring values + *                                            returned. + *                                            This differs from egef_annotation_calculation in that + *                                            it returns only the calculation of all annotation values. + *                                            You can sum, avg, count, etc. egef_annotation_calculation() + *                                            returns ElggEntities ordered by a calculation on their + *                                            annotation values. + * + *  metastring_type               => STR      metadata or annotation(s) + * + * @return mixed + * @access private + */ +function elgg_get_metastring_based_objects($options) { +	$options = elgg_normalize_metastrings_options($options); + +	switch ($options['metastring_type']) { +		case 'metadata': +			$type = 'metadata'; +			$callback = 'row_to_elggmetadata'; +			break; + +		case 'annotations': +		case 'annotation': +			$type = 'annotations'; +			$callback = 'row_to_elggannotation'; +			break; + +		default: +			return false; +	} + +	$defaults = array( +		// entities +		'types'					=>	ELGG_ENTITIES_ANY_VALUE, +		'subtypes'				=>	ELGG_ENTITIES_ANY_VALUE, +		'type_subtype_pairs'	=>	ELGG_ENTITIES_ANY_VALUE, + +		'guids'					=>	ELGG_ENTITIES_ANY_VALUE, +		'owner_guids'			=>	ELGG_ENTITIES_ANY_VALUE, +		'container_guids'		=>	ELGG_ENTITIES_ANY_VALUE, +		'site_guids'			=>	get_config('site_guid'), + +		'modified_time_lower'	=>	ELGG_ENTITIES_ANY_VALUE, +		'modified_time_upper'	=>	ELGG_ENTITIES_ANY_VALUE, +		'created_time_lower'	=>	ELGG_ENTITIES_ANY_VALUE, +		'created_time_upper'	=>	ELGG_ENTITIES_ANY_VALUE, + +		// options are normalized to the plural in case we ever add support for them. +		'metastring_names'							=>	ELGG_ENTITIES_ANY_VALUE, +		'metastring_values'							=>	ELGG_ENTITIES_ANY_VALUE, +		//'metastring_name_value_pairs'				=>	ELGG_ENTITIES_ANY_VALUE, +		//'metastring_name_value_pairs_operator'	=>	'AND', + +		'metastring_case_sensitive' 				=>	TRUE, +		//'order_by_metastring'						=>	array(), +		'metastring_calculation'					=>	ELGG_ENTITIES_NO_VALUE, + +		'metastring_created_time_lower'				=>	ELGG_ENTITIES_ANY_VALUE, +		'metastring_created_time_upper'				=>	ELGG_ENTITIES_ANY_VALUE, + +		'metastring_owner_guids'					=>	ELGG_ENTITIES_ANY_VALUE, + +		'metastring_ids'							=>	ELGG_ENTITIES_ANY_VALUE, + +		// sql +		'order_by'	=>	'n_table.time_created asc', +		'limit'		=>	10, +		'offset'	=>	0, +		'count'		=>	FALSE, +		'selects'	=>	array(), +		'wheres'	=>	array(), +		'joins'		=>	array(), + +		'callback'	=> $callback +	); + +	// @todo Ignore site_guid right now because of #2910 +	$options['site_guid'] = ELGG_ENTITIES_ANY_VALUE; + +	$options = array_merge($defaults, $options); + +	// can't use helper function with type_subtype_pair because +	// it's already an array...just need to merge it +	if (isset($options['type_subtype_pair'])) { +		if (isset($options['type_subtype_pairs'])) { +			$options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'], +				$options['type_subtype_pair']); +		} else { +			$options['type_subtype_pairs'] = $options['type_subtype_pair']; +		} +	} + +	$singulars = array( +		'type', 'subtype', 'type_subtype_pair', +		'guid', 'owner_guid', 'container_guid', 'site_guid', +		'metastring_name', 'metastring_value', +		'metastring_owner_guid', 'metastring_id', +		'select', 'where', 'join' +	); + +	$options = elgg_normalise_plural_options_array($options, $singulars); + +	if (!$options) { +		return false; +	} + +	$db_prefix = elgg_get_config('dbprefix'); + +	// evaluate where clauses +	if (!is_array($options['wheres'])) { +		$options['wheres'] = array($options['wheres']); +	} + +	$wheres = $options['wheres']; + +	// entities +	$wheres[] = elgg_get_entity_type_subtype_where_sql('e', $options['types'], +		$options['subtypes'], $options['type_subtype_pairs']); + +	$wheres[] = elgg_get_guid_based_where_sql('e.guid', $options['guids']); +	$wheres[] = elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']); +	$wheres[] = elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']); +	$wheres[] = elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']); + +	$wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'], +		$options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']); + + +	$wheres[] = elgg_get_entity_time_where_sql('n_table', $options['metastring_created_time_upper'], +		$options['metastring_created_time_lower'], null, null); + +	$wheres[] = elgg_get_guid_based_where_sql('n_table.owner_guid', +		$options['metastring_owner_guids']); + +	// see if any functions failed +	// remove empty strings on successful functions +	foreach ($wheres as $i => $where) { +		if ($where === FALSE) { +			return FALSE; +		} elseif (empty($where)) { +			unset($wheres[$i]); +		} +	} + +	// remove identical where clauses +	$wheres = array_unique($wheres); + +	// evaluate join clauses +	if (!is_array($options['joins'])) { +		$options['joins'] = array($options['joins']); +	} + +	$joins = $options['joins']; +	$joins[] = "JOIN {$db_prefix}entities e ON n_table.entity_guid = e.guid"; + +	// evaluate selects +	if (!is_array($options['selects'])) { +		$options['selects'] = array($options['selects']); +	} + +	$selects = $options['selects']; + +	// For performance reasons we don't want the joins required for metadata / annotations +	// unless we're going through one of their callbacks. +	// this means we expect the functions passing different callbacks to pass their required joins. +	// If we're doing a calculation +	$custom_callback = ($options['callback'] == 'row_to_elggmetadata' +						|| $options['callback'] == 'row_to_elggannotation'); +	$is_calculation = $options['metastring_calculation'] ? true : false; +	 +	if ($custom_callback || $is_calculation) { +		$joins[] = "JOIN {$db_prefix}metastrings n on n_table.name_id = n.id"; +		$joins[] = "JOIN {$db_prefix}metastrings v on n_table.value_id = v.id"; + +		$selects[] = 'n.string as name'; +		$selects[] = 'v.string as value'; +	} + +	foreach ($joins as $i => $join) { +		if ($join === FALSE) { +			return FALSE; +		} elseif (empty($join)) { +			unset($joins[$i]); +		} +	} + +	// metastrings +	$metastring_clauses = elgg_get_metastring_sql('n_table', $options['metastring_names'], +		$options['metastring_values'], null, $options['metastring_ids'], +		$options['metastring_case_sensitive']); + +	if ($metastring_clauses) { +		$wheres = array_merge($wheres, $metastring_clauses['wheres']); +		$joins = array_merge($joins, $metastring_clauses['joins']); +	} else { +		$wheres[] = get_access_sql_suffix('n_table'); +	} + +	if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) { +		$selects = array_unique($selects); +		// evalutate selects +		$select_str = ''; +		if ($selects) { +			foreach ($selects as $select) { +				$select_str .= ", $select"; +			} +		} + +		$query = "SELECT DISTINCT n_table.*{$select_str} FROM {$db_prefix}$type n_table"; +	} elseif ($options['count']) { +		// count is over the entities +		$query = "SELECT count(DISTINCT e.guid) as calculation FROM {$db_prefix}$type n_table"; +	} else { +		$query = "SELECT {$options['metastring_calculation']}(v.string) as calculation FROM {$db_prefix}$type n_table"; +	} + +	// remove identical join clauses +	$joins = array_unique($joins); + +	// add joins +	foreach ($joins as $j) { +		$query .= " $j "; +	} + +	// add wheres +	$query .= ' WHERE '; + +	foreach ($wheres as $w) { +		$query .= " $w AND "; +	} + +	// Add access controls +	$query .= get_access_sql_suffix('e'); + +	// reverse order by +	if (isset($options['reverse_order_by']) && $options['reverse_order_by']) { +		$options['order_by'] = elgg_sql_reverse_order_by_clause($options['order_by'], +			$defaults['order_by']); +	} + +	if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) { +		if (isset($options['group_by'])) { +			$options['group_by'] = sanitise_string($options['group_by']); +			$query .= " GROUP BY {$options['group_by']}"; +		} + +		if (isset($options['order_by']) && $options['order_by']) { +			$options['order_by'] = sanitise_string($options['order_by']); +			$query .= " ORDER BY {$options['order_by']}, n_table.id"; +		} + +		if ($options['limit']) { +			$limit = sanitise_int($options['limit']); +			$offset = sanitise_int($options['offset'], false); +			$query .= " LIMIT $offset, $limit"; +		} + +		$dt = get_data($query, $options['callback']); +		return $dt; +	} else { +		$result = get_data_row($query); +		return $result->calculation; +	} +} + +/** + * Returns an array of joins and wheres for use in metastrings. + * + * @note The $pairs is reserved for name/value pairs if we want to implement those. + * + * @param string $table          The annotation or metadata table name or alias + * @param array  $names          An array of names + * @param array  $values         An array of values + * @param array  $pairs          Name / value pairs. Not currently used. + * @param array  $ids            Metastring IDs + * @param bool   $case_sensitive Should name and values be case sensitive? + * + * @return array + * @access private + */ +function elgg_get_metastring_sql($table, $names = null, $values = null, +	$pairs = null, $ids = null, $case_sensitive = false) { + +	if ((!$names && $names !== 0) +		&& (!$values && $values !== 0) +		&& !$ids +		&& (!$pairs && $pairs !== 0)) { + +		return array(); +	} + +	$db_prefix = elgg_get_config('dbprefix'); + +	// binary forces byte-to-byte comparision of strings, making +	// it case- and diacritical-mark- sensitive. +	// only supported on values. +	$binary = ($case_sensitive) ? ' BINARY ' : ''; + +	$return = array ( +		'joins' => array (), +		'wheres' => array() +	); + +	$wheres = array(); + +	// get names wheres and joins +	$names_where = ''; +	if ($names !== NULL) { +		if (!is_array($names)) { +			$names = array($names); +		} + +		$sanitised_names = array(); +		foreach ($names as $name) { +			// normalise to 0. +			if (!$name) { +				$name = '0'; +			} +			$sanitised_names[] = '\'' . sanitise_string($name) . '\''; +		} + +		if ($names_str = implode(',', $sanitised_names)) { +			$return['joins'][] = "JOIN {$db_prefix}metastrings msn on $table.name_id = msn.id"; +			$names_where = "(msn.string IN ($names_str))"; +		} +	} + +	// get values wheres and joins +	$values_where = ''; +	if ($values !== NULL) { +		if (!is_array($values)) { +			$values = array($values); +		} + +		$sanitised_values = array(); +		foreach ($values as $value) { +			// normalize to 0 +			if (!$value) { +				$value = 0; +			} +			$sanitised_values[] = '\'' . sanitise_string($value) . '\''; +		} + +		if ($values_str = implode(',', $sanitised_values)) { +			$return['joins'][] = "JOIN {$db_prefix}metastrings msv on $table.value_id = msv.id"; +			$values_where = "({$binary}msv.string IN ($values_str))"; +		} +	} + +	if ($ids !== NULL) { +		if (!is_array($ids)) { +			$ids = array($ids); +		} + +		$ids_str = implode(',', $ids); + +		if ($ids_str) { +			$wheres[] = "n_table.id IN ($ids_str)"; +		} +	} + +	if ($names_where && $values_where) { +		$wheres[] = "($names_where AND $values_where)"; +	} elseif ($names_where) { +		$wheres[] = $names_where; +	} elseif ($values_where) { +		$wheres[] = $values_where; +	} + +	$wheres[] = get_access_sql_suffix($table); + +	if ($where = implode(' AND ', $wheres)) { +		$return['wheres'][] = "($where)"; +	} + +	return $return; +} + +/** + * Normalizes metadata / annotation option names to their corresponding metastrings name. + * + * @param array $options An options array + * @since 1.8.0 + * @return array + * @access private + */ +function elgg_normalize_metastrings_options(array $options = array()) { + +	// support either metastrings_type or metastring_type +	// because I've made this mistake many times and hunting it down is a pain... +	$type = elgg_extract('metastring_type', $options, null); +	$type = elgg_extract('metastrings_type', $options, $type); + +	$options['metastring_type'] = $type; + +	// support annotation_ and annotations_ because they're way too easy to confuse +	$prefixes = array('metadata_', 'annotation_', 'annotations_'); + +	// map the metadata_* options to metastring_* options +	$map = array( +		'names'					=>	'metastring_names', +		'values'				=>	'metastring_values', +		'case_sensitive'		=>	'metastring_case_sensitive', +		'owner_guids'			=>	'metastring_owner_guids', +		'created_time_lower'	=>	'metastring_created_time_lower', +		'created_time_upper'	=>	'metastring_created_time_upper', +		'calculation'			=>	'metastring_calculation', +		'ids'					=>	'metastring_ids' +	); + +	foreach ($prefixes as $prefix) { +		$singulars = array("{$prefix}name", "{$prefix}value", "{$prefix}owner_guid", "{$prefix}id"); +		$options = elgg_normalise_plural_options_array($options, $singulars); + +		foreach ($map as $specific => $normalized) { +			$key = $prefix . $specific; +			if (isset($options[$key])) { +				$options[$normalized] = $options[$key]; +			} +		} +	} + +	return $options; +} + +/** + * Enables or disables a metastrings-based object by its id. + * + * @warning To enable disabled metastrings you must first use + * {@link access_show_hidden_entities()}. + * + * @param int    $id      The object's ID + * @param string $enabled Value to set to: yes or no + * @param string $type    The type of table to use: metadata or annotations + * + * @return bool + * @throws InvalidParameterException + * @since 1.8.0 + * @access private + */ +function elgg_set_metastring_based_object_enabled_by_id($id, $enabled, $type) { +	$id = (int)$id; +	$db_prefix = elgg_get_config('dbprefix'); + +	$object = elgg_get_metastring_based_object_from_id($id, $type); + +	switch($type) { +		case 'annotation': +		case 'annotations': +			$table = "{$db_prefix}annotations"; +			break; + +		case 'metadata': +			$table = "{$db_prefix}metadata"; +			break; +	} + +	if ($enabled === 'yes' || $enabled === 1 || $enabled === true) { +		$enabled = 'yes'; +		$event = 'enable'; +	} elseif ($enabled === 'no' || $enabled === 0 || $enabled === false) { +		$enabled = 'no'; +		$event = 'disable'; +	} else { +		return false; +	} + +	$return = false; + +	if ($object) { +		// don't set it if it's already set. +		if ($object->enabled == $enabled) { +			$return = false; +		} elseif ($object->canEdit() && (elgg_trigger_event($event, $type, $object))) { +			$return = update_data("UPDATE $table SET enabled = '$enabled' where id = $id"); +		} +	} + +	return $return; +} + +/** + * Runs metastrings-based objects found using $options through $callback + * + * @warning Unlike elgg_get_metastring_based_objects() this will not accept an + * empty options array! + * + * @warning This returns null on no ops. + * + * @param array  $options    An options array. {@See elgg_get_metastring_based_objects()} + * @param string $callback   The callback to pass each result through + * @param bool   $inc_offset Increment the offset? Pass false for callbacks that delete / disable + * + * @return bool|null true on success, false on failure, null if no objects are found. + * @since 1.8.0 + * @access private + */ +function elgg_batch_metastring_based_objects(array $options, $callback, $inc_offset = true) { +	if (!$options || !is_array($options)) { +		return false; +	} + +	$batch = new ElggBatch('elgg_get_metastring_based_objects', $options, $callback, 50, $inc_offset); +	return $batch->callbackResult; +} + +/** + * Returns a singular metastring-based object by its ID. + * + * @param int    $id   The metastring-based object's ID + * @param string $type The type: annotation or metadata + * @return ElggMetadata|ElggAnnotation + * + * @since 1.8.0 + * @access private + */ +function elgg_get_metastring_based_object_from_id($id, $type) { +	$id = (int)$id; +	if (!$id) { +		return false; +	} + +	$options = array( +		'metastring_type' => $type, +		'metastring_id' => $id +	); + +	$obj = elgg_get_metastring_based_objects($options); + +	if ($obj && count($obj) == 1) { +		return $obj[0]; +	} + +	return false; +} + +/** + * Deletes a metastring-based object by its id + * + * @param int    $id   The object's ID + * @param string $type The object's metastring type: annotation or metadata + * @return bool + * + * @since 1.8.0 + * @access private + */ +function elgg_delete_metastring_based_object_by_id($id, $type) { +	$id = (int)$id; +	$db_prefix = elgg_get_config('dbprefix'); + +	switch ($type) { +		case 'annotation': +		case 'annotations': +			$type = 'annotations'; +			break; + +		case 'metadata': +			$type = 'metadata'; +			break; + +		default: +			return false; +	} + +	$obj = elgg_get_metastring_based_object_from_id($id, $type); +	$table = $db_prefix . $type; + +	if ($obj) { +		// Tidy up if memcache is enabled. +		// @todo only metadata is supported +		if ($type == 'metadata') { +			static $metabyname_memcache; +			if ((!$metabyname_memcache) && (is_memcache_available())) { +				$metabyname_memcache = new ElggMemcache('metabyname_memcache'); +			} + +			if ($metabyname_memcache) { +				// @todo why name_id? is that even populated? +				$metabyname_memcache->delete("{$obj->entity_guid}:{$obj->name_id}"); +			} +		} + +		if (($obj->canEdit()) && (elgg_trigger_event('delete', $type, $obj))) { +			return (bool)delete_data("DELETE from $table where id=$id"); +		} +	} + +	return false; +} + +/** + * Entities interface helpers + */ + +/** + * 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 + * @access private + */ +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; +} + +// unit testing +elgg_register_plugin_hook_handler('unit_test', 'system', 'metastrings_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 metastrings_test($hook, $type, $value, $params) { +	global $CONFIG; +	$value[] = $CONFIG->path . 'engine/tests/api/metastrings.php'; +	return $value; +} | 
