* @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 */ 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"); } /** * 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; } } else { $owner_guid = 0; } } 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 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); ?>