aboutsummaryrefslogtreecommitdiff
path: root/engine/lib/annotations.php
diff options
context:
space:
mode:
Diffstat (limited to 'engine/lib/annotations.php')
-rw-r--r--engine/lib/annotations.php1310
1 files changed, 609 insertions, 701 deletions
diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php
index 6cc6ae1c6..5e9b530de 100644
--- a/engine/lib/annotations.php
+++ b/engine/lib/annotations.php
@@ -1,710 +1,618 @@
-<?php
- /**
- * Elgg annotations
- * Functions to manage object annotations.
- *
- * @package Elgg
- * @subpackage Core
- * @license http://www.gnu.org/licenses/old-licenses/gpl-2.0.html GNU Public License version 2
- * @author Curverider Ltd <info@elgg.com>
- * @copyright Curverider Ltd 2008
- * @link http://elgg.org/
- */
-
- /**
- * Include the ElggExtender superclass
- *
- */
- require_once('extender.php');
-
- /**
- * ElggAnnotation
- *
- * An annotation is similar to metadata each entity can contain more than one of each annotation.
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- */
- class ElggAnnotation extends ElggExtender
- {
-
- /**
- * Construct a new site object, optionally from a given id value or db row.
- *
- * @param mixed $id
- */
- function __construct($id = null)
- {
- $this->attributes = array();
-
- if (!empty($id)) {
- if ($id instanceof stdClass)
- $annotation = $id;
- else
- $annotation = get_annotation($id);
-
- if ($annotation) {
- $objarray = (array) $annotation;
- foreach($objarray as $key => $value) {
- $this->attributes[$key] = $value;
- }
- $this->attributes['type'] = "annotation";
- }
- }
- }
-
- /**
- * Class member get overloading
- *
- * @param string $name
- * @return mixed
- */
- function __get($name) {
- return $this->get($name);
- }
-
- /**
- * Class member set overloading
- *
- * @param string $name
- * @param mixed $value
- * @return void
- */
- function __set($name, $value) {
- return $this->set($name, $value);
- }
-
- /**
- * Save this instance
- *
- * @return int an object id
- */
- function save()
- {
- if ($this->id > 0)
- return update_annotation($this->id, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id);
- else
- {
- $this->id = create_annotation($this->entity_guid, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id);
- if (!$this->id) throw new IOException(sprintf(elgg_new('IOException:UnableToSaveNew'), get_class()));
- return $this->id;
- }
- }
-
- /**
- * Delete a given site.
- */
- function delete()
- {
- return delete_annotation($this->id);
- }
-
- /**
- * Get a url for this annotation.
- *
- * @return string
- */
- public function getURL() { return get_annotation_url($this->guid); }
-
- // SYSTEM LOG INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * For a given ID, return the object associated with it.
- * This is used by the river functionality primarily.
- * This is useful for checking access permissions etc on objects.
- */
- public function getObjectFromID($id) { return get_annotation($id); }
- }
-
- /**
- * Convert a database row to a new ElggAnnotation
- *
- * @param stdClass $row
- * @return stdClass or ElggAnnotation
- */
- function row_to_elggannotation($row)
- {
- if (!($row instanceof stdClass))
- return $row;
-
- return new ElggAnnotation($row);
- }
-
- /**
- * Get a specific annotation.
- *
- * @param int $annotation_id
- */
- function get_annotation($annotation_id)
- {
- global $CONFIG;
-
- $annotation_id = (int) $annotation_id;
- $access = get_access_sql_suffix("a");
-
- return row_to_elggannotation(get_data_row("SELECT a.*, n.string as name, v.string as value from {$CONFIG->dbprefix}annotations a JOIN {$CONFIG->dbprefix}metastrings n on a.name_id = n.id JOIN {$CONFIG->dbprefix}metastrings v on a.value_id = v.id where a.id=$annotation_id and $access"));
- }
-
- /**
- * Create a new annotation.
- *
- * @param int $entity_guid
- * @param string $name
- * @param string $value
- * @param string $value_type
- * @param int $owner_guid
- * @param int $access_id
- */
- function create_annotation($entity_guid, $name, $value, $value_type, $owner_guid, $access_id = 0)
- {
- global $CONFIG;
-
- $entity_guid = (int)$entity_guid;
- //$name = sanitise_string(trim($name));
- //$value = sanitise_string(trim($value));
- $value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type)));
-
- $owner_guid = (int)$owner_guid;
- if ($owner_guid==0) $owner_guid = get_loggedin_userid();
-
- $access_id = (int)$access_id;
-
- $time = time();
-
- // Add the metastring
- $value = add_metastring($value);
- if (!$value) return false;
-
- $name = add_metastring($name);
- if (!$name) return false;
-
- $entity = get_entity($entity_guid);
- system_log($entity, 'annotate');
-
- // If ok then add it
- $result = insert_data("INSERT into {$CONFIG->dbprefix}annotations (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)");
- if ($result!==false) {
- $obj = get_annotation($result);
- if (trigger_elgg_event('create', 'annotation', $obj)) {
- return true;
- } else {
- delete_annotation($result);
- }
- }
-
- return $result;
- }
-
- /**
- * Update an annotation.
- *
- * @param int $annotation_id
- * @param string $name
- * @param string $value
- * @param string $value_type
- * @param int $owner_guid
- * @param int $access_id
- */
- function update_annotation($annotation_id, $name, $value, $value_type, $owner_guid, $access_id)
- {
- global $CONFIG;
-
- $annotation_id = (int)$annotation_id;
- $name = (trim($name));
- $value = (trim($value));
- $value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type)));
-
- $owner_guid = (int)$owner_guid;
- if ($owner_guid==0) $owner_guid = get_loggedin_userid();
-
- $access_id = (int)$access_id;
-
- $access = get_access_sql_suffix();
-
- // Add the metastring
- $value = add_metastring($value);
- if (!$value) return false;
-
- $name = add_metastring($name);
- if (!$name) return false;
-
- // If ok then add it
- $result = update_data("UPDATE {$CONFIG->dbprefix}annotations set value_id='$value', value_type='$value_type', access_id=$access_id, owner_guid=$owner_guid where id=$annotation_id and name_id='$name' and $access");
- if ($result!==false) {
- $obj = get_annotation($annotation_id);
- if (trigger_elgg_event('update', 'annotation', $obj)) {
- return true;
- } else {
- delete_annotation($annotation_id);
- }
- }
-
- return $result;
- }
-
- /**
- * Get a list of annotations for a given object/user/annotation type.
- *
- * @param int|array $entity_guid
- * @param string $entity_type
- * @param string $entity_subtype
- * @param string $name
- * @param mixed $value
- * @param int|array $owner_guid
- * @param int $limit
- * @param int $offset
- * @param string $order_by
- */
- function get_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "asc")
- {
- global $CONFIG;
-
- if (is_array($entity_guid)) {
- if (sizeof($entity_guid) > 0) {
- foreach($entity_guid as $key => $val) {
- $entity_guid[$key] = (int) $val;
- }
- } else {
- $entity_guid = 0;
- }
- } else {
- $entity_guid = (int)$entity_guid;
- }
- $entity_type = sanitise_string($entity_type);
- $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
- if ($name)
- {
- $name = get_metastring_id($name);
-
- if ($name === false)
- $name = 0;
- }
- if ($value != "") $value = get_metastring_id($value);
- 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;
- }
- } else {
- $owner_guid = (int)$owner_guid;
- }
- $limit = (int)$limit;
- $offset = (int)$offset;
- if($order_by == 'asc')
- $order_by = "a.time_created asc";
-
- if($order_by == 'desc')
- $order_by = "a.time_created desc";
-
- $where = array();
-
- if ($entity_guid != 0 && !is_array($owner_guid)) {
- $where[] = "a.entity_guid=$entity_guid";
- } else if (is_array($owner_guid)) {
- $where[] = "a.entity_guid in (". implode(",",$entity_guid) . ")";
- }
-
- if ($entity_type != "")
- $where[] = "e.type='$entity_type'";
-
- if ($entity_subtype != "")
- $where[] = "e.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 !== "")
- $where[] = "a.name_id='$name'";
-
- if ($value != "")
- $where[] = "a.value_id='$value'";
-
- $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 ";
- $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");
-
+<?php
+/**
+ * Elgg annotations
+ * Functions to manage object annotations.
+ *
+ * @package Elgg
+ * @subpackage Core
+ */
+
+/**
+ * Convert a database row to a new ElggAnnotation
+ *
+ * @param stdClass $row Db row result object
+ *
+ * @return ElggAnnotation
+ * @access private
+ */
+function row_to_elggannotation($row) {
+ if (!($row instanceof stdClass)) {
+ // @todo should throw in this case?
+ return $row;
}
-
- /**
- * Return a list of entities which are annotated with a specific annotation.
- * These can be ordered by when the annotation was created/updated.
- *
- * @param string $entity_type Type of entity.
- * @param string $entity_subtype Subtype of entity.
- * @param string $name Name of annotation.
- * @param string $value Value of annotation.
- * @param int $owner_guid Owner.
- * @param int $group_guid Group container. Currently this is only supported if $entity_type == 'object'
- * @param int $limit Maximum number of results to return.
- * @param int $offset Place to start.
- * @param string $order_by How to order results.
- * @param boolean $count Whether to count entities rather than return them
- */
- function get_entities_from_annotations($entity_type = "", $entity_subtype = "", $name = "", $value = "", $owner_guid = 0, $group_guid = 0, $limit = 10, $offset = 0, $order_by = "asc", $count = false)
- {
- global $CONFIG;
-
- $entity_type = sanitise_string($entity_type);
- $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
- if ($name)
- {
- $name = get_metastring_id($name);
-
- if ($name === false)
- $name = 0;
- }
- if ($value != "") $value = get_metastring_id($value);
- if (is_array($owner_guid)) {
- if (sizeof($owner_guid) > 0) {
- foreach($owner_guid as $key => $val) {
- $owner_guid[$key] = (int) $val;
- }
+
+ return new ElggAnnotation($row);
+}
+
+/**
+ * Get a specific annotation by its id.
+ * If you want multiple annotation objects, use
+ * {@link elgg_get_annotations()}.
+ *
+ * @param int $id The id of the annotation object being retrieved.
+ *
+ * @return ElggAnnotation|false
+ */
+function elgg_get_annotation_from_id($id) {
+ return elgg_get_metastring_based_object_from_id($id, 'annotations');
+}
+
+/**
+ * Deletes an annotation using its ID.
+ *
+ * @param int $id The annotation ID to delete.
+ * @return bool
+ */
+function elgg_delete_annotation_by_id($id) {
+ $annotation = elgg_get_annotation_from_id($id);
+ if (!$annotation) {
+ return false;
+ }
+ return $annotation->delete();
+}
+
+/**
+ * Create a new annotation.
+ *
+ * @param int $entity_guid Entity Guid
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value (default is auto detection)
+ * @param int $owner_guid Owner of annotation (default is logged in user)
+ * @param int $access_id Access level of annotation
+ *
+ * @return int|bool id on success or false on failure
+ */
+function create_annotation($entity_guid, $name, $value, $value_type = '',
+$owner_guid = 0, $access_id = ACCESS_PRIVATE) {
+ global $CONFIG;
+
+ $result = false;
+
+ $entity_guid = (int)$entity_guid;
+ //$name = sanitise_string(trim($name));
+ //$value = sanitise_string(trim($value));
+ $value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type)));
+
+ $owner_guid = (int)$owner_guid;
+ if ($owner_guid == 0) {
+ $owner_guid = elgg_get_logged_in_user_guid();
+ }
+
+ $access_id = (int)$access_id;
+ $time = time();
+
+ // Add the metastring
+ $value = add_metastring($value);
+ if (!$value) {
+ return false;
+ }
+
+ $name = add_metastring($name);
+ if (!$name) {
+ return false;
+ }
+
+ $entity = get_entity($entity_guid);
+
+ if (elgg_trigger_event('annotate', $entity->type, $entity)) {
+ // If ok then add it
+ $result = insert_data("INSERT into {$CONFIG->dbprefix}annotations
+ (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)");
+
+ if ($result !== false) {
+ $obj = elgg_get_annotation_from_id($result);
+ if (elgg_trigger_event('create', 'annotation', $obj)) {
+ return $result;
} else {
- $owner_guid = 0;
+ // plugin returned false to reject annotation
+ elgg_delete_annotation_by_id($result);
+ return FALSE;
}
- } else {
- $owner_guid = (int)$owner_guid;
}
- $group_guid = (int)$group_guid;
-
- $limit = (int)$limit;
- $offset = (int)$offset;
- if($order_by == 'asc')
- $order_by = "maxtime asc";
-
- if($order_by == 'desc')
- $order_by = "maxtime desc";
-
- $where = array();
-
- if ($entity_type != "")
- $where[] = "e.type='$entity_type'";
-
- if ($entity_subtype != "")
- $where[] = "e.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 (($group_guid != 0) && ($entity_type=='object'))
- $where[] = "e.container_guid = $group_guid";
-
- if ($name !== "")
- $where[] = "a.name_id='$name'";
-
- if ($value != "")
- $where[] = "a.value_id='$value'";
-
-
- if ($count) {
- $query = "SELECT count(distinct e.guid) as total ";
- } else {
- $query = "SELECT e.*, max(a.time_created) as maxtime ";
- }
- $query .= "from {$CONFIG->dbprefix}annotations a JOIN {$CONFIG->dbprefix}entities e on e.guid = a.entity_guid ";
- if ($value != "")
- $query .= " JOIN {$CONFIG->dbprefix}metastrings v on a.value_id=v.id";
-
- if (($group_guid != 0) && ($entity_type=='object')) $query .= "JOIN {$CONFIG->dbprefix}objects_entity o on o.guid = e.guid";
- $query .= " where";
-
- foreach ($where as $w)
- $query .= " $w and ";
- $query .= get_access_sql_suffix("a"); // Add access controls
-
- if ($count) {
- $row = get_data_row($query);
- return $row->total;
- } else {
- $query .= " group by a.entity_guid order by $order_by limit $offset,$limit"; // Add order and limit
- return get_data($query, "entity_row_to_elggstar");
- }
- }
-
- /**
- * Lists entities
- *
- * @see elgg_view_entity_list
- *
- * @param string $entity_type Type of entity.
- * @param string $entity_subtype Subtype of entity.
- * @param string $name Name of annotation.
- * @param string $value Value of annotation.
- * @param int $limit Maximum number of results to return.
- * @param int $owner_guid Owner.
- * @param int $group_guid Group container. Currently this is only supported if $entity_type == 'object'
- * @param boolean $asc Whether to list in ascending or descending order (default: desc)
- * @param boolean $fullview Whether to display the entities in full
- * @param boolean $viewtypetoggle Determines whether or not the 'gallery' view can be displayed (default: no)
- * @return string Formatted entity list
- */
- function list_entities_from_annotations($entity_type = "", $entity_subtype = "", $name = "", $value = "", $limit = 10, $owner_guid = 0, $group_guid = 0, $asc = false, $fullview = true, $viewtypetoggle = false) {
-
- if ($asc) {
- $asc = "asc";
- } else {
- $asc = "desc";
- }
- $count = get_entities_from_annotations($entity_type, $entity_subtype, $name, $value, $owner_guid, $group_guid, null, null, $asc, true);
- $offset = (int) get_input("offset",0);
- $entities = get_entities_from_annotations($entity_type, $entity_subtype, $name, $value, $owner_guid, $group_guid, $limit, $offset, $asc);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle);
-
- }
-
- /**
- * Returns a human-readable list of annotations on a particular entity.
- *
- * @param int $entity_guid The entity GUID
- * @param string $name The name of the kind of annotation
- * @param int $limit The number of annotations to display at once
- * @param true|false $asc Whether or not the annotations are displayed in ascending order. (Default: true)
- * @return string HTML (etc) version of the annotation list
- */
- function list_annotations($entity_guid, $name = "", $limit = 25, $asc = true) {
-
- if ($asc) {
- $asc = "asc";
- } else {
- $asc = "desc";
- }
- $count = count_annotations($entity_guid, "", "", $name);
- $offset = (int) get_input("annoff",0);
- $annotations = get_annotations($entity_guid, "", "", $name, "", "", $limit, $offset, $asc);
-
- return elgg_view_annotation_list($annotations, $count, $offset, $limit);
-
- }
-
- /**
- * Return the sum of a given integer annotation.
- *
- * @param $entity_guid int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- */
- function get_annotations_sum($entity_guid, $entity_type = "", $entity_subtype = "", $name = "")
- {
- return __get_annotations_calculate_x("sum", $entity_guid, $entity_type, $entity_subtype, $name);
- }
-
- /**
- * Return the max of a given integer annotation.
- *
- * @param $entity_guid int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- */
- function get_annotations_max($entity_guid, $entity_type = "", $entity_subtype = "", $name = "")
- {
- return __get_annotations_calculate_x("max", $entity_guid, $entity_type, $entity_subtype, $name);
- }
-
- /**
- * Return the minumum of a given integer annotation.
- *
- * @param $entity_guid int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- */
- function get_annotations_min($entity_guid, $entity_type = "", $entity_subtype = "", $name = "")
- {
- return __get_annotations_calculate_x("min", $entity_guid, $entity_type, $entity_subtype, $name);
- }
-
- /**
- * Return the average of a given integer annotation.
- *
- * @param $entity_guid int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- */
- function get_annotations_avg($entity_guid, $entity_type = "", $entity_subtype = "", $name = "")
- {
- return __get_annotations_calculate_x("avg", $entity_guid, $entity_type, $entity_subtype, $name);
- }
-
- /**
- * Count the number of annotations based on search parameters
- *
- * @param int $entity_guid
- * @param string $entity_type
- * @param string $entity_subtype
- * @param string $name
- */
- function count_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0)
- {
- return __get_annotations_calculate_x("count", $entity_guid, $entity_type, $entity_subtype, $name);
- }
-
- /**
- * Perform a mathmatical calculation on integer annotations.
- *
- * @param $sum string
- * @param $entity_id int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- */
- function __get_annotations_calculate_x($sum = "avg", $entity_guid, $entity_type = "", $entity_subtype = "", $name = "")
- {
- global $CONFIG;
-
- $sum = sanitise_string($sum);
- $entity_guid = (int)$entity_guid;
- $entity_type = sanitise_string($entity_type);
- $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
- $name = get_metastring_id($name);
-
- if (empty($name)) return 0;
-
- $where = array();
-
- if ($entity_guid)
- $where[] = "e.guid=$entity_guid";
- if ($entity_type!="")
- $where[] = "e.type='$entity_type'";
- if ($entity_subtype)
- $where[] = "e.subtype=$entity_subtype";
- if ($name!="")
- $where[] = "a.name_id='$name'";
-
- if ($sum != "count")
- $where[] = "a.value_type='integer'"; // Limit on integer types
-
- $query = "SELECT $sum(ms.string) as sum from {$CONFIG->dbprefix}annotations a JOIN {$CONFIG->dbprefix}entities e on a.entity_guid = e.guid JOIN {$CONFIG->dbprefix}metastrings ms on a.value_id=ms.id WHERE ";
- foreach ($where as $w)
- $query .= " $w and ";
- $query .= get_access_sql_suffix("a"); // now add access
-
- $row = get_data_row($query);
- if ($row)
- return $row->sum;
-
- return false;
- }
-
- /**
- * Delete a given annotation.
- *
- * @param $id int The id
- */
- function delete_annotation($id)
- {
- global $CONFIG;
-
- $id = (int)$id;
-
- $access = get_access_sql_suffix();
-
- return delete_data("DELETE from {$CONFIG->dbprefix}annotations where id=$id and $access");
- }
-
- /**
- * Clear all the annotations for a given entity, assuming you have access to that metadata.
- *
- * @param int $guid
- */
- function clear_annotations($guid, $name = "")
- {
- global $CONFIG;
-
- $guid = (int)$guid;
-
- if (!empty($name))
- $name = get_metastring_id($name);
-
- $entity_guid = (int) $guid;
- if ($entity = get_entity($entity_guid)) {
- if ($entity->canEdit()) {
-
- $where = array();
-
- if ($name != "")
- $where[] = " name_id='$name'";
-
- $query = "DELETE from {$CONFIG->dbprefix}annotations where entity_guid=$guid ";
- foreach ($where as $w)
- $query .= " and $w";
-
- return delete_data($query);
-
- }
- }
- }
-
- /**
- * Handler called by trigger_plugin_hook on the "export" event.
- */
- function export_annotation_plugin_hook($hook, $entity_type, $returnvalue, $params)
- {
- // Sanity check values
- if ((!is_array($params)) && (!isset($params['guid'])))
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:GUIDNotForExport'));
-
- if (!is_array($returnvalue))
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonArrayReturnValue'));
-
- $guid = (int)$params['guid'];
- $name = $params['name'];
-
- $result = get_annotations($guid);
-
- if ($result)
- {
- foreach ($result as $r)
- $returnvalue[] = $r->export();
- }
-
- return $returnvalue;
}
-
- /**
- * Get the URL for this item of metadata, by default this links to the export handler in the current view.
- *
- * @param int $id
- */
- function get_annotation_url($id)
- {
- $id = (int)$id;
-
- if ($extender = get_annotation($id)) {
- return get_extender_url($extender);
- }
+
+ return $result;
+}
+
+/**
+ * Update an annotation.
+ *
+ * @param int $annotation_id Annotation ID
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value
+ * @param int $owner_guid Owner of annotation
+ * @param int $access_id Access level of annotation
+ *
+ * @return bool
+ */
+function update_annotation($annotation_id, $name, $value, $value_type, $owner_guid, $access_id) {
+ global $CONFIG;
+
+ $annotation_id = (int)$annotation_id;
+ $name = (trim($name));
+ $value = (trim($value));
+ $value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type)));
+
+ $owner_guid = (int)$owner_guid;
+ if ($owner_guid == 0) {
+ $owner_guid = elgg_get_logged_in_user_guid();
+ }
+
+ $access_id = (int)$access_id;
+
+ $access = get_access_sql_suffix();
+
+ // Add the metastring
+ $value = add_metastring($value);
+ if (!$value) {
+ return false;
+ }
+
+ $name = add_metastring($name);
+ if (!$name) {
return false;
}
+
+ // If ok then add it
+ $result = update_data("UPDATE {$CONFIG->dbprefix}annotations
+ set name_id='$name', value_id='$value', value_type='$value_type', access_id=$access_id, owner_guid=$owner_guid
+ where id=$annotation_id and $access");
+
+ if ($result !== false) {
+ // @todo add plugin hook that sends old and new annotation information before db access
+ $obj = elgg_get_annotation_from_id($annotation_id);
+ elgg_trigger_event('update', 'annotation', $obj);
+ }
+
+ return $result;
+}
+
+/**
+ * Returns annotations. Accepts all elgg_get_entities() options for entity
+ * restraints.
+ *
+ * @see elgg_get_entities
+ *
+ * @param array $options Array in format:
+ *
+ * annotation_names => NULL|ARR Annotation names
+ * annotation_values => NULL|ARR Annotation values
+ * annotation_ids => NULL|ARR annotation ids
+ * annotation_case_sensitive => BOOL Overall Case sensitive
+ * annotation_owner_guids => NULL|ARR guids for annotation owners
+ * annotation_created_time_lower => INT Lower limit for created time.
+ * annotation_created_time_upper => INT Upper limit for created time.
+ * annotation_calculation => STR Perform the MySQL function on the annotation values returned.
+ * Do not confuse this "annotation_calculation" option with the
+ * "calculation" option to elgg_get_entities_from_annotation_calculation().
+ * The "annotation_calculation" option causes this function to
+ * return the result of performing a mathematical calculation on
+ * all annotations that match the query instead of ElggAnnotation
+ * objects.
+ * See the docs for elgg_get_entities_from_annotation_calculation()
+ * for the proper use of the "calculation" option.
+ *
+ *
+ * @return ElggAnnotation[]|mixed
+ * @since 1.8.0
+ */
+function elgg_get_annotations(array $options = array()) {
+
+ // @todo remove support for count shortcut - see #4393
+ if (isset($options['__egefac']) && $options['__egefac']) {
+ unset($options['__egefac']);
+ } else {
+ // support shortcut of 'count' => true for 'annotation_calculation' => 'count'
+ if (isset($options['count']) && $options['count']) {
+ $options['annotation_calculation'] = 'count';
+ unset($options['count']);
+ }
+ }
+ $options['metastring_type'] = 'annotations';
+ return elgg_get_metastring_based_objects($options);
+}
+
+/**
+ * Deletes annotations based on $options.
+ *
+ * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
+ * This requires at least one constraint: annotation_owner_guid(s),
+ * annotation_name(s), annotation_value(s), or guid(s) must be set.
+ *
+ * @param array $options An options array. {@See elgg_get_annotations()}
+ * @return bool|null true on success, false on failure, null if no annotations to delete.
+ * @since 1.8.0
+ */
+function elgg_delete_annotations(array $options) {
+ if (!elgg_is_valid_options_for_batch_operation($options, 'annotations')) {
+ return false;
+ }
+
+ $options['metastring_type'] = 'annotations';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false);
+}
+
+/**
+ * Disables annotations based on $options.
+ *
+ * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
+ *
+ * @param array $options An options array. {@See elgg_get_annotations()}
+ * @return bool|null true on success, false on failure, null if no annotations disabled.
+ * @since 1.8.0
+ */
+function elgg_disable_annotations(array $options) {
+ if (!elgg_is_valid_options_for_batch_operation($options, 'annotations')) {
+ return false;
+ }
- /**
- * Register an annotation url handler.
- *
- * @param string $function_name The function.
- * @param string $extender_name The name, default 'all'.
- */
- function register_annotation_url_handler($function_name, $extender_name = "all") {
- return register_extender_url_handler($function_name, 'annotation', $extender_name);
- }
-
- /** Register the hook */
- register_plugin_hook("export", "all", "export_annotation_plugin_hook", 2);
-?> \ No newline at end of file
+ // 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();
+
+ $options['metastring_type'] = 'annotations';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset);
+}
+
+/**
+ * Enables annotations based on $options.
+ *
+ * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
+ *
+ * @warning In order to enable annotations, you must first use
+ * {@link access_show_hidden_entities()}.
+ *
+ * @param array $options An options array. {@See elgg_get_annotations()}
+ * @return bool|null true on success, false on failure, null if no metadata enabled.
+ * @since 1.8.0
+ */
+function elgg_enable_annotations(array $options) {
+ if (!$options || !is_array($options)) {
+ return false;
+ }
+
+ $options['metastring_type'] = 'annotations';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_enable_callback');
+}
+
+/**
+ * Returns a rendered list of annotations with pagination.
+ *
+ * @param array $options Annotation getter and display options.
+ * {@see elgg_get_annotations()} and {@see elgg_list_entities()}.
+ *
+ * @return string The list of entities
+ * @since 1.8.0
+ */
+function elgg_list_annotations($options) {
+ $defaults = array(
+ 'limit' => 25,
+ 'offset' => (int) max(get_input('annoff', 0), 0),
+ );
+
+ $options = array_merge($defaults, $options);
+
+ return elgg_list_entities($options, 'elgg_get_annotations', 'elgg_view_annotation_list');
+}
+
+/**
+ * Entities interfaces
+ */
+
+/**
+ * Returns entities based upon annotations. Also accepts all options available
+ * to elgg_get_entities() and elgg_get_entities_from_metadata().
+ *
+ * Entity creation time is selected as maxtime. To sort based upon
+ * this, pass 'order_by' => 'maxtime asc' || 'maxtime desc'
+ *
+ * @see elgg_get_entities
+ * @see elgg_get_entities_from_metadata
+ *
+ * @param array $options Array in format:
+ *
+ * annotation_names => NULL|ARR annotations names
+ *
+ * annotation_values => NULL|ARR annotations values
+ *
+ * annotation_name_value_pairs => NULL|ARR (name = 'name', value => 'value',
+ * 'operator' => '=', 'case_sensitive' => TRUE) entries.
+ * Currently if multiple values are sent via an array (value => array('value1', 'value2')
+ * 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
+ *
+ * annotation_case_sensitive => BOOL Overall Case sensitive
+ *
+ * order_by_annotation => NULL|ARR (array('name' => 'annotation_text1', 'direction' => ASC|DESC,
+ * 'as' => text|integer),
+ *
+ * Also supports array('name' => 'annotation_text1')
+ *
+ * annotation_owner_guids => NULL|ARR guids for annotaiton owners
+ *
+ * @return mixed If count, int. If not count, array. false on errors.
+ * @since 1.7.0
+ */
+function elgg_get_entities_from_annotations(array $options = array()) {
+ $defaults = array(
+ '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',
+ 'annotation_case_sensitive' => TRUE,
+ 'order_by_annotation' => array(),
+
+ 'annotation_created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
+ 'annotation_created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
+
+ 'annotation_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
+
+ 'order_by' => 'maxtime desc',
+ 'group_by' => 'a.entity_guid'
+ );
+
+ $options = array_merge($defaults, $options);
+
+ $singulars = array('annotation_name', 'annotation_value',
+ 'annotation_name_value_pair', 'annotation_owner_guid');
+
+ $options = elgg_normalise_plural_options_array($options, $singulars);
+ $options = elgg_entities_get_metastrings_options('annotation', $options);
+
+ if (!$options) {
+ return false;
+ }
+
+ // special sorting for annotations
+ //@todo overrides other sorting
+ $options['selects'][] = "max(n_table.time_created) as maxtime";
+ $options['group_by'] = 'n_table.entity_guid';
+
+ $time_wheres = elgg_get_entity_time_where_sql('a', $options['annotation_created_time_upper'],
+ $options['annotation_created_time_lower']);
+
+ if ($time_wheres) {
+ $options['wheres'] = array_merge($options['wheres'], $time_wheres);
+ }
+
+ return elgg_get_entities_from_metadata($options);
+}
+
+/**
+ * Returns a viewable list of entities from annotations.
+ *
+ * @param array $options Options array
+ *
+ * @see elgg_get_entities_from_annotations()
+ * @see elgg_list_entities()
+ *
+ * @return string
+ */
+function elgg_list_entities_from_annotations($options = array()) {
+ return elgg_list_entities($options, 'elgg_get_entities_from_annotations');
+}
+
+/**
+ * Get entities ordered by a mathematical calculation on annotation values
+ *
+ * @param array $options An options array:
+ * 'calculation' => The calculation to use. Must be a valid MySQL function.
+ * Defaults to sum. Result selected as 'annotation_calculation'.
+ * Don't confuse this "calculation" option with the
+ * "annotation_calculation" option to elgg_get_annotations().
+ * This "calculation" option is applied to each entity's set of
+ * annotations and is selected as annotation_calculation for that row.
+ * See the docs for elgg_get_annotations() for proper use of the
+ * "annotation_calculation" option.
+ * 'order_by' => The order for the sorting. Defaults to 'annotation_calculation desc'.
+ * 'annotation_names' => The names of annotations on the entity.
+ * 'annotation_values' => The values of annotations on the entity.
+ *
+ * 'metadata_names' => The name of metadata on the entity.
+ * 'metadata_values' => The value of metadata on the entitiy.
+ *
+ * @return mixed If count, int. If not count, array. false on errors.
+ */
+function elgg_get_entities_from_annotation_calculation($options) {
+ $db_prefix = elgg_get_config('dbprefix');
+ $defaults = array(
+ 'calculation' => 'sum',
+ 'order_by' => 'annotation_calculation desc'
+ );
+
+ $options = array_merge($defaults, $options);
+
+ $function = sanitize_string(elgg_extract('calculation', $options, 'sum', false));
+
+ // you must cast this as an int or it sorts wrong.
+ $options['selects'][] = 'e.*';
+ $options['selects'][] = "$function(cast(a_msv.string as signed)) as annotation_calculation";
+
+ // need our own join to get the values because the lower level functions don't
+ // add all the joins if it's a different callback.
+ $options['joins'][] = "JOIN {$db_prefix}metastrings a_msv ON n_table.value_id = a_msv.id";
+
+ // don't need access control because it's taken care of by elgg_get_annotations.
+ $options['group_by'] = 'n_table.entity_guid';
+
+ $options['callback'] = 'entity_row_to_elggstar';
+
+ // see #4393
+ // @todo remove after the 'count' shortcut is removed from elgg_get_annotations()
+ $options['__egefac'] = true;
+
+ return elgg_get_annotations($options);
+}
+
+/**
+ * List entities from an annotation calculation.
+ *
+ * @see elgg_get_entities_from_annotation_calculation()
+ *
+ * @param array $options An options array.
+ *
+ * @return string
+ */
+function elgg_list_entities_from_annotation_calculation($options) {
+ $defaults = array(
+ 'calculation' => 'sum',
+ 'order_by' => 'annotation_calculation desc'
+ );
+ $options = array_merge($defaults, $options);
+
+ return elgg_list_entities($options, 'elgg_get_entities_from_annotation_calculation');
+}
+
+/**
+ * Export the annotations for the specified entity
+ *
+ * @param string $hook 'export'
+ * @param string $type 'all'
+ * @param mixed $returnvalue Default return value
+ * @param mixed $params Parameters determining what annotations to export
+ *
+ * @elgg_plugin_hook export all
+ *
+ * @return array
+ * @throws InvalidParameterException
+ * @access private
+ */
+function export_annotation_plugin_hook($hook, $type, $returnvalue, $params) {
+ // Sanity check values
+ if ((!is_array($params)) && (!isset($params['guid']))) {
+ throw new InvalidParameterException(elgg_echo('InvalidParameterException:GUIDNotForExport'));
+ }
+
+ if (!is_array($returnvalue)) {
+ throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonArrayReturnValue'));
+ }
+
+ $guid = (int)$params['guid'];
+ $options = array('guid' => $guid, 'limit' => 0);
+ if (isset($params['name'])) {
+ $options['annotation_name'] = $params['name'];
+ }
+
+ $result = elgg_get_annotations($options);
+
+ if ($result) {
+ foreach ($result as $r) {
+ $returnvalue[] = $r->export();
+ }
+ }
+
+ return $returnvalue;
+}
+
+/**
+ * Get the URL for this item of metadata, by default this links to the
+ * export handler in the current view.
+ *
+ * @param int $id Annotation id
+ *
+ * @return mixed
+ */
+function get_annotation_url($id) {
+ $id = (int)$id;
+
+ if ($extender = elgg_get_annotation_from_id($id)) {
+ return get_extender_url($extender);
+ }
+ return false;
+}
+
+/**
+ * Check to see if a user has already created an annotation on an object
+ *
+ * @param int $entity_guid Entity guid
+ * @param string $annotation_type Type of annotation
+ * @param int $owner_guid Defaults to logged in user.
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_annotation_exists($entity_guid, $annotation_type, $owner_guid = NULL) {
+ global $CONFIG;
+
+ if (!$owner_guid && !($owner_guid = elgg_get_logged_in_user_guid())) {
+ return FALSE;
+ }
+
+ $entity_guid = sanitize_int($entity_guid);
+ $owner_guid = sanitize_int($owner_guid);
+ $annotation_type = sanitize_string($annotation_type);
+
+ $sql = "SELECT a.id FROM {$CONFIG->dbprefix}annotations a" .
+ " JOIN {$CONFIG->dbprefix}metastrings m ON a.name_id = m.id" .
+ " WHERE a.owner_guid = $owner_guid AND a.entity_guid = $entity_guid" .
+ " AND m.string = '$annotation_type'";
+
+ if (get_data_row($sql)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Return the URL for a comment
+ *
+ * @param ElggAnnotation $comment The comment object
+ * @return string
+ * @access private
+ */
+function elgg_comment_url_handler(ElggAnnotation $comment) {
+ $entity = $comment->getEntity();
+ if ($entity) {
+ return $entity->getURL() . '#item-annotation-' . $comment->id;
+ }
+ return "";
+}
+
+/**
+ * Register an annotation url handler.
+ *
+ * @param string $extender_name The name, default 'all'.
+ * @param string $function_name The function.
+ *
+ * @return string
+ */
+function elgg_register_annotation_url_handler($extender_name = "all", $function_name) {
+ return elgg_register_extender_url_handler('annotation', $extender_name, $function_name);
+}
+
+/**
+ * Register annotation unit tests
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $value
+ * @param array $params
+ * @return array
+ * @access private
+ */
+function annotations_test($hook, $type, $value, $params) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/annotations.php';
+ return $value;
+}
+
+/**
+ * Initialize the annotation library
+ * @access private
+ */
+function elgg_annotations_init() {
+ elgg_register_annotation_url_handler('generic_comment', 'elgg_comment_url_handler');
+
+ elgg_register_plugin_hook_handler("export", "all", "export_annotation_plugin_hook", 2);
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'annotations_test');
+}
+
+elgg_register_event_handler('init', 'system', 'elgg_annotations_init');