]> gitweb.fluxo.info Git - lorea/elgg.git/commitdiff
Refs #650. Deprecated get_annotations() for elgg_get_annotations().
authorbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>
Fri, 11 Feb 2011 02:03:08 +0000 (02:03 +0000)
committerbrettp <brettp@36083f99-b078-4883-b0ff-0f9b5a30f544>
Fri, 11 Feb 2011 02:03:08 +0000 (02:03 +0000)
git-svn-id: http://code.elgg.org/elgg/trunk@8109 36083f99-b078-4883-b0ff-0f9b5a30f544

engine/lib/annotations.php
engine/lib/metadata.php
engine/tests/api/entity_getter_functions.php

index f43c13c8708878d43c9f59202d6fe4d7ee45c7b8..d0ff3559cf04d891fb672f86411b930823972871 100644 (file)
@@ -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
index 6204e0461e04f1b54fc7e2864bfc67f60ff2fb55..5935df43b8481d406b7d61ca8e8c85b49efb070d 100644 (file)
@@ -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
index c2e7b8dd1d5078630c6c1541f0657a334d9a2ebc..e3e265d21185e660db7185f2aae39a877feb0502 100644 (file)
@@ -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);
+               }
+       }
 }