aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>2011-02-11 02:03:08 +0000
committerbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>2011-02-11 02:03:08 +0000
commit0c65a46b3ff62fefb9efb1e4324291b8cb33e1c8 (patch)
tree121e252066fea851515415183f00b47924d36c14
parenta665ef2e94312ed5479c1e730d0d429c33c4dea8 (diff)
downloadelgg-0c65a46b3ff62fefb9efb1e4324291b8cb33e1c8.tar.gz
elgg-0c65a46b3ff62fefb9efb1e4324291b8cb33e1c8.tar.bz2
Refs #650. Deprecated get_annotations() for elgg_get_annotations().
git-svn-id: http://code.elgg.org/elgg/trunk@8109 36083f99-b078-4883-b0ff-0f9b5a30f544
-rw-r--r--engine/lib/annotations.php427
-rw-r--r--engine/lib/metadata.php2
-rw-r--r--engine/tests/api/entity_getter_functions.php98
3 files changed, 427 insertions, 100 deletions
diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php
index f43c13c87..d0ff3559c 100644
--- a/engine/lib/annotations.php
+++ b/engine/lib/annotations.php
@@ -170,158 +170,387 @@ function update_annotation($annotation_id, $name, $value, $value_type, $owner_gu
}
/**
- * Get a list of annotations for a given object/user/annotation type.
+ * Returns annotations. Accepts all elgg_get_entities() options for entity
+ * restraints.
*
- * @param int|array $entity_guid GUID to return annotations of (falsey for any)
- * @param string $entity_type Type of entity
- * @param string $entity_subtype Subtype of entity
- * @param string $name Name of annotation
- * @param mixed $value Value of annotation
- * @param int|array $owner_guid Owner(s) of annotation
- * @param int $limit Limit
- * @param int $offset Offset
- * @param string $order_by Order annotations by SQL
- * @param int $timelower Lower time limit
- * @param int $timeupper Upper time limit
- * @param int $entity_owner_guid Owner guid for the entity
+ * @see elgg_get_entities
+ *
+ * @param array $options Array in format:
+ *
+ * annotation_names => NULL|ARR Annotation names
+ *
+ * annotation_values => NULL|ARR Annotation values
+ *
+ * annotation_case_sensitive => BOOL Overall Case sensitive
+ *
+ * annotation_owner_guids => NULL|ARR guids for metadata owners
+ *
+ * annotation_created_time_lower => INT Lower limit for created time.
+ *
+ * annotation_created_time_upper => INT Upper limit for created time.
*
* @return array
+ * @since 1.8.0
*/
-function get_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "",
-$value = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "asc", $timelower = 0,
-$timeupper = 0, $entity_owner_guid = 0) {
- global $CONFIG;
+function elgg_get_annotations($options = array()) {
+ $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,
+
+ // annotations
+ // options are normalized to the plural in case we ever add support for them.
+ 'annotation_names' => ELGG_ENTITIES_ANY_VALUE,
+ 'annotation_values' => ELGG_ENTITIES_ANY_VALUE,
+// 'annotation_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
+// 'annotation_name_value_pairs_operator' => 'AND',
- $timelower = (int) $timelower;
- $timeupper = (int) $timeupper;
+ 'annotation_case_sensitive' => TRUE,
+// 'order_by_annotation' => array(),
- if (is_array($entity_guid)) {
- if (sizeof($entity_guid) > 0) {
- foreach ($entity_guid as $key => $val) {
- $entity_guid[$key] = (int) $val;
- }
+ 'annotation_created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
+ 'annotation_created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
+
+ 'annotation_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
+
+ // sql
+ 'order_by' => 'a.time_created asc',
+ 'limit' => 10,
+ 'offset' => 0,
+ 'count' => FALSE,
+ 'selects' => array(),
+ 'wheres' => array(),
+ 'joins' => array(),
+
+ 'callback' => 'row_to_elggannotation',
+ );
+
+ $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 {
- $entity_guid = 0;
+ $options['type_subtype_pairs'] = $options['type_subtype_pair'];
}
- } else {
- $entity_guid = (int)$entity_guid;
}
- $entity_type = sanitise_string($entity_type);
+ $singulars = array('type', 'subtype', 'guid', 'owner_guid', 'container_guid', 'site_guid',
+ 'annotation_name', 'annotation_value'
+ );
+ $options = elgg_normalise_plural_options_array($options, $singulars);
- if ($entity_subtype) {
- if (!$entity_subtype = get_subtype_id($entity_type, $entity_subtype)) {
- // requesting a non-existing subtype: return false
+ 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']);
+
+ // annotations
+ $annotation_clauses = elgg_get_annotation_sql('a', $options['annotation_names'],
+ $options['annotation_values'], $options['annotation_case_sensitive']);
+
+ $wheres = array_merge($wheres, $annotation_clauses['wheres']);
+
+ $wheres[] = elgg_get_entity_time_where_sql('a', $options['annotation_created_time_upper'],
+ $options['annotation_created_time_lower'], null, null);
+
+ $wheres[] = elgg_get_guid_based_where_sql('a.owner_guid', $options['annotation_owner_guids']);
+
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
+
+ // 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]);
}
}
- if ($name) {
- $name = get_metastring_id($name);
+ // evaluate join clauses
+ if (!is_array($options['joins'])) {
+ $options['joins'] = array($options['joins']);
+ }
- if ($name === false) {
- $name = 0;
+ $joins = $options['joins'];
+
+ $joins = array_merge($joins, $annotation_clauses['joins']);
+ $joins[] = "JOIN {$db_prefix}entities e ON a.entity_guid = e.guid";
+ $joins[] = "JOIN {$db_prefix}metastrings n on a.name_id = n.id";
+ $joins[] = "JOIN {$db_prefix}metastrings v on a.value_id = v.id";
+
+
+ // remove identical join clauses
+ $joins = array_unique($joins);
+
+ foreach ($joins as $i => $join) {
+ if ($join === FALSE) {
+ return FALSE;
+ } elseif (empty($join)) {
+ unset($joins[$i]);
}
}
- if ($value != "") {
- $value = get_metastring_id($value);
+
+ // evalutate selects
+ if ($options['selects']) {
+ $selects = '';
+ foreach ($options['selects'] as $select) {
+ $selects .= ", $select";
+ }
+ } else {
+ $selects = '';
}
- if (is_array($owner_guid)) {
- if (sizeof($owner_guid) > 0) {
- foreach ($owner_guid as $key => $val) {
- $owner_guid[$key] = (int) $val;
- }
- } else {
- $owner_guid = 0;
+ // n_table is the normalized table that holds metastrings info.
+ if (!$options['count']) {
+ $query = "SELECT DISTINCT a.*, n.string as name, v.string as value FROM {$db_prefix}annotations a";
+ } else {
+ $query = "SELECT count(DISTINCT a.*) as total FROM {$db_prefix}annotations a";
+ }
+
+ // 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');
+ if (!$options['count']) {
+ if ($options['group_by'] = sanitise_string($options['group_by'])) {
+ $query .= " GROUP BY {$options['group_by']}";
+ }
+
+ if ($options['order_by'] = sanitise_string($options['order_by'])) {
+ $query .= " ORDER BY {$options['order_by']}";
}
+
+ if ($options['limit']) {
+ $limit = sanitise_int($options['limit']);
+ $offset = sanitise_int($options['offset']);
+ $query .= " LIMIT $offset, $limit";
+ }
+
+ $dt = get_data($query, $options['callback']);
+ return $dt;
} else {
- $owner_guid = (int)$owner_guid;
+ $total = get_data_row($query);
+ return (int)$total->total;
+ }
+}
+
+/**
+ * Returns an array of joins and wheres for use in annotations.
+ *
+ * @note The $pairs is reserved for name/value pairs if we want to implement those.
+ *
+ * @param string $table The annotation 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 bool $case_sensitive Should name and values be case sensitive?
+ *
+ * @return array
+ */
+function elgg_get_annotation_sql($table, $names = null, $values = null,
+ $pairs = null, $case_sensitive = false) {
+
+ if ((!$names && $names !== 0)
+ && (!$values && $values !== 0)
+ && (!$pairs && $pairs !== 0)) {
+
+ return '';
+ }
+
+ $db_prefix = elgg_get_config('dbprefix');
+
+ // join counter for incremental joins.
+ $i = 1;
+
+ // binary forces byte-to-byte comparision of strings, making
+ // it case- and diacritical-mark- sensitive.
+ // only supported on values.
+ $binary = ($case_sensitive) ? ' BINARY ' : '';
+
+ $access = get_access_sql_suffix($table);
+
+ $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))";
+ }
}
- if (is_array($entity_owner_guid)) {
- if (sizeof($entity_owner_guid) > 0) {
- foreach ($entity_owner_guid as $key => $val) {
- $entity_owner_guid[$key] = (int) $val;
+ // 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;
}
- } else {
- $entity_owner_guid = 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))";
}
- } else {
- $entity_owner_guid = (int)$entity_owner_guid;
}
- $limit = (int)$limit;
- $offset = (int)$offset;
- if ($order_by == 'asc') {
- $order_by = "a.time_created asc";
+ if ($names_where && $values_where) {
+ $wheres[] = "($names_where AND $values_where AND $access)";
+ } elseif ($names_where) {
+ $wheres[] = "($names_where AND $access)";
+ } elseif ($values_where) {
+ $wheres[] = "($values_where AND $access)";
}
- if ($order_by == 'desc') {
- $order_by = "a.time_created desc";
+ if ($where = implode(' AND ', $wheres)) {
+ $return['wheres'][] = "($where)";
}
- $where = array();
+ return $return;
+}
+
+/**
+ * Get a list of annotations for a given object/user/annotation type.
+ *
+ * @param int|array $entity_guid GUID to return annotations of (falsey for any)
+ * @param string $entity_type Type of entity
+ * @param string $entity_subtype Subtype of entity
+ * @param string $name Name of annotation
+ * @param mixed $value Value of annotation
+ * @param int|array $owner_guid Owner(s) of annotation
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Order annotations by SQL
+ * @param int $timelower Lower time limit
+ * @param int $timeupper Upper time limit
+ * @param int $entity_owner_guid Owner guid for the entity
+ *
+ * @return array
+ */
+function get_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "",
+$value = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "asc", $timelower = 0,
+$timeupper = 0, $entity_owner_guid = 0) {
+ global $CONFIG;
- if ($entity_guid != 0 && !is_array($entity_guid)) {
- $where[] = "a.entity_guid=$entity_guid";
- } else if (is_array($entity_guid)) {
- $where[] = "a.entity_guid in (" . implode(",", $entity_guid) . ")";
+ $options = array();
+
+ if ($entity_guid) {
+ $options['guid'] = $entity_guid;
}
- if ($entity_type != "") {
- $where[] = "e.type='$entity_type'";
+ if ($entity_type) {
+ $options['type'] = $entity_type;
}
- if ($entity_subtype != "") {
- $where[] = "e.subtype='$entity_subtype'";
+ if ($entity_subtype) {
+ $options['subtype'] = $entity_subtype;
}
- if ($owner_guid != 0 && !is_array($owner_guid)) {
- $where[] = "a.owner_guid=$owner_guid";
- } else {
- if (is_array($owner_guid)) {
- $where[] = "a.owner_guid in (" . implode(",", $owner_guid) . ")";
- }
+ if ($name) {
+ $options['annotation_name'] = $name;
}
- if ($entity_owner_guid != 0 && !is_array($entity_owner_guid)) {
- $where[] = "e.owner_guid=$entity_owner_guid";
- } else {
- if (is_array($entity_owner_guid)) {
- $where[] = "e.owner_guid in (" . implode(",", $entity_owner_guid) . ")";
- }
+ if ($value) {
+ $options['annotation_value'] = $value;
}
- if ($name !== "") {
- $where[] = "a.name_id='$name'";
+ if ($owner_guid) {
+ $options['annotation_owner_guid'] = $owner_guid;
}
- if ($value != "") {
- $where[] = "a.value_id='$value'";
+ $options['limit'] = $limit;
+ $options['offset'] = $offset;
+
+ if ($order_by == 'desc') {
+ $options['order_by'] = 'a.time_created desc';
}
if ($timelower) {
- $where[] = "a.time_created >= {$timelower}";
+ $options['annotation_time_lower'] = $timelower;
}
if ($timeupper) {
- $where[] = "a.time_created <= {$timeupper}";
+ $options['annotation_time_upper'] = $timeupper;
}
- $query = "SELECT a.*, n.string as name, v.string as value
- FROM {$CONFIG->dbprefix}annotations a
- JOIN {$CONFIG->dbprefix}entities e on a.entity_guid = e.guid
- JOIN {$CONFIG->dbprefix}metastrings v on a.value_id=v.id
- JOIN {$CONFIG->dbprefix}metastrings n on a.name_id = n.id where ";
-
- foreach ($where as $w) {
- $query .= " $w and ";
+ if ($entity_owner_guid) {
+ $options['owner_guid'] = $entity_owner_guid;
}
- $query .= get_access_sql_suffix("a"); // Add access controls
- $query .= " order by $order_by limit $offset,$limit"; // Add order and limit
- return get_data($query, "row_to_elggannotation");
+ return elgg_get_annotations($options);
}
/**
@@ -343,9 +572,9 @@ $timeupper = 0, $entity_owner_guid = 0) {
* annotation_values => NULL|ARR annotations values
*
* annotation_name_value_pairs => NULL|ARR (name = 'name', value => 'value',
- * 'operand' => '=', 'case_sensitive' => TRUE) entries.
+ * 'operator' => '=', '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".
+ * the pair's operator will be forced to "IN".
*
* annotation_name_value_pairs_operator => NULL|STR The operator to use for combining
* (name = value) OPERATOR (name = value); default AND
diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php
index 6204e0461..5935df43b 100644
--- a/engine/lib/metadata.php
+++ b/engine/lib/metadata.php
@@ -58,7 +58,7 @@ function get_metadata($id) {
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
diff --git a/engine/tests/api/entity_getter_functions.php b/engine/tests/api/entity_getter_functions.php
index c2e7b8dd1..e3e265d21 100644
--- a/engine/tests/api/entity_getter_functions.php
+++ b/engine/tests/api/entity_getter_functions.php
@@ -227,6 +227,24 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest {
return $r;
}
+ /**
+ * Creates random annotations on $entity
+ *
+ * @param unknown_type $entity
+ * @param unknown_type $max
+ */
+ public function createRandomAnnotations($entity, $max = 1) {
+ $annotations = array();
+ for ($i=0; $i<$max; $i++) {
+ $name = 'test_annotation_name_' . rand();
+ $value = rand();
+ $id = create_annotation($entity->getGUID(), $name, $value, 'integer', $entity->getGUID());
+ $annotations[] = get_annotation($id);
+ }
+
+ return $annotations;
+ }
+
/***********************************
* TYPE TESTS
@@ -2690,4 +2708,84 @@ class ElggCoreEntityGetterFunctionsTest extends ElggCoreUnitTest {
}
}
}
+
+ public function testElggGetAnnotationsAnnotationNames() {
+ $options = array('annotation_names' => array());
+ $a_e_map = array();
+
+ // create test annotations on a few entities.
+ for ($i=0; $i<3; $i++) {
+ do {
+ $e = $this->entities[array_rand($this->entities)];
+ } while(in_array($e->guid, $a_e_map));
+ $annotations = $this->createRandomAnnotations($e);
+
+ foreach($annotations as $a) {
+ $options['annotation_names'][] = $a->name;
+ $a_e_map[$a->id] = $e->guid;
+ }
+ }
+
+ $as = elgg_get_annotations($options);
+
+ $this->assertEqual(count($a_e_map), count($as));
+
+ foreach ($as as $a) {
+ $this->assertEqual($a_e_map[$a->id], $a->entity_guid);
+ }
+ }
+
+ public function testElggGetAnnotationsAnnotationValues() {
+ $options = array('annotation_values' => array());
+ $a_e_map = array();
+
+ // create test annotations on a few entities.
+ for ($i=0; $i<3; $i++) {
+ do {
+ $e = $this->entities[array_rand($this->entities)];
+ } while(in_array($e->guid, $a_e_map));
+ $annotations = $this->createRandomAnnotations($e);
+
+ foreach($annotations as $a) {
+ $options['annotation_values'][] = $a->value;
+ $a_e_map[$a->id] = $e->guid;
+ }
+ }
+
+ $as = elgg_get_annotations($options);
+
+ $this->assertEqual(count($a_e_map), count($as));
+
+ foreach ($as as $a) {
+ $this->assertEqual($a_e_map[$a->id], $a->entity_guid);
+ }
+ }
+
+ public function testElggGetAnnotationsAnnotationOwnerGuids() {
+ $options = array('annotation_owner_guids' => array());
+ $a_e_map = array();
+
+ // create test annotations on a single entity
+ for ($i=0; $i<3; $i++) {
+ do {
+ $e = $this->entities[array_rand($this->entities)];
+ } while(in_array($e->guid, $a_e_map));
+
+ // remove annotations left over from previous tests.
+ clear_annotations($e->guid);
+ $annotations = $this->createRandomAnnotations($e);
+
+ foreach($annotations as $a) {
+ $options['annotation_owner_guids'][] = $e->guid;
+ $a_e_map[$a->id] = $e->guid;
+ }
+ }
+
+ $as = elgg_get_annotations($options);
+ $this->assertEqual(count($a_e_map), count($as));
+
+ foreach ($as as $a) {
+ $this->assertEqual($a_e_map[$a->id], $a->owner_guid);
+ }
+ }
}