From d6c85011e4e5b65997732489f3ed8bc602909556 Mon Sep 17 00:00:00 2001 From: brettp Date: Tue, 13 Oct 2009 20:27:12 +0000 Subject: Standardized entities.php. git-svn-id: http://code.elgg.org/elgg/trunk@3530 36083f99-b078-4883-b0ff-0f9b5a30f544 --- engine/lib/entities.php | 5479 ++++++++++++++++++++++++----------------------- 1 file changed, 2840 insertions(+), 2639 deletions(-) (limited to 'engine/lib/entities.php') diff --git a/engine/lib/entities.php b/engine/lib/entities.php index b72eb6ff0..51d5cac25 100644 --- a/engine/lib/entities.php +++ b/engine/lib/entities.php @@ -1,1550 +1,1799 @@ + * @link http://elgg.org/ + */ + +/// Cache objects in order to minimise database access. +$ENTITY_CACHE = NULL; + +/// Cache subtype searches +$SUBTYPE_CACHE = NULL; + +/// Require the locatable interface TODO: Move this into start.php? +require_once('location.php'); + +/** + * ElggEntity The elgg entity superclass + * This class holds methods for accessing the main entities table. + * + * @author Curverider Ltd + * @package Elgg + * @subpackage Core + */ +abstract class ElggEntity implements + Notable, // Calendar interface + Locatable, // Geocoding interface + Exportable, // Allow export of data + Importable, // Allow import of data + Loggable, // Can events related to this object class be logged + Iterator, // Override foreach behaviour + ArrayAccess // Override for array access +{ /** - * Elgg entities. - * Functions to manage all elgg entities (sites, collections, objects and users). - * - * @package Elgg - * @subpackage Core - * @author Curverider Ltd - * @link http://elgg.org/ - */ - - /// Cache objects in order to minimise database access. - $ENTITY_CACHE = NULL; - - /// Cache subtype searches - $SUBTYPE_CACHE = NULL; - - /// Require the locatable interface TODO: Move this into start.php? - require_once('location.php'); - - /** - * ElggEntity The elgg entity superclass - * This class holds methods for accessing the main entities table. - * - * @author Curverider Ltd - * @package Elgg - * @subpackage Core - */ - abstract class ElggEntity implements - Notable, // Calendar interface - Locatable, // Geocoding interface - Exportable, // Allow export of data - Importable, // Allow import of data - Loggable, // Can events related to this object class be logged - Iterator, // Override foreach behaviour - ArrayAccess // Override for array access - { - /** - * The main attributes of an entity. - * Blank entries for all database fields should be created by the constructor. - * Subclasses should add to this in their constructors. - * Any field not appearing in this will be viewed as a - */ - protected $attributes; + * The main attributes of an entity. + * Blank entries for all database fields should be created by the constructor. + * Subclasses should add to this in their constructors. + * Any field not appearing in this will be viewed as a + */ + protected $attributes; - /** - * If set, overrides the value of getURL() - */ - protected $url_override; - - /** - * Icon override, overrides the value of getIcon(). - */ - protected $icon_override; - - /** - * Temporary cache for metadata, permitting meta data access before a guid has obtained. - */ - protected $temp_metadata; - - /** - * Temporary cache for annotations, permitting meta data access before a guid has obtained. - */ - protected $temp_annotations; - - /** - * Initialise the attributes array. - * This is vital to distinguish between metadata and base parameters. - * - * Place your base parameters here. - * - * @return void - */ - protected function initialise_attributes() - { - initialise_entity_cache(); - - // Create attributes array if not already created - if (!is_array($this->attributes)) $this->attributes = array(); - if (!is_array($this->temp_metadata)) $this->temp_metadata = array(); - if (!is_array($this->temp_annotations)) $this->temp_annotations = array(); - - $this->attributes['guid'] = ""; - $this->attributes['type'] = ""; - $this->attributes['subtype'] = ""; - - $this->attributes['owner_guid'] = get_loggedin_userid(); - $this->attributes['container_guid'] = get_loggedin_userid(); - - $this->attributes['site_guid'] = 0; - $this->attributes['access_id'] = ACCESS_PRIVATE; - $this->attributes['time_created'] = ""; - $this->attributes['time_updated'] = ""; - $this->attributes['enabled'] = "yes"; - - // There now follows a bit of a hack - /* Problem: To speed things up, some objects are split over several tables, this means that it requires - * n number of database reads to fully populate an entity. This causes problems for caching and create events - * since it is not possible to tell whether a subclassed entity is complete. - * Solution: We have two counters, one 'tables_split' which tells whatever is interested how many tables - * are going to need to be searched in order to fully populate this object, and 'tables_loaded' which is how - * many have been loaded thus far. - * If the two are the same then this object is complete. - * - * Use: isFullyLoaded() to check - */ - $this->attributes['tables_split'] = 1; - $this->attributes['tables_loaded'] = 0; - } - - /** - * Return the value of a given key. - * If $name is a key field (as defined in $this->attributes) that value is returned, otherwise it will - * then look to see if the value is in this object's metadata. - * - * Q: Why are we not using __get overload here? - * A: Because overload operators cause problems during subclassing, so we put the code here and - * create overloads in subclasses. - * - * @param string $name - * @return mixed Returns the value of a given value, or null. - */ - public function get($name) - { - // See if its in our base attribute - if (isset($this->attributes[$name])) { - return $this->attributes[$name]; - } - - // No, so see if its in the meta data for this entity - $meta = $this->getMetaData($name); - if ($meta) - return $meta; - - // Can't find it, so return null - return null; - } - - /** - * Set the value of a given key, replacing it if necessary. - * If $name is a base attribute (as defined in $this->attributes) that value is set, otherwise it will - * set the appropriate item of metadata. - * - * Note: It is important that your class populates $this->attributes with keys for all base attributes, anything - * not in their gets set as METADATA. - * - * Q: Why are we not using __set overload here? - * A: Because overload operators cause problems during subclassing, so we put the code here and - * create overloads in subclasses. - * - * @todo Move "title" logic to applicable extending classes. - * - * @param string $name - * @param mixed $value - */ - public function set($name, $value) - { - if (array_key_exists($name, $this->attributes)) - { - // Check that we're not trying to change the guid! - if ((array_key_exists('guid', $this->attributes)) && ($name=='guid')) - return false; - - // strip out tags from title - if ($name == 'title') { - $value = strip_tags($value); - } - - $this->attributes[$name] = $value; - } - else - return $this->setMetaData($name, $value); - - return true; - } - - /** - * Get a given piece of metadata. - * - * @param string $name - */ - public function getMetaData($name) - { - if ((int) ($this->guid) > 0) { - $md = get_metadata_byname($this->getGUID(), $name); - } else { - if (isset($this->temp_metadata[$name])) - return $this->temp_metadata[$name]; - } + /** + * If set, overrides the value of getURL() + */ + protected $url_override; - if ($md && !is_array($md)) { - return $md->value; - } else if ($md && is_array($md)) { - return metadata_array_to_values($md); - } - - return null; + /** + * Icon override, overrides the value of getIcon(). + */ + protected $icon_override; + + /** + * Temporary cache for metadata, permitting meta data access before a guid has obtained. + */ + protected $temp_metadata; + + /** + * Temporary cache for annotations, permitting meta data access before a guid has obtained. + */ + protected $temp_annotations; + + /** + * Initialise the attributes array. + * This is vital to distinguish between metadata and base parameters. + * + * Place your base parameters here. + * + * @return void + */ + protected function initialise_attributes() { + initialise_entity_cache(); + + // Create attributes array if not already created + if (!is_array($this->attributes)) { + $this->attributes = array(); } - - /** - * Class member get overloading - * - * @param string $name - * @return mixed - */ - function __get($name) { - return $this->get($name); + if (!is_array($this->temp_metadata)) { + $this->temp_metadata = array(); } - - /** - * Class member set overloading - * - * @param string $name - * @param mixed $value - * @return mixed - */ - function __set($name, $value) { - return $this->set($name, $value); + if (!is_array($this->temp_annotations)) { + $this->temp_annotations = array(); } - - /** - * Supporting isset. + + $this->attributes['guid'] = ""; + $this->attributes['type'] = ""; + $this->attributes['subtype'] = ""; + + $this->attributes['owner_guid'] = get_loggedin_userid(); + $this->attributes['container_guid'] = get_loggedin_userid(); + + $this->attributes['site_guid'] = 0; + $this->attributes['access_id'] = ACCESS_PRIVATE; + $this->attributes['time_created'] = ""; + $this->attributes['time_updated'] = ""; + $this->attributes['enabled'] = "yes"; + + // There now follows a bit of a hack + /* Problem: To speed things up, some objects are split over several tables, this means that it requires + * n number of database reads to fully populate an entity. This causes problems for caching and create events + * since it is not possible to tell whether a subclassed entity is complete. + * Solution: We have two counters, one 'tables_split' which tells whatever is interested how many tables + * are going to need to be searched in order to fully populate this object, and 'tables_loaded' which is how + * many have been loaded thus far. + * If the two are the same then this object is complete. * - * @param string $name The name of the attribute or metadata. - * @return bool + * Use: isFullyLoaded() to check */ - function __isset($name) { - if ($this->$name!="") { - return true; - } - else { + $this->attributes['tables_split'] = 1; + $this->attributes['tables_loaded'] = 0; + } + + /** + * Return the value of a given key. + * If $name is a key field (as defined in $this->attributes) that value is returned, otherwise it will + * then look to see if the value is in this object's metadata. + * + * Q: Why are we not using __get overload here? + * A: Because overload operators cause problems during subclassing, so we put the code here and + * create overloads in subclasses. + * + * @param string $name + * @return mixed Returns the value of a given value, or null. + */ + public function get($name) { + // See if its in our base attribute + if (isset($this->attributes[$name])) { + return $this->attributes[$name]; + } + + // No, so see if its in the meta data for this entity + $meta = $this->getMetaData($name); + if ($meta) { + return $meta; + } + + // Can't find it, so return null + return null; + } + + /** + * Set the value of a given key, replacing it if necessary. + * If $name is a base attribute (as defined in $this->attributes) that value is set, otherwise it will + * set the appropriate item of metadata. + * + * Note: It is important that your class populates $this->attributes with keys for all base attributes, anything + * not in their gets set as METADATA. + * + * Q: Why are we not using __set overload here? + * A: Because overload operators cause problems during subclassing, so we put the code here and + * create overloads in subclasses. + * + * @todo Move "title" logic to applicable extending classes. + * + * @param string $name + * @param mixed $value + */ + public function set($name, $value) { + if (array_key_exists($name, $this->attributes)) { + // Check that we're not trying to change the guid! + if ((array_key_exists('guid', $this->attributes)) && ($name=='guid')) { return false; } + + // strip out tags from title + if ($name == 'title') { + $value = strip_tags($value); + } + + $this->attributes[$name] = $value; } - - /** - * Supporting unsetting of magic attributes. - * - * @param string $name The name of the attribute or metadata. - */ - function __unset($name) - { - if (array_key_exists($name, $this->attributes)) - $this->attributes[$name] = ""; - else - $this->clearMetaData($name); - } - - /** - * Set a piece of metadata. - * - * @param string $name - * @param mixed $value - * @param string $value_type - * @param bool $multiple - * @return bool - */ - public function setMetaData($name, $value, $value_type = "", $multiple = false) - { - if (is_array($value)) - { - unset($this->temp_metadata[$name]); - remove_metadata($this->getGUID(), $name); - foreach ($value as $v) { - if ((int) $this->guid > 0) { - $multiple = true; - if (!create_metadata($this->getGUID(), $name, $v, $value_type, $this->getOwner(), $this->getAccessID(), $multiple)) return false; - } else { - if (($multiple) && (isset($this->temp_metadata[$name]))) - { - if (!is_array($this->temp_metadata[$name])) - { - $tmp = $this->temp_metadata[$name]; - $this->temp_metadata[$name] = array(); - $this->temp_metadata[$name][] = $tmp; - } - - $this->temp_metadata[$name][] = $value; - } - else - $this->temp_metadata[$name] = $value; - } - } - - return true; + else { + return $this->setMetaData($name, $value); + } + + return true; + } + + /** + * Get a given piece of metadata. + * + * @param string $name + */ + public function getMetaData($name) { + if ((int) ($this->guid) > 0) { + $md = get_metadata_byname($this->getGUID(), $name); + } else { + if (isset($this->temp_metadata[$name])) { + return $this->temp_metadata[$name]; } - else - { - unset($this->temp_metadata[$name]); + } + + if ($md && !is_array($md)) { + return $md->value; + } else if ($md && is_array($md)) { + return metadata_array_to_values($md); + } + + return null; + } + + /** + * 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 mixed + */ + function __set($name, $value) { + return $this->set($name, $value); + } + + /** + * Supporting isset. + * + * @param string $name The name of the attribute or metadata. + * @return bool + */ + function __isset($name) { + if ($this->$name!="") { + return true; + } + else { + return false; + } + } + + /** + * Supporting unsetting of magic attributes. + * + * @param string $name The name of the attribute or metadata. + */ + function __unset($name) { + if (array_key_exists($name, $this->attributes)) { + $this->attributes[$name] = ""; + } + else { + $this->clearMetaData($name); + } + } + + /** + * Set a piece of metadata. + * + * @param string $name + * @param mixed $value + * @param string $value_type + * @param bool $multiple + * @return bool + */ + public function setMetaData($name, $value, $value_type = "", $multiple = false) { + if (is_array($value)) { + unset($this->temp_metadata[$name]); + remove_metadata($this->getGUID(), $name); + foreach ($value as $v) { if ((int) $this->guid > 0) { - return create_metadata($this->getGUID(), $name, $value, $value_type, $this->getOwner(), $this->getAccessID(), $multiple); + $multiple = true; + if (!create_metadata($this->getGUID(), $name, $v, $value_type, + $this->getOwner(), $this->getAccessID(), $multiple)) { + return false; + } } else { - //$this->temp_metadata[$name] = $value; - - if (($multiple) && (isset($this->temp_metadata[$name]))) - { - if (!is_array($this->temp_metadata[$name])) - { + if (($multiple) && (isset($this->temp_metadata[$name]))) { + if (!is_array($this->temp_metadata[$name])) { $tmp = $this->temp_metadata[$name]; $this->temp_metadata[$name] = array(); $this->temp_metadata[$name][] = $tmp; } - + $this->temp_metadata[$name][] = $value; } - else + else { $this->temp_metadata[$name] = $value; - - return true; + } } } - } - - /** - * Clear metadata. - */ - public function clearMetaData($name = "") - { - if (empty($name)) { - return clear_metadata($this->getGUID()); - } else { - return remove_metadata($this->getGUID(),$name); - } - } - - /** - * Remove all entities associated with this entity - * - * @return true - */ - public function clearRelationships() { - remove_entity_relationships($this->getGUID()); - remove_entity_relationships($this->getGUID(),"",true); + return true; - } - - /** - * Add a relationship. - * - * @param int $guid Relationship to link to. - * @param string $relationship The type of relationship. - */ - public function addRelationship($guid, $relationship) - { - return add_entity_relationship($this->getGUID(), $relationship, $guid); - } - - function setPrivateSetting($name, $value) { - return set_private_setting($this->getGUID(), $name, $value); - } - - function getPrivateSetting($name) { - return get_private_setting($this->getGUID(), $name); - } - - function removePrivateSetting($name) { - return remove_private_setting($this->getGUID(), $name); - } - - /** - * Adds an annotation to an entity. By default, the type is detected automatically; however, - * it can also be set. Note that by default, annotations are private. - * - * @param string $name - * @param mixed $value - * @param int $access_id - * @param int $owner_id - * @param string $vartype - */ - function annotate($name, $value, $access_id = ACCESS_PRIVATE, $owner_id = 0, $vartype = "") - { + } else { + unset($this->temp_metadata[$name]); if ((int) $this->guid > 0) { - return create_annotation($this->getGUID(), $name, $value, $vartype, $owner_id, $access_id); - } else { - $this->temp_annotations[$name] = $value; - } - return true; - } - - /** - * Get the annotations for an entity. - * - * @param string $name - * @param int $limit - * @param int $offset - * @param string $order - */ - function getAnnotations($name, $limit = 50, $offset = 0, $order="asc") - { - if ((int) ($this->guid) > 0) { - return get_annotations($this->getGUID(), "", "", $name, "", 0, $limit, $offset, $order); + return create_metadata($this->getGUID(), $name, $value, $value_type, $this->getOwner(), $this->getAccessID(), $multiple); } else { - return $this->temp_annotations[$name]; + //$this->temp_metadata[$name] = $value; + + if (($multiple) && (isset($this->temp_metadata[$name]))) { + if (!is_array($this->temp_metadata[$name])) { + $tmp = $this->temp_metadata[$name]; + $this->temp_metadata[$name] = array(); + $this->temp_metadata[$name][] = $tmp; + } + + $this->temp_metadata[$name][] = $value; + } + else { + $this->temp_metadata[$name] = $value; + } + + return true; } } - - /** - * Remove all annotations or all annotations for this entity. - * - * @param string $name - */ - function clearAnnotations($name = "") - { - return clear_annotations($this->getGUID(), $name); - } - - /** - * Return the annotations for the entity. - * - * @param string $name The type of annotation. - */ - function countAnnotations($name = "") - { - return count_annotations($this->getGUID(), "","",$name); - } + } - /** - * Get the average of an integer type annotation. - * - * @param string $name - */ - function getAnnotationsAvg($name) - { - return get_annotations_avg($this->getGUID(), "","",$name); - } - - /** - * Get the sum of integer type annotations of a given name. - * - * @param string $name - */ - function getAnnotationsSum($name) - { - return get_annotations_sum($this->getGUID(), "","",$name); - } - - /** - * Get the minimum of integer type annotations of given name. - * - * @param string $name - */ - function getAnnotationsMin($name) - { - return get_annotations_min($this->getGUID(), "","",$name); - } - - /** - * Get the maximum of integer type annotations of a given name. - * - * @param string $name - */ - function getAnnotationsMax($name) - { - return get_annotations_max($this->getGUID(), "","",$name); - } - - /** - * Gets an array of entities from a specific relationship type - * - * @param string $relationship Relationship type (eg "friends") - * @param true|false $inverse Is this an inverse relationship? - * @param int $limit Number of elements to return - * @param int $offset Indexing offset - * @return array|false An array of entities or false on failure - */ - function getEntitiesFromRelationship($relationship, $inverse = false, $limit = 50, $offset = 0) { - return get_entities_from_relationship($relationship,$this->getGUID(),$inverse,"","","","time_created desc",$limit,$offset); - } - - /** - * Gets the number of of entities from a specific relationship type - * - * @param string $relationship Relationship type (eg "friends") - * @return int|false The number of entities or false on failure - */ - function countEntitiesFromRelationship($relationship) { - return get_entities_from_relationship($relationship,$this->getGUID(),false,"","","","time_created desc",null,null,true); - } - - /** - * Determines whether or not the specified user (by default the current one) can edit the entity - * - * @param int $user_guid The user GUID, optionally (defaults to the currently logged in user) - * @return true|false - */ - function canEdit($user_guid = 0) { - return can_edit_entity($this->getGUID(),$user_guid); - } - - /** - * Determines whether or not the specified user (by default the current one) can edit metadata on the entity - * - * @param ElggMetadata $metadata The piece of metadata to specifically check - * @param int $user_guid The user GUID, optionally (defaults to the currently logged in user) - * @return true|false - */ - function canEditMetadata($metadata = null, $user_guid = 0) { - return can_edit_entity_metadata($this->getGUID(), $user_guid, $metadata); + /** + * Clear metadata. + */ + public function clearMetaData($name = "") { + if (empty($name)) { + return clear_metadata($this->getGUID()); + } else { + return remove_metadata($this->getGUID(),$name); } - - /** - * Returns whether the given user (or current user) has the ability to write to this group. - * - * @param int $user_guid The user. - * @return bool - */ - public function canWriteToContainer($user_guid = 0) - { - return can_write_to_container($user_guid, $this->getGUID()); + } + + /** + * Remove all entities associated with this entity + * + * @return true + */ + public function clearRelationships() { + remove_entity_relationships($this->getGUID()); + remove_entity_relationships($this->getGUID(),"",true); + return true; + } + + /** + * Add a relationship. + * + * @param int $guid Relationship to link to. + * @param string $relationship The type of relationship. + */ + public function addRelationship($guid, $relationship) { + return add_entity_relationship($this->getGUID(), $relationship, $guid); + } + + /** + * Adds a private setting to this entity. + * + * @param $name + * @param $value + * @return unknown_type + */ + function setPrivateSetting($name, $value) { + return set_private_setting($this->getGUID(), $name, $value); + } + + /** + * Gets private setting for this entity + * + * @param $name + * @return unknown_type + */ + function getPrivateSetting($name) { + return get_private_setting($this->getGUID(), $name); + } + + /** + * Removes private setting for this entity. + * + * @param $name + * @return unknown_type + */ + function removePrivateSetting($name) { + return remove_private_setting($this->getGUID(), $name); + } + + /** + * Adds an annotation to an entity. By default, the type is detected automatically; however, + * it can also be set. Note that by default, annotations are private. + * + * @param string $name + * @param mixed $value + * @param int $access_id + * @param int $owner_id + * @param string $vartype + */ + function annotate($name, $value, $access_id = ACCESS_PRIVATE, $owner_id = 0, $vartype = "") { + if ((int) $this->guid > 0) { + return create_annotation($this->getGUID(), $name, $value, $vartype, $owner_id, $access_id); + } else { + $this->temp_annotations[$name] = $value; } - - /** - * Obtain this entity's access ID - * - * @return int The access ID - */ - public function getAccessID() { return $this->get('access_id'); } - - /** - * Obtain this entity's GUID - * - * @return int GUID - */ - public function getGUID() { return $this->get('guid'); } - - /** - * Get the owner of this entity - * - * @return int The owner GUID - */ - public function getOwner() { return $this->get('owner_guid'); } - - /** - * Returns the actual entity of the user who owns this entity, if any - * - * @return ElggEntity The owning user - */ - public function getOwnerEntity() { return get_entity($this->get('owner_guid')); } - - /** - * Gets the type of entity this is - * - * @return string Entity type - */ - public function getType() { return $this->get('type'); } - - /** - * Returns the subtype of this entity - * - * @return string The entity subtype - */ - public function getSubtype() { - if (!((int) $this->guid > 0)) return $this->get('subtype'); // If this object hasn't been saved, then return the subtype string. - - return get_subtype_from_id($this->get('subtype')); - } - - /** - * Gets the UNIX epoch time that this entity was created - * - * @return int UNIX epoch time - */ - public function getTimeCreated() { return $this->get('time_created'); } - - /** - * Gets the UNIX epoch time that this entity was last updated - * - * @return int UNIX epoch time - */ - public function getTimeUpdated() { return $this->get('time_updated'); } - - /** - * Gets the display URL for this entity - * - * @return string The URL - */ - public function getURL() { - if (!empty($this->url_override)) return $this->url_override; - return get_entity_url($this->getGUID()); + return true; + } + + /** + * Get the annotations for an entity. + * + * @param string $name + * @param int $limit + * @param int $offset + * @param string $order + */ + function getAnnotations($name, $limit = 50, $offset = 0, $order="asc") { + if ((int) ($this->guid) > 0) { + return get_annotations($this->getGUID(), "", "", $name, "", 0, $limit, $offset, $order); + } else { + return $this->temp_annotations[$name]; } - - /** - * Overrides the URL returned by getURL - * - * @param string $url The new item URL - * @return string The URL - */ - public function setURL($url) { - $this->url_override = $url; - return $url; + } + + /** + * Remove all annotations or all annotations for this entity. + * + * @param string $name + */ + function clearAnnotations($name = "") { + return clear_annotations($this->getGUID(), $name); + } + + /** + * Return the annotations for the entity. + * + * @param string $name The type of annotation. + */ + function countAnnotations($name = "") { + return count_annotations($this->getGUID(), "", "", $name); + } + + /** + * Get the average of an integer type annotation. + * + * @param string $name + */ + function getAnnotationsAvg($name) { + return get_annotations_avg($this->getGUID(), "", "", $name); + } + + /** + * Get the sum of integer type annotations of a given name. + * + * @param string $name + */ + function getAnnotationsSum($name) { + return get_annotations_sum($this->getGUID(), "", "", $name); + } + + /** + * Get the minimum of integer type annotations of given name. + * + * @param string $name + */ + function getAnnotationsMin($name) { + return get_annotations_min($this->getGUID(), "", "", $name); + } + + /** + * Get the maximum of integer type annotations of a given name. + * + * @param string $name + */ + function getAnnotationsMax($name) { + return get_annotations_max($this->getGUID(), "", "", $name); + } + + /** + * Gets an array of entities from a specific relationship type + * + * @param string $relationship Relationship type (eg "friends") + * @param true|false $inverse Is this an inverse relationship? + * @param int $limit Number of elements to return + * @param int $offset Indexing offset + * @return array|false An array of entities or false on failure + */ + function getEntitiesFromRelationship($relationship, $inverse = false, $limit = 50, $offset = 0) { + return get_entities_from_relationship($relationship, $this->getGUID(), $inverse, + "", "", "", "time_created desc", $limit, $offset); + } + + /** + * Gets the number of of entities from a specific relationship type + * + * @param string $relationship Relationship type (eg "friends") + * @return int|false The number of entities or false on failure + */ + function countEntitiesFromRelationship($relationship) { + return get_entities_from_relationship($relationship, $this->getGUID(), false, "", "", "", + "time_created desc", null, null, true); + } + + /** + * Determines whether or not the specified user (by default the current one) can edit the entity + * + * @param int $user_guid The user GUID, optionally (defaults to the currently logged in user) + * @return true|false + */ + function canEdit($user_guid = 0) { + return can_edit_entity($this->getGUID(), $user_guid); + } + + /** + * Determines whether or not the specified user (by default the current one) can edit metadata on the entity + * + * @param ElggMetadata $metadata The piece of metadata to specifically check + * @param int $user_guid The user GUID, optionally (defaults to the currently logged in user) + * @return true|false + */ + function canEditMetadata($metadata = null, $user_guid = 0) { + return can_edit_entity_metadata($this->getGUID(), $user_guid, $metadata); + } + + /** + * Returns whether the given user (or current user) has the ability to write to this group. + * + * @param int $user_guid The user. + * @return bool + */ + public function canWriteToContainer($user_guid = 0) { + return can_write_to_container($user_guid, $this->getGUID()); + } + + /** + * Obtain this entity's access ID + * + * @return int The access ID + */ + public function getAccessID() { + return $this->get('access_id'); + } + + /** + * Obtain this entity's GUID + * + * @return int GUID + */ + public function getGUID() { + return $this->get('guid'); + } + + /** + * Get the owner of this entity + * + * @return int The owner GUID + */ + public function getOwner() { + return $this->get('owner_guid'); + } + + /** + * Returns the actual entity of the user who owns this entity, if any + * + * @return ElggEntity The owning user + */ + public function getOwnerEntity() { + return get_entity($this->get('owner_guid')); + } + + /** + * Gets the type of entity this is + * + * @return string Entity type + */ + public function getType() { + return $this->get('type'); + } + + /** + * Returns the subtype of this entity + * + * @return string The entity subtype + */ + public function getSubtype() { + // If this object hasn't been saved, then return the subtype string. + if (!((int) $this->guid > 0)) { + return $this->get('subtype'); + } + + return get_subtype_from_id($this->get('subtype')); + } + + /** + * Gets the UNIX epoch time that this entity was created + * + * @return int UNIX epoch time + */ + public function getTimeCreated() { + return $this->get('time_created'); + } + + /** + * Gets the UNIX epoch time that this entity was last updated + * + * @return int UNIX epoch time + */ + public function getTimeUpdated() { + return $this->get('time_updated'); + } + + /** + * Gets the display URL for this entity + * + * @return string The URL + */ + public function getURL() { + if (!empty($this->url_override)) { + return $this->url_override; + } + return get_entity_url($this->getGUID()); + } + + /** + * Overrides the URL returned by getURL + * + * @param string $url The new item URL + * @return string The URL + */ + public function setURL($url) { + $this->url_override = $url; + return $url; + } + + /** + * Return a url for the entity's icon, trying multiple alternatives. + * + * @param string $size Either 'large','medium','small' or 'tiny' + * @return string The url or false if no url could be worked out. + */ + public function getIcon($size = 'medium') { + if (isset($this->icon_override[$size])) { + return $this->icon_override[$size]; + } + return get_entity_icon_url($this, $size); + } + + /** + * Set an icon override for an icon and size. + * + * @param string $url The url of the icon. + * @param string $size The size its for. + * @return bool + */ + public function setIcon($url, $size = 'medium') { + $url = sanitise_string($url); + $size = sanitise_string($size); + + if (!$this->icon_override) { + $this->icon_override = array(); + } + $this->icon_override[$size] = $url; + + return true; + } + + /** + * Tests to see whether the object has been fully loaded. + * + * @return bool + */ + public function isFullyLoaded() { + return ! ($this->attributes['tables_loaded'] < $this->attributes['tables_split']); + } + + /** + * Save generic attributes to the entities table. + */ + public function save() { + $guid = (int) $this->guid; + if ($guid > 0) { + cache_entity($this); + + return update_entity( + $this->get('guid'), + $this->get('owner_guid'), + $this->get('access_id'), + $this->get('container_guid') + ); + } else { + // Create a new entity (nb: using attribute array directly 'cos set function does something special!) + $this->attributes['guid'] = create_entity($this->attributes['type'], $this->attributes['subtype'], $this->attributes['owner_guid'], $this->attributes['access_id'], $this->attributes['site_guid'], $this->attributes['container_guid']); + if (!$this->attributes['guid']) { + throw new IOException(elgg_echo('IOException:BaseEntitySaveFailed')); + } + + // Save any unsaved metadata TODO: How to capture extra information (access id etc) + if (sizeof($this->temp_metadata) > 0) { + foreach($this->temp_metadata as $name => $value) { + $this->$name = $value; + unset($this->temp_metadata[$name]); + } + } + + // Save any unsaved annotations metadata. TODO: How to capture extra information (access id etc) + if (sizeof($this->temp_annotations) > 0) { + foreach($this->temp_annotations as $name => $value) { + $this->annotate($name, $value); + unset($this->temp_annotations[$name]); + } + } + + // Cache object handle + if ($this->attributes['guid']) cache_entity($this); + + return $this->attributes['guid']; + } + } + + /** + * Load the basic entity information and populate base attributes array. + * + * @param int $guid + */ + protected function load($guid) { + $row = get_entity_as_row($guid); + + if ($row) { + // Create the array if necessary - all subclasses should test before creating + if (!is_array($this->attributes)) { + $this->attributes = array(); + } + + // Now put these into the attributes array as core values + $objarray = (array) $row; + foreach($objarray as $key => $value) { + $this->attributes[$key] = $value; + } + + // Increment the portion counter + if (!$this->isFullyLoaded()) { + $this->attributes['tables_loaded']++; + } + + // Cache object handle + if ($this->attributes['guid']) { + cache_entity($this); + } + + return true; + } + + return false; + } + + /** + * Disable this entity. + * + * @param string $reason Optional reason + * @param bool $recursive Recursively disable all contained entities? + */ + public function disable($reason = "", $recursive = true) { + return disable_entity($this->get('guid'), $reason, $recursive); + } + + /** + * Re-enable this entity. + */ + public function enable() { + return enable_entity($this->get('guid')); + } + + /** + * Is this entity enabled? + * + * @return boolean + */ + public function isEnabled() { + if ($this->enabled == 'yes') { + return true; + } + + return false; + } + + /** + * Delete this entity. + */ + public function delete() { + return delete_entity($this->get('guid')); + } + + // LOCATABLE INTERFACE ///////////////////////////////////////////////////////////// + + /** Interface to set the location */ + public function setLocation($location) { + $location = sanitise_string($location); + + $this->location = $location; + + return true; + } + + /** + * Set latitude and longitude tags for a given entity. + * + * @param float $lat + * @param float $long + */ + public function setLatLong($lat, $long) { + $lat = sanitise_string($lat); + $long = sanitise_string($long); + + $this->set('geo:lat', $lat); + $this->set('geo:long', $long); + + return true; + } + + /** + * Get the contents of the ->geo:lat field. + * + */ + public function getLatitude() { + return $this->get('geo:lat'); + } + + /** + * Get the contents of the ->geo:lat field. + * + */ + public function getLongitude() { + return $this->get('geo:long'); + } + + /** + * Get the ->location metadata. + * + */ + public function getLocation() { + return $this->get('location'); + } + + // NOTABLE INTERFACE /////////////////////////////////////////////////////////////// + + /** + * Calendar functionality. + * This function sets the time of an object on a calendar listing. + * + * @param int $hour If ommitted, now is assumed. + * @param int $minute If ommitted, now is assumed. + * @param int $second If ommitted, now is assumed. + * @param int $day If ommitted, now is assumed. + * @param int $month If ommitted, now is assumed. + * @param int $year If ommitted, now is assumed. + * @param int $duration Duration of event, remainder of the day is assumed. + */ + public function setCalendarTimeAndDuration($hour = NULL, $minute = NULL, $second = NULL, $day = NULL, $month = NULL, $year = NULL, $duration = NULL) { + $start = mktime($hour, $minute, $second, $month, $day, $year); + $end = $start + abs($duration); + if (!$duration) { + $end = get_day_end($day,$month,$year); + } + + $this->calendar_start = $start; + $this->calendar_end = $end; + + return true; + } + + /** + * Return the start timestamp. + */ + public function getCalendarStartTime() { + return (int)$this->calendar_start; + } + + /** + * Return the end timestamp. + */ + public function getCalendarEndTime() { + return (int)$this->calendar_end; + } + + // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Return an array of fields which can be exported. + */ + public function getExportableValues() { + return array( + 'guid', + 'type', + 'subtype', + 'time_created', + 'container_guid', + 'owner_guid', + ); + } + + /** + * Export this class into an array of ODD Elements containing all necessary fields. + * Override if you wish to return more information than can be found in $this->attributes (shouldn't happen) + */ + public function export() { + $tmp = array(); + + // Generate uuid + $uuid = guid_to_uuid($this->getGUID()); + + // Create entity + $odd = new ODDEntity( + $uuid, + $this->attributes['type'], + get_subtype_from_id($this->attributes['subtype']) + ); + + $tmp[] = $odd; + + $exportable_values = $this->getExportableValues(); + + // Now add its attributes + foreach ($this->attributes as $k => $v) { + $meta = NULL; + + if (in_array( $k, $exportable_values)) { + switch ($k) { + case 'guid' : // Dont use guid in OpenDD + case 'type' : // Type and subtype already taken care of + case 'subtype' : + break; + + case 'time_created' : // Created = published + $odd->setAttribute('published', date("r", $v)); + break; + + case 'site_guid' : // Container + $k = 'site_uuid'; + $v = guid_to_uuid($v); + $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); + break; + + case 'container_guid' : // Container + $k = 'container_uuid'; + $v = guid_to_uuid($v); + $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); + break; + + case 'owner_guid' : // Convert owner guid to uuid, this will be stored in metadata + $k = 'owner_uuid'; + $v = guid_to_uuid($v); + $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); + break; + + default : + $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); + } + + // set the time of any metadata created + if ($meta) { + $meta->setAttribute('published', date("r",$this->time_created)); + $tmp[] = $meta; + } + } + } + + // Now we do something a bit special. + /* + * This provides a rendered view of the entity to foreign sites. + */ + + elgg_set_viewtype('default'); + $view = elgg_view_entity($this, true); + elgg_set_viewtype(); + + $tmp[] = new ODDMetaData($uuid . "volatile/renderedentity/", $uuid, 'renderedentity', $view , 'volatile'); + + return $tmp; + } + + // IMPORTABLE INTERFACE //////////////////////////////////////////////////////////// + + /** + * Import data from an parsed xml data array. + * + * @param array $data + * @param int $version + */ + public function import(ODD $data) { + if (!($data instanceof ODDEntity)) { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnexpectedODDClass')); + } + + // Set type and subtype + $this->attributes['type'] = $data->getAttribute('class'); + $this->attributes['subtype'] = $data->getAttribute('subclass'); + + // Set owner + $this->attributes['owner_guid'] = get_loggedin_userid(); // Import as belonging to importer. + + // Set time + $this->attributes['time_created'] = strtotime($data->getAttribute('published')); + $this->attributes['time_updated'] = time(); + + return true; + } + + // SYSTEM LOG INTERFACE //////////////////////////////////////////////////////////// + + /** + * Return an identification for the object for storage in the system log. + * This id must be an integer. + * + * @return int + */ + public function getSystemLogID() { + return $this->getGUID(); + } + + /** + * Return the class name of the object. + */ + public function getClassName() { + return get_class($this); + } + + /** + * 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_entity($id); + } + + /** + * Return the GUID of the owner of this object. + */ + public function getObjectOwnerGUID() { + return $this->owner_guid; + } + + // ITERATOR INTERFACE ////////////////////////////////////////////////////////////// + /* + * This lets an entity's attributes be displayed using foreach as a normal array. + * Example: http://www.sitepoint.com/print/php5-standard-library + */ + + private $valid = FALSE; + + function rewind() { + $this->valid = (FALSE !== reset($this->attributes)); + } + + function current() { + return current($this->attributes); + } + + function key() { + return key($this->attributes); + } + + function next() { + $this->valid = (FALSE !== next($this->attributes)); + } + + function valid() { + return $this->valid; + } + + // ARRAY ACCESS INTERFACE ////////////////////////////////////////////////////////// + /* + * This lets an entity's attributes be accessed like an associative array. + * Example: http://www.sitepoint.com/print/php5-standard-library + */ + + function offsetSet($key, $value) { + if ( array_key_exists($key, $this->attributes) ) { + $this->attributes[$key] = $value; + } + } + + function offsetGet($key) { + if ( array_key_exists($key, $this->attributes) ) { + return $this->attributes[$key]; + } + } + + function offsetUnset($key) { + if ( array_key_exists($key, $this->attributes) ) { + $this->attributes[$key] = ""; // Full unsetting is dangerious for our objects + } + } + + function offsetExists($offset) { + return array_key_exists($offset, $this->attributes); + } +} + +/** + * Initialise the entity cache. + */ +function initialise_entity_cache() { + global $ENTITY_CACHE; + + if (!$ENTITY_CACHE) { + //select_default_memcache('entity_cache'); // TODO: Replace with memcache? + $ENTITY_CACHE = array(); + } +} + +/** + * Invalidate this class' entry in the cache. + * + * @param int $guid The guid + */ +function invalidate_cache_for_entity($guid) { + global $ENTITY_CACHE; + + $guid = (int)$guid; + + unset($ENTITY_CACHE[$guid]); + //$ENTITY_CACHE->delete($guid); +} + +/** + * Cache an entity. + * + * @param ElggEntity $entity Entity to cache + */ +function cache_entity(ElggEntity $entity) { + global $ENTITY_CACHE; + + $ENTITY_CACHE[$entity->guid] = $entity; +} + +/** + * Retrieve a entity from the cache. + * + * @param int $guid The guid + */ +function retrieve_cached_entity($guid) { + global $ENTITY_CACHE; + + $guid = (int)$guid; + + if (isset($ENTITY_CACHE[$guid])) { + if ($ENTITY_CACHE[$guid]->isFullyLoaded()) { + return $ENTITY_CACHE[$guid]; + } + } + + return false; +} + +/** + * As retrieve_cached_entity, but returns the result as a stdClass (compatible with load functions that + * expect a database row.) + * + * @param int $guid The guid + */ +function retrieve_cached_entity_row($guid) { + $obj = retrieve_cached_entity($guid); + if ($obj) { + $tmp = new stdClass; + + foreach ($obj as $k => $v) { + $tmp->$k = $v; + } + + return $tmp; + } + + return false; +} + +/** + * Return the integer ID for a given subtype, or false. + * + * TODO: Move to a nicer place? + * + * @param string $type + * @param string $subtype + */ +function get_subtype_id($type, $subtype) { + global $CONFIG, $SUBTYPE_CACHE; + + $type = sanitise_string($type); + $subtype = sanitise_string($subtype); + + if ($subtype=="") { + return $subtype; + } + + // Todo: cache here? Or is looping less efficient that going to the db each time? + $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes + where type='$type' and subtype='$subtype'"); + + if ($result) { + if (!$SUBTYPE_CACHE) { + //select_default_memcache('subtype_cache'); + $SUBTYPE_CACHE = array(); + } + + $SUBTYPE_CACHE[$result->id] = $result; + return $result->id; + } + + return 0; +} + +/** + * For a given subtype ID, return its identifier text. + * + * TODO: Move to a nicer place? + * + * @param int $subtype_id + */ +function get_subtype_from_id($subtype_id) { + global $CONFIG, $SUBTYPE_CACHE; + + $subtype_id = (int)$subtype_id; + + if (!$subtype_id) { + return false; + } + + if (isset($SUBTYPE_CACHE[$subtype_id])) { + return $SUBTYPE_CACHE[$subtype_id]->subtype; + } + + $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where id=$subtype_id"); + if ($result) { + if (!$SUBTYPE_CACHE) { + //select_default_memcache('subtype_cache'); + $SUBTYPE_CACHE = array(); + } + + $SUBTYPE_CACHE[$subtype_id] = $result; + return $result->subtype; + } + + return false; +} + +/** + * This function tests to see if a subtype has a registered class handler. + * + * @param string $type The type + * @param string $subtype The subtype + * @return a class name or null + */ +function get_subtype_class($type, $subtype) { + global $CONFIG, $SUBTYPE_CACHE; + + $type = sanitise_string($type); + $subtype = sanitise_string($subtype); + + // Todo: cache here? Or is looping less efficient that going to the db each time? + $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes + where type='$type' and subtype='$subtype'"); + + if ($result) { + if (!$SUBTYPE_CACHE) { + //select_default_memcache('subtype_cache'); + $SUBTYPE_CACHE = array(); } - - /** - * Return a url for the entity's icon, trying multiple alternatives. - * - * @param string $size Either 'large','medium','small' or 'tiny' - * @return string The url or false if no url could be worked out. - */ - public function getIcon($size = 'medium') - { - if (isset($this->icon_override[$size])) return $this->icon_override[$size]; - return get_entity_icon_url($this, $size); - } - - /** - * Set an icon override for an icon and size. - * - * @param string $url The url of the icon. - * @param string $size The size its for. - * @return bool - */ - public function setIcon($url, $size = 'medium') - { - $url = sanitise_string($url); - $size = sanitise_string($size); - - if (!$this->icon_override) $this->icon_override = array(); - $this->icon_override[$size] = $url; - - return true; + + $SUBTYPE_CACHE[$result->id] = $result; + return $result->class; + } + + return NULL; +} + +/** + * This function tests to see if a subtype has a registered class handler by its id. + * + * @param int $subtype_id The subtype + * @return a class name or null + */ +function get_subtype_class_from_id($subtype_id) { + global $CONFIG, $SUBTYPE_CACHE; + + $subtype_id = (int)$subtype_id; + + if (!$subtype_id) { + return false; + } + + if (isset($SUBTYPE_CACHE[$subtype_id])) { + return $SUBTYPE_CACHE[$subtype_id]->class; + } + + $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where id=$subtype_id"); + + if ($result) { + if (!$SUBTYPE_CACHE) { + //select_default_memcache('subtype_cache'); + $SUBTYPE_CACHE = array(); } - - /** - * Tests to see whether the object has been fully loaded. - * - * @return bool - */ - public function isFullyLoaded() { return ! ($this->attributes['tables_loaded'] < $this->attributes['tables_split']); } - - /** - * Save generic attributes to the entities table. - */ - public function save() - { - $guid = (int) $this->guid; - if ($guid > 0) - { - cache_entity($this); + $SUBTYPE_CACHE[$subtype_id] = $result; + return $result->class; + } + + return NULL; +} + +/** + * This function will register a new subtype, returning its ID as required. + * + * @param string $type The type you're subtyping + * @param string $subtype The subtype label + * @param string $class Optional class handler (if you don't want it handled by the generic elgg handler for the type) + */ +function add_subtype($type, $subtype, $class = "") { + global $CONFIG; + $type = sanitise_string($type); + $subtype = sanitise_string($subtype); + $class = sanitise_string($class); + + // Short circuit if no subtype is given + if ($subtype == "") { + return 0; + } + + $id = get_subtype_id($type, $subtype); + + if ($id==0) { + return insert_data("insert into {$CONFIG->dbprefix}entity_subtypes (type, subtype, class) values ('$type','$subtype','$class')"); + } - return update_entity( - $this->get('guid'), - $this->get('owner_guid'), - $this->get('access_id'), - $this->get('container_guid') - ); + return $id; +} + +/** + * Update an existing entity. + * + * @param int $guid + * @param int $owner_guid + * @param int $access_id + * @param int $container_guid + */ +function update_entity($guid, $owner_guid, $access_id, $container_guid = null) { + global $CONFIG, $ENTITY_CACHE; + + $guid = (int)$guid; + $owner_guid = (int)$owner_guid; + $access_id = (int)$access_id; + $container_guid = (int) $container_guid; + if (is_null($container_guid)) { + $container_guid = $owner_guid; + } + $time = time(); + + $entity = get_entity($guid); + + if ($entity->canEdit()) { + if (trigger_elgg_event('update',$entity->type,$entity)) { + $ret = update_data("UPDATE {$CONFIG->dbprefix}entities set owner_guid='$owner_guid', access_id='$access_id', container_guid='$container_guid', time_updated='$time' WHERE guid=$guid"); + + if ($entity instanceof ElggObject) { + update_river_access_by_object($guid,$access_id); } - else - { - // Create a new entity (nb: using attribute array directly 'cos set function does something special!) - $this->attributes['guid'] = create_entity($this->attributes['type'], $this->attributes['subtype'], $this->attributes['owner_guid'], $this->attributes['access_id'], $this->attributes['site_guid'], $this->attributes['container_guid']); - if (!$this->attributes['guid']) throw new IOException(elgg_echo('IOException:BaseEntitySaveFailed')); - - // Save any unsaved metadata TODO: How to capture extra information (access id etc) - if (sizeof($this->temp_metadata) > 0) { - foreach($this->temp_metadata as $name => $value) { - $this->$name = $value; - unset($this->temp_metadata[$name]); - } - } - - // Save any unsaved annotations metadata. TODO: How to capture extra information (access id etc) - if (sizeof($this->temp_annotations) > 0) { - foreach($this->temp_annotations as $name => $value) { - $this->annotate($name, $value); - unset($this->temp_annotations[$name]); - } - } - - // Cache object handle - if ($this->attributes['guid']) cache_entity($this); - - return $this->attributes['guid']; + + // If memcache is available then delete this entry from the cache + static $newentity_cache; + if ((!$newentity_cache) && (is_memcache_available())) { + $newentity_cache = new ElggMemcache('new_entity_cache'); } - } - - /** - * Load the basic entity information and populate base attributes array. - * - * @param int $guid - */ - protected function load($guid) - { - $row = get_entity_as_row($guid); - - if ($row) - { - // Create the array if necessary - all subclasses should test before creating - if (!is_array($this->attributes)) $this->attributes = array(); - - // Now put these into the attributes array as core values - $objarray = (array) $row; - foreach($objarray as $key => $value) - $this->attributes[$key] = $value; - - // Increment the portion counter - if (!$this->isFullyLoaded()) $this->attributes['tables_loaded'] ++; - - // Cache object handle - if ($this->attributes['guid']) cache_entity($this); - - return true; + if ($newentity_cache) { + $new_entity = $newentity_cache->delete($guid); } - - return false; - } - - /** - * Disable this entity. - * - * @param string $reason Optional reason - * @param bool $recursive Recursively disable all contained entities? - */ - public function disable($reason = "", $recursive = true) - { - return disable_entity($this->get('guid'), $reason, $recursive); - } - - /** - * Re-enable this entity. - */ - public function enable() - { - return enable_entity($this->get('guid')); - } - - /** - * Is this entity enabled? - * - * @return boolean - */ - public function isEnabled() - { - if ($this->enabled == 'yes') - return true; - - return false; - } - - /** - * Delete this entity. - */ - public function delete() - { - return delete_entity($this->get('guid')); - } - - // LOCATABLE INTERFACE ///////////////////////////////////////////////////////////// - - /** Interface to set the location */ - public function setLocation($location) - { - $location = sanitise_string($location); - - $this->location = $location; - - return true; - } - - /** - * Set latitude and longitude tags for a given entity. - * - * @param float $lat - * @param float $long - */ - public function setLatLong($lat, $long) - { - $lat = sanitise_string($lat); - $long = sanitise_string($long); - - $this->set('geo:lat', $lat); - $this->set('geo:long', $long); - + + // Handle cases where there was no error BUT no rows were updated! + if ($ret===false) { + return false; + } + return true; } - - /** - * Get the contents of the ->geo:lat field. - * - */ - public function getLatitude() { return $this->get('geo:lat'); } - - /** - * Get the contents of the ->geo:lat field. - * - */ - public function getLongitude() { return $this->get('geo:long'); } - - /** - * Get the ->location metadata. - * - */ - public function getLocation() { return $this->get('location'); } - - // NOTABLE INTERFACE /////////////////////////////////////////////////////////////// - - /** - * Calendar functionality. - * This function sets the time of an object on a calendar listing. - * - * @param int $hour If ommitted, now is assumed. - * @param int $minute If ommitted, now is assumed. - * @param int $second If ommitted, now is assumed. - * @param int $day If ommitted, now is assumed. - * @param int $month If ommitted, now is assumed. - * @param int $year If ommitted, now is assumed. - * @param int $duration Duration of event, remainder of the day is assumed. - */ - public function setCalendarTimeAndDuration($hour = NULL, $minute = NULL, $second = NULL, $day = NULL, $month = NULL, $year = NULL, $duration = NULL) - { - $start = mktime($hour, $minute, $second, $month, $day, $year); - $end = $start + abs($duration); - if (!$duration) - $end = get_day_end($day,$month,$year); - - $this->calendar_start = $start; - $this->calendar_end = $end; - + } +} + +/** + * Determine whether a given user is able to write to a given container. + * + * @param int $user_guid The user guid, or 0 for get_loggedin_userid() + * @param int $container_guid The container, or 0 for the current page owner. + */ +function can_write_to_container($user_guid = 0, $container_guid = 0, $entity_type = 'all') { + global $CONFIG; + + $user_guid = (int)$user_guid; + $user = get_entity($user_guid); + if (!$user) { + $user = get_loggedin_user(); + } + + $container_guid = (int)$container_guid; + if (!$container_guid) { + $container_guid = page_owner(); + } + if (!$container_guid) { + return true; + } + + $container = get_entity($container_guid); + + if ($container) { + // If the user can edit the container, they can also write to it + if ($container->canEdit($user_guid)) { return true; } - - /** - * Return the start timestamp. - */ - public function getCalendarStartTime() { return (int)$this->calendar_start; } - - /** - * Return the end timestamp. - */ - public function getCalendarEndTime() { return (int)$this->calendar_end; } - - // EXPORTABLE INTERFACE //////////////////////////////////////////////////////////// - - /** - * Return an array of fields which can be exported. - */ - public function getExportableValues() - { - return array( - 'guid', - 'type', - 'subtype', - 'time_created', - 'container_guid', - 'owner_guid', - ); - } - - /** - * Export this class into an array of ODD Elements containing all necessary fields. - * Override if you wish to return more information than can be found in $this->attributes (shouldn't happen) - */ - public function export() - { - $tmp = array(); - - // Generate uuid - $uuid = guid_to_uuid($this->getGUID()); - - // Create entity - $odd = new ODDEntity( - $uuid, - $this->attributes['type'], - get_subtype_from_id($this->attributes['subtype']) - ); - - $tmp[] = $odd; - - $exportable_values = $this->getExportableValues(); - - // Now add its attributes - foreach ($this->attributes as $k => $v) - { - $meta = NULL; - - if (in_array( $k, $exportable_values)) { - switch ($k) - { - case 'guid' : // Dont use guid in OpenDD - case 'type' : // Type and subtype already taken care of - case 'subtype' : - break; - - case 'time_created' : // Created = published - $odd->setAttribute('published', date("r", $v)); - break; - - case 'site_guid' : // Container - $k = 'site_uuid'; - $v = guid_to_uuid($v); - $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); - break; - - case 'container_guid' : // Container - $k = 'container_uuid'; - $v = guid_to_uuid($v); - $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); - break; - - case 'owner_guid' : // Convert owner guid to uuid, this will be stored in metadata - $k = 'owner_uuid'; - $v = guid_to_uuid($v); - $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); - break; - - default : - $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); - } - - // set the time of any metadata created - if ($meta) - { - $meta->setAttribute('published', date("r",$this->time_created)); - $tmp[] = $meta; - } - } + + // Basics, see if the user is a member of the group. + if ($user && $container instanceof ElggGroup) { + if (!$container->isMember($user)) { + return false; + } else { + return true; } - - // Now we do something a bit special. - /* - * This provides a rendered view of the entity to foreign sites. - */ - - elgg_set_viewtype('default'); - $view = elgg_view_entity($this, true); - elgg_set_viewtype(); - - $tmp[] = new ODDMetaData($uuid . "volatile/renderedentity/", $uuid, 'renderedentity', $view , 'volatile'); - - - return $tmp; - } - - // IMPORTABLE INTERFACE //////////////////////////////////////////////////////////// - - /** - * Import data from an parsed xml data array. - * - * @param array $data - * @param int $version - */ - public function import(ODD $data) - { - if (!($data instanceof ODDEntity)) - throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnexpectedODDClass')); - - // Set type and subtype - $this->attributes['type'] = $data->getAttribute('class'); - $this->attributes['subtype'] = $data->getAttribute('subclass'); - - // Set owner - $this->attributes['owner_guid'] = get_loggedin_userid(); // Import as belonging to importer. - - // Set time - $this->attributes['time_created'] = strtotime($data->getAttribute('published')); - $this->attributes['time_updated'] = time(); - - return true; } - - // SYSTEM LOG INTERFACE //////////////////////////////////////////////////////////// - - /** - * Return an identification for the object for storage in the system log. - * This id must be an integer. - * - * @return int - */ - public function getSystemLogID() { return $this->getGUID(); } - - /** - * Return the class name of the object. - */ - public function getClassName() { return get_class($this); } - - /** - * 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_entity($id); } - - /** - * Return the GUID of the owner of this object. - */ - public function getObjectOwnerGUID() { return $this->owner_guid; } - - // ITERATOR INTERFACE ////////////////////////////////////////////////////////////// - /* - * This lets an entity's attributes be displayed using foreach as a normal array. - * Example: http://www.sitepoint.com/print/php5-standard-library - */ - - private $valid = FALSE; - - function rewind() - { - $this->valid = (FALSE !== reset($this->attributes)); - } - - function current() - { - return current($this->attributes); - } - - function key() - { - return key($this->attributes); - } - - function next() - { - $this->valid = (FALSE !== next($this->attributes)); - } - - function valid() - { - return $this->valid; - } - - // ARRAY ACCESS INTERFACE ////////////////////////////////////////////////////////// - /* - * This lets an entity's attributes be accessed like an associative array. - * Example: http://www.sitepoint.com/print/php5-standard-library - */ - function offsetSet($key, $value) - { - if ( array_key_exists($key, $this->attributes) ) { - $this->attributes[$key] = $value; - } - } - - function offsetGet($key) - { - if ( array_key_exists($key, $this->attributes) ) { - return $this->attributes[$key]; - } - } - - function offsetUnset($key) - { - if ( array_key_exists($key, $this->attributes) ) { - $this->attributes[$key] = ""; // Full unsetting is dangerious for our objects - } - } - - function offsetExists($offset) - { - return array_key_exists($offset, $this->attributes); - } - } - - /** - * Initialise the entity cache. - */ - function initialise_entity_cache() - { - global $ENTITY_CACHE; - - if (!$ENTITY_CACHE) - $ENTITY_CACHE = array(); //select_default_memcache('entity_cache'); // TODO: Replace with memcache? + // See if anyone else has anything to say + return trigger_plugin_hook('container_permissions_check', $entity_type, + array('container' => $container, 'user' => $user), false); } - - /** - * Invalidate this class' entry in the cache. - * - * @param int $guid The guid - */ - function invalidate_cache_for_entity($guid) - { - global $ENTITY_CACHE; - - $guid = (int)$guid; - - unset($ENTITY_CACHE[$guid]); - //$ENTITY_CACHE->delete($guid); + + return false; +} + +/** + * Create a new entity of a given type. + * + * @param string $type The type of the entity (site, user, object). + * @param string $subtype The subtype of the entity. + * @param int $owner_guid The GUID of the object's owner. + * @param int $access_id The access control group to create the entity with. + * @param int $site_guid The site to add this entity to. Leave as 0 (default) for the current site. + * @return mixed The new entity's GUID, or false on failure + */ +function create_entity($type, $subtype, $owner_guid, $access_id, $site_guid = 0, $container_guid = 0) { + global $CONFIG; + + $type = sanitise_string($type); + $subtype = add_subtype($type, $subtype); + $owner_guid = (int)$owner_guid; + $access_id = (int)$access_id; + $time = time(); + if ($site_guid == 0) { + $site_guid = $CONFIG->site_guid; } - - /** - * Cache an entity. - * - * @param ElggEntity $entity Entity to cache - */ - function cache_entity(ElggEntity $entity) - { - global $ENTITY_CACHE; - - $ENTITY_CACHE[$entity->guid] = $entity; + $site_guid = (int) $site_guid; + if ($container_guid == 0) { + $container_guid = $owner_guid; } - - /** - * Retrieve a entity from the cache. - * - * @param int $guid The guid - */ - function retrieve_cached_entity($guid) - { - global $ENTITY_CACHE; - - $guid = (int)$guid; - - if (isset($ENTITY_CACHE[$guid])) - if ($ENTITY_CACHE[$guid]->isFullyLoaded()) return $ENTITY_CACHE[$guid]; - + + $user = get_loggedin_user(); + if (!can_write_to_container($user->guid, $owner_guid, $type)) { return false; } - - /** - * As retrieve_cached_entity, but returns the result as a stdClass (compatible with load functions that - * expect a database row.) - * - * @param int $guid The guid - */ - function retrieve_cached_entity_row($guid) - { - $obj = retrieve_cached_entity($guid); - if ($obj) - { - $tmp = new stdClass; - - foreach ($obj as $k => $v) - $tmp->$k = $v; - - return $tmp; + if ($owner_guid != $container_guid) { + if (!can_write_to_container($user->guid, $container_guid, $type)) { + return false; } + } + if ($type=="") { + throw new InvalidParameterException(elgg_echo('InvalidParameterException:EntityTypeNotSet')); + } + + return insert_data("INSERT into {$CONFIG->dbprefix}entities + (type, subtype, owner_guid, site_guid, container_guid, access_id, time_created, time_updated) values + ('$type',$subtype, $owner_guid, $site_guid, $container_guid, $access_id, $time, $time)"); +} + +/** + * Retrieve the entity details for a specific GUID, returning it as a stdClass db row. + * + * You will only get an object if a) it exists, b) you have access to it. + * + * @param int $guid The GUID of the object to extract + */ +function get_entity_as_row($guid) { + global $CONFIG; + if (!$guid) { return false; } - - /** - * Return the integer ID for a given subtype, or false. - * - * TODO: Move to a nicer place? - * - * @param string $type - * @param string $subtype - */ - function get_subtype_id($type, $subtype) + + $guid = (int) $guid; + + /*$row = retrieve_cached_entity_row($guid); + if ($row) { - global $CONFIG, $SUBTYPE_CACHE; - - $type = sanitise_string($type); - $subtype = sanitise_string($subtype); - - if ($subtype=="") return $subtype; - - // Todo: cache here? Or is looping less efficient that going to the db each time? - - $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where type='$type' and subtype='$subtype'"); - - if ($result) { - - if (!$SUBTYPE_CACHE) - $SUBTYPE_CACHE = array(); //select_default_memcache('subtype_cache'); - - $SUBTYPE_CACHE[$result->id] = $result; - return $result->id; - } - - return 0; + // We have already cached this object, so retrieve its value from the cache + if (isset($CONFIG->debug) && $CONFIG->debug) + error_log("** Retrieving GUID:$guid from cache"); + + return $row; } - - /** - * For a given subtype ID, return its identifier text. - * - * TODO: Move to a nicer place? - * - * @param int $subtype_id - */ - function get_subtype_from_id($subtype_id) - { - global $CONFIG, $SUBTYPE_CACHE; - - $subtype_id = (int)$subtype_id; - - if (!$subtype_id) return false; - - if (isset($SUBTYPE_CACHE[$subtype_id])) - return $SUBTYPE_CACHE[$subtype_id]->subtype; - - $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where id=$subtype_id"); - if ($result) { - - if (!$SUBTYPE_CACHE) - $SUBTYPE_CACHE = array(); //select_default_memcache('subtype_cache'); - - $SUBTYPE_CACHE[$subtype_id] = $result; - return $result->subtype; - } - - return false; + else + {*/ + // Object not cached, load it. + if (isset($CONFIG->debug) && $CONFIG->debug == true) { + error_log("** GUID:$guid loaded from DB"); + } + + $access = get_access_sql_suffix(); + + return get_data_row("SELECT * from {$CONFIG->dbprefix}entities where guid=$guid and $access"); + //} +} + +/** + * Create an Elgg* object from a given entity row. + */ +function entity_row_to_elggstar($row) { + if (!($row instanceof stdClass)) { + return $row; } - - /** - * This function tests to see if a subtype has a registered class handler. - * - * @param string $type The type - * @param string $subtype The subtype - * @return a class name or null - */ - function get_subtype_class($type, $subtype) - { - global $CONFIG, $SUBTYPE_CACHE; - - $type = sanitise_string($type); - $subtype = sanitise_string($subtype); - - // Todo: cache here? Or is looping less efficient that going to the db each time? - - $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where type='$type' and subtype='$subtype'"); - if ($result) { - - if (!$SUBTYPE_CACHE) - $SUBTYPE_CACHE = array(); //select_default_memcache('subtype_cache'); - - $SUBTYPE_CACHE[$result->id] = $result; - return $result->class; - } - - return NULL; - } - - /** - * This function tests to see if a subtype has a registered class handler by its id. - * - * @param int $subtype_id The subtype - * @return a class name or null - */ - function get_subtype_class_from_id($subtype_id) - { - global $CONFIG, $SUBTYPE_CACHE; - - $subtype_id = (int)$subtype_id; - - if (!$subtype_id) return false; - - if (isset($SUBTYPE_CACHE[$subtype_id])) - return $SUBTYPE_CACHE[$subtype_id]->class; - - $result = get_data_row("SELECT * from {$CONFIG->dbprefix}entity_subtypes where id=$subtype_id"); - if ($result) { - - if (!$SUBTYPE_CACHE) - $SUBTYPE_CACHE = array(); //select_default_memcache('subtype_cache'); - - $SUBTYPE_CACHE[$subtype_id] = $result; - return $result->class; - } - - return NULL; - } - - /** - * This function will register a new subtype, returning its ID as required. - * - * @param string $type The type you're subtyping - * @param string $subtype The subtype label - * @param string $class Optional class handler (if you don't want it handled by the generic elgg handler for the type) - */ - function add_subtype($type, $subtype, $class = "") - { - global $CONFIG; - $type = sanitise_string($type); - $subtype = sanitise_string($subtype); - $class = sanitise_string($class); - - // Short circuit if no subtype is given - if ($subtype == "") - return 0; - - $id = get_subtype_id($type, $subtype); - - if ($id==0) - return insert_data("insert into {$CONFIG->dbprefix}entity_subtypes (type, subtype, class) values ('$type','$subtype','$class')"); - - return $id; - } - - /** - * Update an existing entity. - * - * @param int $guid - * @param int $owner_guid - * @param int $access_id - * @param int $container_guid - */ - function update_entity($guid, $owner_guid, $access_id, $container_guid = null) - { - global $CONFIG, $ENTITY_CACHE; - - $guid = (int)$guid; - $owner_guid = (int)$owner_guid; - $access_id = (int)$access_id; - $container_guid = (int) $container_guid; - if (is_null($container_guid)) $container_guid = $owner_guid; - $time = time(); - - $entity = get_entity($guid); - - if ($entity->canEdit()) { - - if (trigger_elgg_event('update',$entity->type,$entity)) { - $ret = update_data("UPDATE {$CONFIG->dbprefix}entities set owner_guid='$owner_guid', access_id='$access_id', container_guid='$container_guid', time_updated='$time' WHERE guid=$guid"); - - if ($entity instanceof ElggObject) - update_river_access_by_object($guid,$access_id); - - // If memcache is available then delete this entry from the cache - static $newentity_cache; - if ((!$newentity_cache) && (is_memcache_available())) - $newentity_cache = new ElggMemcache('new_entity_cache'); - if ($newentity_cache) $new_entity = $newentity_cache->delete($guid); - - // Handle cases where there was no error BUT no rows were updated! - if ($ret===false) - return false; - - return true; + + if ((!isset($row->guid)) || (!isset($row->subtype))) { + return $row; + } + + $new_entity = false; + + // Create a memcache cache if we can + static $newentity_cache; + if ((!$newentity_cache) && (is_memcache_available())) { + $newentity_cache = new ElggMemcache('new_entity_cache'); + } + if ($newentity_cache) { + $new_entity = $newentity_cache->load($row->guid); + } + if ($new_entity) { + return $new_entity; + } + + $classname = get_subtype_class_from_id($row->subtype); + if ($classname!="") { + if (class_exists($classname)) { + $new_entity = new $classname($row); + + if (!($new_entity instanceof ElggEntity)) { + throw new ClassException(sprintf(elgg_echo('ClassException:ClassnameNotClass'), $classname, 'ElggEntity')); } - + } + else { + error_log(sprintf(elgg_echo('ClassNotFoundException:MissingClass'), $classname)); } } - - /** - * Determine whether a given user is able to write to a given container. - * - * @param int $user_guid The user guid, or 0 for get_loggedin_userid() - * @param int $container_guid The container, or 0 for the current page owner. - */ - function can_write_to_container($user_guid = 0, $container_guid = 0, $entity_type = 'all') - { - global $CONFIG; - - $user_guid = (int)$user_guid; - $user = get_entity($user_guid); - if (!$user) $user = get_loggedin_user(); - - $container_guid = (int)$container_guid; - if (!$container_guid) $container_guid = page_owner(); - if (!$container_guid) return true; - - $container = get_entity($container_guid); - - if ($container) - { - - // If the user can edit the container, they can also write to it - if ($container->canEdit($user_guid)) return true; - - // Basics, see if the user is a member of the group. - if ($user && $container instanceof ElggGroup) { - if (!$container->isMember($user)) { - return false; - } else { - return true; - } - } - - // See if anyone else has anything to say - return trigger_plugin_hook('container_permissions_check',$entity_type,array('container' => $container, 'user' => $user), false); - + else { + switch ($row->type) { + case 'object' : + $new_entity = new ElggObject($row); break; + case 'user' : + $new_entity = new ElggUser($row); break; + case 'group' : + $new_entity = new ElggGroup($row); break; + case 'site' : + $new_entity = new ElggSite($row); break; + default: + throw new InstallationException(sprintf(elgg_echo('InstallationException:TypeNotSupported'), $row->type)); } - + } + + // Cache entity if we have a cache available + if (($newentity_cache) && ($new_entity)) { + $newentity_cache->save($new_entity->guid, $new_entity); + } + + return $new_entity; +} + +/** + * Return the entity for a given guid as the correct object. + * @param int $guid The GUID of the entity + * @return a child of ElggEntity appropriate for the type. + */ +function get_entity($guid) { + static $newentity_cache; + $new_entity = false; + if ((!$newentity_cache) && (is_memcache_available())) { + $newentity_cache = new ElggMemcache('new_entity_cache'); + } + + if ($newentity_cache) { + $new_entity = $newentity_cache->load($guid); + } + + if ($new_entity) { + return $new_entity; + } + + return entity_row_to_elggstar(get_entity_as_row($guid)); +} + +/** + * Return entities matching a given query, or the number thereof + * + * @param string $type The type of entity (eg "user", "object" etc) + * @param string|array $subtype The arbitrary subtype of the entity or array(type1 => array('subtype1', ...'subtypeN'), ...) + * @param int $owner_guid The GUID of the owning user + * @param string $order_by The field to order by; by default, time_created desc + * @param int $limit The number of entities to return; 10 by default + * @param int $offset The indexing offset, 0 by default + * @param boolean $count Set to true to get a count rather than the entities themselves (limits and offsets don't apply in this context). Defaults to false. + * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites. + * @param int|array $container_guid The container or containers to get entities from (default: all containers). + * @param int $timelower The earliest time the entity can have been created. Default: all + * @param int $timeupper The latest time the entity can have been created. Default: all + * @return array A list of entities. + */ +function get_entities($type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null, $timelower = 0, $timeupper = 0) { + global $CONFIG; + + if ($subtype === false || $subtype === null || $subtype === 0) { return false; } - - /** - * Create a new entity of a given type. - * - * @param string $type The type of the entity (site, user, object). - * @param string $subtype The subtype of the entity. - * @param int $owner_guid The GUID of the object's owner. - * @param int $access_id The access control group to create the entity with. - * @param int $site_guid The site to add this entity to. Leave as 0 (default) for the current site. - * @return mixed The new entity's GUID, or false on failure - */ - function create_entity($type, $subtype, $owner_guid, $access_id, $site_guid = 0, $container_guid = 0) - { - global $CONFIG; - - $type = sanitise_string($type); - $subtype = add_subtype($type, $subtype); - $owner_guid = (int)$owner_guid; - $access_id = (int)$access_id; - $time = time(); - if ($site_guid == 0) - $site_guid = $CONFIG->site_guid; - $site_guid = (int) $site_guid; - if ($container_guid == 0) $container_guid = $owner_guid; - - $user = get_loggedin_user(); - if (!can_write_to_container($user->guid, $owner_guid, $type)) return false; - if ($owner_guid != $container_guid) - if (!can_write_to_container($user->guid, $container_guid, $type)) return false; - - if ($type=="") throw new InvalidParameterException(elgg_echo('InvalidParameterException:EntityTypeNotSet')); - return insert_data("INSERT into {$CONFIG->dbprefix}entities (type, subtype, owner_guid, site_guid, container_guid, access_id, time_created, time_updated) values ('$type',$subtype, $owner_guid, $site_guid, $container_guid, $access_id, $time, $time)"); + if ($order_by == "") { + $order_by = "time_created desc"; } - - /** - * Retrieve the entity details for a specific GUID, returning it as a stdClass db row. - * - * You will only get an object if a) it exists, b) you have access to it. - * - * @param int $guid The GUID of the object to extract - */ - function get_entity_as_row($guid) - { - global $CONFIG; - - if (!$guid) return false; - - $guid = (int) $guid; - - /*$row = retrieve_cached_entity_row($guid); - if ($row) - { - // We have already cached this object, so retrieve its value from the cache - if (isset($CONFIG->debug) && $CONFIG->debug) - error_log("** Retrieving GUID:$guid from cache"); - - return $row; - } - else - {*/ - // Object not cached, load it. - if (isset($CONFIG->debug) && $CONFIG->debug == true) - error_log("** GUID:$guid loaded from DB"); - - $access = get_access_sql_suffix(); - - return get_data_row("SELECT * from {$CONFIG->dbprefix}entities where guid=$guid and $access"); - //} - } - - /** - * Create an Elgg* object from a given entity row. - */ - function entity_row_to_elggstar($row) - { - if (!($row instanceof stdClass)) - return $row; - - if ((!isset($row->guid)) || (!isset($row->subtype))) - return $row; - - $new_entity = false; - - // Create a memcache cache if we can - static $newentity_cache; - if ((!$newentity_cache) && (is_memcache_available())) - $newentity_cache = new ElggMemcache('new_entity_cache'); - if ($newentity_cache) $new_entity = $newentity_cache->load($row->guid); - if ($new_entity) return $new_entity; - - $classname = get_subtype_class_from_id($row->subtype); - if ($classname!="") - { - if (class_exists($classname)) - { - $new_entity = new $classname($row); - - if (!($new_entity instanceof ElggEntity)) - throw new ClassException(sprintf(elgg_echo('ClassException:ClassnameNotClass'), $classname, 'ElggEntity')); + $order_by = sanitise_string($order_by); + $limit = (int)$limit; + $offset = (int)$offset; + $site_guid = (int) $site_guid; + $timelower = (int) $timelower; + $timeupper = (int) $timeupper; + + if ($site_guid == 0) { + $site_guid = $CONFIG->site_guid; + } + + $where = array(); + + if (is_array($subtype)) { + $tempwhere = ""; + if (sizeof($subtype)) { + foreach($subtype as $typekey => $subtypearray) { + foreach($subtypearray as $subtypeval) { + $typekey = sanitise_string($typekey); + if (!empty($subtypeval)) { + if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) + return false; + } else { + // @todo: Setting subtype to 0 when $subtype = '' returns entities with + // no subtype. This is different to the non-array behavior + // but may be required in some cases. + $subtypeval = 0; + } + if (!empty($tempwhere)) $tempwhere .= " or "; + $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})"; + } } - else - error_log(sprintf(elgg_echo('ClassNotFoundException:MissingClass'), $classname)); } - else - { - switch ($row->type) - { - case 'object' : - $new_entity = new ElggObject($row); break; - case 'user' : - $new_entity = new ElggUser($row); break; - case 'group' : - $new_entity = new ElggGroup($row); break; - case 'site' : - $new_entity = new ElggSite($row); break; - default: throw new InstallationException(sprintf(elgg_echo('InstallationException:TypeNotSupported'), $row->type)); + if (!empty($tempwhere)) { + $where[] = "({$tempwhere})"; + } + } else { + $type = sanitise_string($type); + if ($subtype !== "" AND !$subtype = get_subtype_id($type, $subtype)) { + return false; + } + + if ($type != "") { + $where[] = "type='$type'"; + } + + if ($subtype!=="") { + $where[] = "subtype=$subtype"; + } + } + + if ($owner_guid != "") { + if (!is_array($owner_guid)) { + $owner_array = array($owner_guid); + $owner_guid = (int) $owner_guid; + // $where[] = "owner_guid = '$owner_guid'"; + } else if (sizeof($owner_guid) > 0) { + $owner_array = array_map('sanitise_int', $owner_guid); + // Cast every element to the owner_guid array to int + // $owner_guid = array_map("sanitise_int", $owner_guid); + // $owner_guid = implode(",",$owner_guid); + // $where[] = "owner_guid in ({$owner_guid})"; + } + if (is_null($container_guid)) { + $container_guid = $owner_array; + } + } + if ($site_guid > 0) { + $where[] = "site_guid = {$site_guid}"; + } + + if (!is_null($container_guid)) { + if (is_array($container_guid)) { + foreach($container_guid as $key => $val) { + $container_guid[$key] = (int) $val; } - + $where[] = "container_guid in (" . implode(",",$container_guid) . ")"; + } else { + $container_guid = (int) $container_guid; + $where[] = "container_guid = {$container_guid}"; } - - // Cache entity if we have a cache available - if (($newentity_cache) && ($new_entity)) $newentity_cache->save($new_entity->guid, $new_entity); - - return $new_entity; } - - /** - * Return the entity for a given guid as the correct object. - * @param int $guid The GUID of the entity - * @return a child of ElggEntity appropriate for the type. - */ - function get_entity($guid) - { - static $newentity_cache; - $new_entity = false; - if ((!$newentity_cache) && (is_memcache_available())) - $newentity_cache = new ElggMemcache('new_entity_cache'); - if ($newentity_cache) $new_entity = $newentity_cache->load($guid); - if ($new_entity) return $new_entity; - - return entity_row_to_elggstar(get_entity_as_row($guid)); - } - - /** - * Return entities matching a given query, or the number thereof - * - * @param string $type The type of entity (eg "user", "object" etc) - * @param string|array $subtype The arbitrary subtype of the entity or array(type1 => array('subtype1', ...'subtypeN'), ...) - * @param int $owner_guid The GUID of the owning user - * @param string $order_by The field to order by; by default, time_created desc - * @param int $limit The number of entities to return; 10 by default - * @param int $offset The indexing offset, 0 by default - * @param boolean $count Set to true to get a count rather than the entities themselves (limits and offsets don't apply in this context). Defaults to false. - * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites. - * @param int|array $container_guid The container or containers to get entities from (default: all containers). - * @param int $timelower The earliest time the entity can have been created. Default: all - * @param int $timeupper The latest time the entity can have been created. Default: all - * @return array A list of entities. - */ - function get_entities($type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null, $timelower = 0, $timeupper = 0) - { - global $CONFIG; - - if ($subtype === false || $subtype === null || $subtype === 0) - return false; - - if ($order_by == "") $order_by = "time_created desc"; - $order_by = sanitise_string($order_by); - $limit = (int)$limit; - $offset = (int)$offset; - $site_guid = (int) $site_guid; - $timelower = (int) $timelower; - $timeupper = (int) $timeupper; - if ($site_guid == 0) - $site_guid = $CONFIG->site_guid; - - $where = array(); - - if (is_array($subtype)) { - $tempwhere = ""; - if (sizeof($subtype)) + if ($timelower) { + $where[] = "time_created >= {$timelower}"; + } + + if ($timeupper) { + $where[] = "time_created <= {$timeupper}"; + } + + if (!$count) { + $query = "SELECT * from {$CONFIG->dbprefix}entities where "; + } else { + $query = "SELECT count(guid) as total from {$CONFIG->dbprefix}entities where "; + } + foreach ($where as $w) { + $query .= " $w and "; + } + + // Add access controls + $query .= get_access_sql_suffix(); + if (!$count) { + $query .= " order by $order_by"; + if ($limit) { + // Add order and limit + $query .= " limit $offset, $limit"; + } + $dt = get_data($query, "entity_row_to_elggstar"); + return $dt; + } else { + $total = get_data_row($query); + return $total->total; + } +} + +/** + * Returns a viewable list of entities + * + * @see elgg_view_entity_list + * + * @param string $type The type of entity (eg "user", "object" etc) + * @param string $subtype The arbitrary subtype of the entity + * @param int $owner_guid The GUID of the owning user + * @param int $limit The number of entities to display per page (default: 10) + * @param true|false $fullview Whether or not to display the full view (default: true) + * @param true|false $viewtypetoggle Whether or not to allow gallery view + * @param true|false $pagination Display pagination? Default: true + * @return string A viewable list of entities + */ +function list_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $pagination = true) { + $offset = (int) get_input('offset'); + $count = get_entities($type, $subtype, $owner_guid, "", $limit, $offset, true); + $entities = get_entities($type, $subtype, $owner_guid, "", $limit, $offset); + + return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination); +} + +/** + * Returns a viewable list of entities contained in a number of groups. + * + * @param string $subtype The arbitrary subtype of the entity + * @param int $owner_guid The GUID of the owning user + * @param int $container_guid The GUID of the containing group + * @param int $limit The number of entities to display per page (default: 10) + * @param true|false $fullview Whether or not to display the full view (default: true) + * @return string A viewable list of entities + */ +function list_entities_groups($subtype = "", $owner_guid = 0, $container_guid = 0, $limit = 10, $fullview = true) { + $offset = (int) get_input('offset'); + $count = get_objects_in_group($container_guid, $subtype, $owner_guid, 0, "", $limit, $offset, true); + $entities = get_objects_in_group($container_guid, $subtype, $owner_guid, 0, "", $limit, $offset); + + return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview); +} + +/** + * Returns a list of months containing content specified by the parameters + * + * @param string $type The type of entity + * @param string $subtype The subtype of entity + * @param int $container_guid The container GUID that the entinties belong to + * @param int $site_guid The site GUID + * @return array|false Either an array of timestamps, or false on failure + */ +function get_entity_dates($type = '', $subtype = '', $container_guid = 0, $site_guid = 0) { + global $CONFIG; + + $site_guid = (int) $site_guid; + if ($site_guid == 0) { + $site_guid = $CONFIG->site_guid; + } + $where = array(); + + if ($type != "") { + $type = sanitise_string($type); + $where[] = "type='$type'"; + } + + if (is_array($subtype)) { + $tempwhere = ""; + if (sizeof($subtype)) { foreach($subtype as $typekey => $subtypearray) { foreach($subtypearray as $subtypeval) { $typekey = sanitise_string($typekey); @@ -1552,901 +1801,811 @@ if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) return false; } else { - // @todo: Setting subtype to 0 when $subtype = '' returns entities with - // no subtype. This is different to the non-array behavior - // but may be required in some cases. $subtypeval = 0; } if (!empty($tempwhere)) $tempwhere .= " or "; $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})"; } } - if (!empty($tempwhere)) $where[] = "({$tempwhere})"; - + } + if (!empty($tempwhere)) { + $where[] = "({$tempwhere})"; + } + } else { + if ($subtype AND !$subtype = get_subtype_id($type, $subtype)) { + return false; } else { - - $type = sanitise_string($type); - if ($subtype !== "" AND !$subtype = get_subtype_id($type, $subtype)) - return false; - - if ($type != "") - $where[] = "type='$type'"; - if ($subtype!=="") - $where[] = "subtype=$subtype"; - } - - if ($owner_guid != "") { - if (!is_array($owner_guid)) { - $owner_array = array($owner_guid); - $owner_guid = (int) $owner_guid; - // $where[] = "owner_guid = '$owner_guid'"; - } else if (sizeof($owner_guid) > 0) { - $owner_array = array_map('sanitise_int', $owner_guid); - // Cast every element to the owner_guid array to int - // $owner_guid = array_map("sanitise_int", $owner_guid); - // $owner_guid = implode(",",$owner_guid); - // $where[] = "owner_guid in ({$owner_guid})"; - } - if (is_null($container_guid)) { - $container_guid = $owner_array; - } + $where[] = "subtype=$subtype"; } - if ($site_guid > 0) - $where[] = "site_guid = {$site_guid}"; + } - if (!is_null($container_guid)) { - if (is_array($container_guid)) { - foreach($container_guid as $key => $val) $container_guid[$key] = (int) $val; - $where[] = "container_guid in (" . implode(",",$container_guid) . ")"; - } else { - $container_guid = (int) $container_guid; - $where[] = "container_guid = {$container_guid}"; + if ($container_guid !== 0) { + if (is_array($container_guid)) { + foreach($container_guid as $key => $val) { + $container_guid[$key] = (int) $val; } - } - if ($timelower) - $where[] = "time_created >= {$timelower}"; - if ($timeupper) - $where[] = "time_created <= {$timeupper}"; - - if (!$count) { - $query = "SELECT * from {$CONFIG->dbprefix}entities where "; - } else { - $query = "SELECT count(guid) as total from {$CONFIG->dbprefix}entities where "; - } - foreach ($where as $w) - $query .= " $w and "; - $query .= get_access_sql_suffix(); // Add access controls - if (!$count) { - $query .= " order by $order_by"; - if ($limit) $query .= " limit $offset, $limit"; // Add order and limit - $dt = get_data($query, "entity_row_to_elggstar"); - return $dt; + $where[] = "container_guid in (" . implode(",",$container_guid) . ")"; } else { - $total = get_data_row($query); - return $total->total; + $container_guid = (int) $container_guid; + $where[] = "container_guid = {$container_guid}"; } } - - /** - * Returns a viewable list of entities - * - * @see elgg_view_entity_list - * - * @param string $type The type of entity (eg "user", "object" etc) - * @param string $subtype The arbitrary subtype of the entity - * @param int $owner_guid The GUID of the owning user - * @param int $limit The number of entities to display per page (default: 10) - * @param true|false $fullview Whether or not to display the full view (default: true) - * @param true|false $viewtypetoggle Whether or not to allow gallery view - * @param true|false $pagination Display pagination? Default: true - * @return string A viewable list of entities - */ - function list_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $pagination = true) { - - $offset = (int) get_input('offset'); - $count = get_entities($type, $subtype, $owner_guid, "", $limit, $offset, true); - $entities = get_entities($type, $subtype, $owner_guid, "", $limit, $offset); - - return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination); - - } - - /** - * Returns a viewable list of entities contained in a number of groups. - * - * @param string $subtype The arbitrary subtype of the entity - * @param int $owner_guid The GUID of the owning user - * @param int $container_guid The GUID of the containing group - * @param int $limit The number of entities to display per page (default: 10) - * @param true|false $fullview Whether or not to display the full view (default: true) - * @return string A viewable list of entities - */ - function list_entities_groups($subtype = "", $owner_guid = 0, $container_guid = 0, $limit = 10, $fullview = true) - { - $offset = (int) get_input('offset'); - $count = get_objects_in_group($container_guid, $subtype, $owner_guid, 0, "", $limit, $offset, true); - $entities = get_objects_in_group($container_guid, $subtype, $owner_guid, 0, "", $limit, $offset); - return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview); + if ($site_guid > 0) { + $where[] = "site_guid = {$site_guid}"; } - - /** - * Returns a list of months containing content specified by the parameters - * - * @param string $type The type of entity - * @param string $subtype The subtype of entity - * @param int $container_guid The container GUID that the entinties belong to - * @param int $site_guid The site GUID - * @return array|false Either an array of timestamps, or false on failure - */ - function get_entity_dates($type = '', $subtype = '', $container_guid = 0, $site_guid = 0) { - - global $CONFIG; - - $site_guid = (int) $site_guid; - if ($site_guid == 0) - $site_guid = $CONFIG->site_guid; - - $where = array(); - - if ($type != "") { - $type = sanitise_string($type); - $where[] = "type='$type'"; + + $where[] = get_access_sql_suffix(); + + $sql = "SELECT DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time_created)) AS yearmonth + FROM {$CONFIG->dbprefix}entities where "; + + foreach ($where as $w) { + $sql .= " $w and "; + } + + $sql .= "1=1"; + if ($result = get_data($sql)) { + $endresult = array(); + foreach($result as $res) { + $endresult[] = $res->yearmonth; } - - if (is_array($subtype)) { - $tempwhere = ""; - if (sizeof($subtype)) - foreach($subtype as $typekey => $subtypearray) { - foreach($subtypearray as $subtypeval) { - $typekey = sanitise_string($typekey); - if (!empty($subtypeval)) { - if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) - return false; - } else { - $subtypeval = 0; + return $endresult; + } + return false; +} + +/** + * Disable an entity but not delete it. + * + * @param int $guid The guid + * @param string $reason Optional reason + */ +function disable_entity($guid, $reason = "", $recursive = true) { + global $CONFIG; + + $guid = (int)$guid; + $reason = sanitise_string($reason); + + if ($entity = get_entity($guid)) { + if (trigger_elgg_event('disable',$entity->type,$entity)) { + if ($entity->canEdit()) { + if ($reason) { + create_metadata($guid, 'disable_reason', $reason,'', 0, ACCESS_PUBLIC); + } + + if ($recursive) { + // Temporary token overriding access controls TODO: Do this better. + static $__RECURSIVE_DELETE_TOKEN; + // Make it slightly harder to guess + $__RECURSIVE_DELETE_TOKEN = md5(get_loggedin_userid()); + + $sub_entities = get_data("SELECT * from {$CONFIG->dbprefix}entities + WHERE container_guid=$guid + or owner_guid=$guid + or site_guid=$guid", 'entity_row_to_elggstar'); + + if ($sub_entities) { + foreach ($sub_entities as $e) { + $e->disable($reason); + } } - if (!empty($tempwhere)) $tempwhere .= " or "; - $tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})"; - } - } - if (!empty($tempwhere)) $where[] = "({$tempwhere})"; - - } else { - if ($subtype AND !$subtype = get_subtype_id($type, $subtype)) { - return false; - } else { - $where[] = "subtype=$subtype"; - } - } - - if ($container_guid !== 0) { - if (is_array($container_guid)) { - foreach($container_guid as $key => $val) $container_guid[$key] = (int) $val; - $where[] = "container_guid in (" . implode(",",$container_guid) . ")"; - } else { - $container_guid = (int) $container_guid; - $where[] = "container_guid = {$container_guid}"; + + $__RECURSIVE_DELETE_TOKEN = null; + } + + $res = update_data("UPDATE {$CONFIG->dbprefix}entities + set enabled='no' + where guid={$guid}"); + + return $res; } } - - if ($site_guid > 0) - $where[] = "site_guid = {$site_guid}"; - - $where[] = get_access_sql_suffix(); - - $sql = "SELECT DISTINCT EXTRACT(YEAR_MONTH FROM FROM_UNIXTIME(time_created)) AS yearmonth FROM {$CONFIG->dbprefix}entities where "; - foreach ($where as $w) - $sql .= " $w and "; - $sql .= "1=1"; - if ($result = get_data($sql)) { - $endresult = array(); - foreach($result as $res) { - $endresult[] = $res->yearmonth; + } + return false; +} + +/** + * Enable an entity again. + * + * @param int $guid + */ +function enable_entity($guid) { + global $CONFIG; + + $guid = (int)$guid; + + // Override access only visible entities + $access_status = access_get_show_hidden_status(); + access_show_hidden_entities(true); + + if ($entity = get_entity($guid)) { + if (trigger_elgg_event('enable',$entity->type,$entity)) { + if ($entity->canEdit()) { + + access_show_hidden_entities($access_status); + + $result = update_data("UPDATE {$CONFIG->dbprefix}entities + set enabled='yes' + where guid={$guid}"); + $entity->clearMetaData('disable_reason'); + + return $result; } - return $endresult; } - return false; - } - - /** - * Disable an entity but not delete it. - * - * @param int $guid The guid - * @param string $reason Optional reason - */ - function disable_entity($guid, $reason = "", $recursive = true) - { - global $CONFIG; - - $guid = (int)$guid; - $reason = sanitise_string($reason); - - if ($entity = get_entity($guid)) { - if (trigger_elgg_event('disable',$entity->type,$entity)) { - if ($entity->canEdit()) { - - if ($reason) - create_metadata($guid, 'disable_reason', $reason,'', 0, ACCESS_PUBLIC); - - if ($recursive) - { - // Temporary token overriding access controls TODO: Do this better. - static $__RECURSIVE_DELETE_TOKEN; - $__RECURSIVE_DELETE_TOKEN = md5(get_loggedin_userid()); // Make it slightly harder to guess - - $sub_entities = get_data("SELECT * from {$CONFIG->dbprefix}entities WHERE container_guid=$guid or owner_guid=$guid or site_guid=$guid", 'entity_row_to_elggstar'); - if ($sub_entities) { - foreach ($sub_entities as $e) - $e->disable($reason); + + access_show_hidden_entities($access_status); + return false; +} + +/** + * Delete a given entity. + * + * @param int $guid + * @param bool $recursive If true (default) then all entities which are owned or contained by $guid will also be deleted. + * Note: this bypasses ownership of sub items. + */ +function delete_entity($guid, $recursive = true) { + global $CONFIG; + + $guid = (int)$guid; + if ($entity = get_entity($guid)) { + if (trigger_elgg_event('delete',$entity->type,$entity)) { + if ($entity->canEdit()) { + + // Delete contained owned and otherwise releated objects (depth first) + if ($recursive) { + // Temporary token overriding access controls TODO: Do this better. + static $__RECURSIVE_DELETE_TOKEN; + // Make it slightly harder to guess + $__RECURSIVE_DELETE_TOKEN = md5(get_loggedin_userid()); + + $sub_entities = get_data("SELECT * from {$CONFIG->dbprefix}entities + WHERE container_guid=$guid + or owner_guid=$guid + or site_guid=$guid", 'entity_row_to_elggstar'); + if ($sub_entities) { + foreach ($sub_entities as $e) { + $e->delete(); } - - $__RECURSIVE_DELETE_TOKEN = null; } - - $res = update_data("UPDATE {$CONFIG->dbprefix}entities set enabled='no' where guid={$guid}"); - - return $res; - } + + $__RECURSIVE_DELETE_TOKEN = null; + } + + // Now delete the entity itself + $entity->clearMetadata(); + $entity->clearAnnotations(); + $entity->clearRelationships(); + remove_from_river_by_subject($guid); + remove_from_river_by_object($guid); + remove_all_private_settings($guid); + $res = delete_data("DELETE from {$CONFIG->dbprefix}entities where guid={$guid}"); + if ($res) { + $sub_table = ""; + + // Where appropriate delete the sub table + switch ($entity->type) { + case 'object' : + $sub_table = $CONFIG->dbprefix . 'objects_entity'; + break; + case 'user' : + $sub_table = $CONFIG->dbprefix . 'users_entity'; + break; + case 'group' : + $sub_table = $CONFIG->dbprefix . 'groups_entity'; + break; + case 'site' : + $sub_table = $CONFIG->dbprefix . 'sites_entity'; + break; + } + + if ($sub_table) + delete_data("DELETE from $sub_table where guid={$guid}"); + } + + return $res; } } - return false; } - - /** - * Enable an entity again. - * - * @param int $guid - */ - function enable_entity($guid) - { - global $CONFIG; - - $guid = (int)$guid; - - // Override access only visible entities - $access_status = access_get_show_hidden_status(); - access_show_hidden_entities(true); - - if ($entity = get_entity($guid)) { - if (trigger_elgg_event('enable',$entity->type,$entity)) { - if ($entity->canEdit()) { - - access_show_hidden_entities($access_status); - - $result = update_data("UPDATE {$CONFIG->dbprefix}entities set enabled='yes' where guid={$guid}"); - $entity->clearMetaData('disable_reason'); - - return $result; + return false; + +} + +/** + * Delete multiple entities that match a given query. + * This function itterates through and calls delete_entity on each one, this is somewhat inefficient but lets + * the 'delete' even be called for each entity. + * + * @param string $type The type of entity (eg "user", "object" etc) + * @param string $subtype The arbitrary subtype of the entity + * @param int $owner_guid The GUID of the owning user + */ +function delete_entities($type = "", $subtype = "", $owner_guid = 0) { + $entities = get_entities($type, $subtype, $owner_guid, "time_created desc", 0); + + foreach ($entities as $entity) { + delete_entity($entity->guid); + } + + return true; +} + +/** + * A plugin hook to get certain volitile (generated on the fly) attributes about an entity in order to export them. + * + * @param unknown_type $hook + * @param unknown_type $entity_type + * @param unknown_type $returnvalue + * @param unknown_type $params The parameters, passed 'guid' and 'varname' + * @return unknown + */ +function volatile_data_export_plugin_hook($hook, $entity_type, $returnvalue, $params) { + $guid = (int)$params['guid']; + $variable_name = sanitise_string($params['varname']); + + if (($hook == 'volatile') && ($entity_type == 'metadata')) { + if (($guid) && ($variable_name)) { + switch ($variable_name) { + case 'renderedentity' : + elgg_set_viewtype('default'); + $view = elgg_view_entity(get_entity($guid)); + elgg_set_viewtype(); + + $tmp = new ElggMetadata(); + $tmp->type = 'volatile'; + $tmp->name = 'renderedentity'; + $tmp->value = $view; + $tmp->entity_guid = $guid; + + return $tmp; + + break; + } + } + } +} + +/** + * Handler called by trigger_plugin_hook on the "export" event. + */ +function export_entity_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']; + + // Get the entity + $entity = get_entity($guid); + if (!($entity instanceof ElggEntity)) { + throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class())); + } + + $export = $entity->export(); + + if (is_array($export)) { + foreach ($export as $e) { + $returnvalue[] = $e; + } + } else { + $returnvalue[] = $export; + } + + return $returnvalue; +} + +/** + * Utility function used by import_entity_plugin_hook() to process an ODDEntity into an unsaved ElggEntity. + * + * @param ODDEntity $element The OpenDD element + * @return ElggEntity the unsaved entity which should be populated by items. + */ +function oddentity_to_elggentity(ODDEntity $element) { + $class = $element->getAttribute('class'); + $subclass = $element->getAttribute('subclass'); + + // See if we already have imported this uuid + $tmp = get_entity_from_uuid($element->getAttribute('uuid')); + + if (!$tmp) { + // Construct new class with owner from session + $classname = get_subtype_class($class, $subclass); + if ($classname!="") { + if (class_exists($classname)) { + $tmp = new $classname(); + + if (!($tmp instanceof ElggEntity)) { + throw new ClassException(sprintf(elgg_echo('ClassException:ClassnameNotClass', $classname, get_class()))); } } + else + error_log(sprintf(elgg_echo('ClassNotFoundException:MissingClass'), $classname)); + } + else { + switch ($class) { + case 'object' : + $tmp = new ElggObject($row); + break; + case 'user' : + $tmp = new ElggUser($row); + break; + case 'group' : + $tmp = new ElggGroup($row); + break; + case 'site' : + $tmp = new ElggSite($row); + break; + default: + throw new InstallationException(sprintf(elgg_echo('InstallationException:TypeNotSupported'), $class)); + } } - - access_show_hidden_entities($access_status); - return false; } - - /** - * Delete a given entity. - * - * @param int $guid - * @param bool $recursive If true (default) then all entities which are owned or contained by $guid will also be deleted. - * Note: this bypasses ownership of sub items. - */ - function delete_entity($guid, $recursive = true) - { - global $CONFIG; - - $guid = (int)$guid; - if ($entity = get_entity($guid)) { - if (trigger_elgg_event('delete',$entity->type,$entity)) { - if ($entity->canEdit()) { - - // Delete contained owned and otherwise releated objects (depth first) - if ($recursive) - { - // Temporary token overriding access controls TODO: Do this better. - static $__RECURSIVE_DELETE_TOKEN; - $__RECURSIVE_DELETE_TOKEN = md5(get_loggedin_userid()); // Make it slightly harder to guess - - $sub_entities = get_data("SELECT * from {$CONFIG->dbprefix}entities WHERE container_guid=$guid or owner_guid=$guid or site_guid=$guid", 'entity_row_to_elggstar'); - if ($sub_entities) { - foreach ($sub_entities as $e) - $e->delete(); - } - - $__RECURSIVE_DELETE_TOKEN = null; - } - - // Now delete the entity itself - $entity->clearMetadata(); - $entity->clearAnnotations(); - $entity->clearRelationships(); - remove_from_river_by_subject($guid); - remove_from_river_by_object($guid); - remove_all_private_settings($guid); - $res = delete_data("DELETE from {$CONFIG->dbprefix}entities where guid={$guid}"); - if ($res) - { - $sub_table = ""; - - // Where appropriate delete the sub table - switch ($entity->type) - { - case 'object' : $sub_table = $CONFIG->dbprefix . 'objects_entity'; break; - case 'user' : $sub_table = $CONFIG->dbprefix . 'users_entity'; break; - case 'group' : $sub_table = $CONFIG->dbprefix . 'groups_entity'; break; - case 'site' : $sub_table = $CONFIG->dbprefix . 'sites_entity'; break; - } - - if ($sub_table) - delete_data("DELETE from $sub_table where guid={$guid}"); - } - - return $res; - } + + if ($tmp) { + if (!$tmp->import($element)) { + throw new ImportException(sprintf(elgg_echo('ImportException:ImportFailed'), $element->getAttribute('uuid'))); + } + + return $tmp; + } + + return NULL; +} + +/** + * Import an entity. + * This function checks the passed XML doc (as array) to see if it is a user, if so it constructs a new + * elgg user and returns "true" to inform the importer that it's been handled. + */ +function import_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) { + $element = $params['element']; + + $tmp = NULL; + + if ($element instanceof ODDEntity) { + $tmp = oddentity_to_elggentity($element); + + if ($tmp) { + // Make sure its saved + if (!$tmp->save()) { + throw new ImportException(sprintf(elgg_echo('ImportException:ProblemSaving'), $element->getAttribute('uuid'))); + } + + // Belts and braces + if (!$tmp->guid) { + throw new ImportException(elgg_echo('ImportException:NoGUID')); + } + + // We have saved, so now tag + add_uuid_to_guid($tmp->guid, $element->getAttribute('uuid')); + + return $tmp; + } + } +} + +/** + * Determines whether or not the specified user can edit the specified entity. + * + * This is extendible by registering a plugin hook taking in the parameters 'entity' and 'user', + * which are the entity and user entities respectively + * + * @see register_plugin_hook + * + * @param int $entity_guid The GUID of the entity + * @param int $user_guid The GUID of the user + * @return true|false Whether the specified user can edit the specified entity. + */ +function can_edit_entity($entity_guid, $user_guid = 0) { + global $CONFIG; + + $user_guid = (int)$user_guid; + $user = get_entity($user_guid); + if (!$user) { + $user = get_loggedin_user(); + } + + if ($entity = get_entity($entity_guid)) { + $return = false; + + // Test user if possible - should default to false unless a plugin hook says otherwise + if (!is_null($user)) { + if ($entity->getOwner() == $user->getGUID()) { + $return = true; + } + if ($entity->container_guid == $user->getGUID()) { + $return = true; + } + if ($entity->type == "user" && $entity->getGUID() == $user->getGUID()) { + $return = true; + } + if ($container_entity = get_entity($entity->container_guid)) { + if ($container_entity->canEdit()) $return = true; } } + + return trigger_plugin_hook('permissions_check', $entity->type,array('entity' => $entity, 'user' => $user), $return); + + } else { return false; - } - - /** - * Delete multiple entities that match a given query. - * This function itterates through and calls delete_entity on each one, this is somewhat inefficient but lets - * the 'delete' even be called for each entity. - * - * @param string $type The type of entity (eg "user", "object" etc) - * @param string $subtype The arbitrary subtype of the entity - * @param int $owner_guid The GUID of the owning user - */ - function delete_entities($type = "", $subtype = "", $owner_guid = 0) - { - $entities = get_entities($type, $subtype, $owner_guid, "time_created desc", 0); - - foreach ($entities as $entity) - delete_entity($entity->guid); - - return true; +} + +/** + * Determines whether or not the specified user can edit metadata on the specified entity. + * + * This is extendible by registering a plugin hook taking in the parameters 'entity' and 'user', + * which are the entity and user entities respectively + * + * @see register_plugin_hook + * + * @param int $entity_guid The GUID of the entity + * @param int $user_guid The GUID of the user + * @param ElggMetadata $metadata The metadata to specifically check (if any; default null) + * @return true|false Whether the specified user can edit the specified entity. + */ +function can_edit_entity_metadata($entity_guid, $user_guid = 0, $metadata = null) { + if ($entity = get_entity($entity_guid)) { + + $return = null; + + if ($metadata->owner_guid == 0) { + $return = true; + } + if (is_null($return)) { + $return = can_edit_entity($entity_guid, $user_guid); + } + + $user = get_entity($user_guid); + $return = trigger_plugin_hook('permissions_check:metadata',$entity->type,array('entity' => $entity, 'user' => $user, 'metadata' => $metadata),$return); + return $return; + } else { + return false; } - - /** - * A plugin hook to get certain volitile (generated on the fly) attributes about an entity in order to export them. - * - * @param unknown_type $hook - * @param unknown_type $entity_type - * @param unknown_type $returnvalue - * @param unknown_type $params The parameters, passed 'guid' and 'varname' - * @return unknown - */ - function volatile_data_export_plugin_hook($hook, $entity_type, $returnvalue, $params) - { - $guid = (int)$params['guid']; - $variable_name = sanitise_string($params['varname']); - - if (($hook == 'volatile') && ($entity_type == 'metadata')) - { - if (($guid) && ($variable_name)) - { - switch ($variable_name) - { - case 'renderedentity' : - elgg_set_viewtype('default'); - $view = elgg_view_entity(get_entity($guid)); - elgg_set_viewtype(); - - $tmp = new ElggMetadata(); - $tmp->type = 'volatile'; - $tmp->name = 'renderedentity'; - $tmp->value = $view; - $tmp->entity_guid = $guid; - - return $tmp; - - break; - } +} + + +/** + * Get the icon for an entity + * + * @param ElggEntity $entity The entity (passed an entity rather than a guid to handle non-created entities) + * @param string $size + */ +function get_entity_icon_url(ElggEntity $entity, $size = 'medium') { + global $CONFIG; + + $size = sanitise_string($size); + switch (strtolower($size)) { + case 'master': + $size = 'master'; + break; + + case 'large' : + $size = 'large'; + break; + + case 'topbar' : + $size = 'topbar'; + break; + + case 'tiny' : + $size = 'tiny'; + break; + + case 'small' : + $size = 'small'; + break; + + case 'medium' : + default: + $size = 'medium'; + } + + $url = false; + + $viewtype = elgg_get_viewtype(); + + // Step one, see if anyone knows how to render this in the current view + $url = trigger_plugin_hook('entity:icon:url', $entity->getType(), array('entity' => $entity, 'viewtype' => $viewtype, 'size' => $size), $url); + + // Fail, so use default + if (!$url) { + $type = $entity->getType(); + $subtype = $entity->getSubtype(); + + if (!empty($subtype)) { + $overrideurl = elgg_view("icon/{$type}/{$subtype}/{$size}",array('entity' => $entity)); + if (!empty($overrideurl)) { + return $overrideurl; } } + + $overrideurl = elgg_view("icon/{$type}/default/{$size}",array('entity' => $entity)); + if (!empty($overrideurl)) { + return $overrideurl; + } + + $url = $CONFIG->url . "_graphics/icons/default/$size.png"; } - /** - * Handler called by trigger_plugin_hook on the "export" event. - */ - function export_entity_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']; - - // Get the entity - $entity = get_entity($guid); - if (!($entity instanceof ElggEntity)) - throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class())); - - $export = $entity->export(); - - if (is_array($export)) - foreach ($export as $e) - $returnvalue[] = $e; - else - $returnvalue[] = $export; - - return $returnvalue; - } - - /** - * Utility function used by import_entity_plugin_hook() to process an ODDEntity into an unsaved ElggEntity. - * - * @param ODDEntity $element The OpenDD element - * @return ElggEntity the unsaved entity which should be populated by items. - */ - function oddentity_to_elggentity(ODDEntity $element) - { - $class = $element->getAttribute('class'); - $subclass = $element->getAttribute('subclass'); - - // See if we already have imported this uuid - $tmp = get_entity_from_uuid($element->getAttribute('uuid')); - - if (!$tmp) - { - // Construct new class with owner from session - $classname = get_subtype_class($class, $subclass); - if ($classname!="") - { - if (class_exists($classname)) - { - $tmp = new $classname(); - - if (!($tmp instanceof ElggEntity)) - throw new ClassException(sprintf(elgg_echo('ClassException:ClassnameNotClass', $classname, get_class()))); - } - else - error_log(sprintf(elgg_echo('ClassNotFoundException:MissingClass'), $classname)); + return $url; +} + +/** + * Gets the URL for an entity, given a particular GUID + * + * @param int $entity_guid The GUID of the entity + * @return string The URL of the entity + */ +function get_entity_url($entity_guid) { + global $CONFIG; + + if ($entity = get_entity($entity_guid)) { + $url = ""; + + if (isset($CONFIG->entity_url_handler[$entity->getType()][$entity->getSubType()])) { + $function = $CONFIG->entity_url_handler[$entity->getType()][$entity->getSubType()]; + if (is_callable($function)) { + $url = $function($entity); } - else - { - switch ($class) - { - case 'object' : $tmp = new ElggObject($row); break; - case 'user' : $tmp = new ElggUser($row); break; - case 'group' : $tmp = new ElggGroup($row); break; - case 'site' : $tmp = new ElggSite($row); break; - default: throw new InstallationException(sprintf(elgg_echo('InstallationException:TypeNotSupported'), $class)); - } + } elseif (isset($CONFIG->entity_url_handler[$entity->getType()]['all'])) { + $function = $CONFIG->entity_url_handler[$entity->getType()]['all']; + if (is_callable($function)) { + $url = $function($entity); + } + } elseif (isset($CONFIG->entity_url_handler['all']['all'])) { + $function = $CONFIG->entity_url_handler['all']['all']; + if (is_callable($function)) { + $url = $function($entity); } } - - if ($tmp) - { - if (!$tmp->import($element)) - throw new ImportException(sprintf(elgg_echo('ImportException:ImportFailed'), $element->getAttribute('uuid'))); - - return $tmp; + + if ($url == "") { + $url = $CONFIG->url . "pg/view/" . $entity_guid; + } + return $url; + + } + + return false; +} + +/** + * Sets the URL handler for a particular entity type and subtype + * + * @param string $function_name The function to register + * @param string $entity_type The entity type + * @param string $entity_subtype The entity subtype + * @return true|false Depending on success + */ +function register_entity_url_handler($function_name, $entity_type = "all", $entity_subtype = "all") { + global $CONFIG; + + if (!is_callable($function_name)) { + return false; + } + + if (!isset($CONFIG->entity_url_handler)) { + $CONFIG->entity_url_handler = array(); + } + + if (!isset($CONFIG->entity_url_handler[$entity_type])) { + $CONFIG->entity_url_handler[$entity_type] = array(); + } + + $CONFIG->entity_url_handler[$entity_type][$entity_subtype] = $function_name; + + return true; +} + +/** + * Default Icon URL handler for entities. + * This will attempt to find a default entity for the current view and return a url. This is registered at + * a low priority so that other handlers will pick it up first. + * + * @param unknown_type $hook + * @param unknown_type $entity_type + * @param unknown_type $returnvalue + * @param unknown_type $params + */ +function default_entity_icon_hook($hook, $entity_type, $returnvalue, $params) { + global $CONFIG; + + if ((!$returnvalue) && ($hook == 'entity:icon:url')) { + $entity = $params['entity']; + $type = $entity->type; + $subtype = get_subtype_from_id($entity->subtype); + $viewtype = $params['viewtype']; + $size = $params['size']; + + $url = "views/$viewtype/graphics/icons/$type/$subtype/$size.png"; + + if (!@file_exists($CONFIG->path . $url)) { + $url = "views/$viewtype/graphics/icons/$type/default/$size.png"; + } + + if(!@file_exists($CONFIG->path . $url)) { + $url = "views/$viewtype/graphics/icons/default/$size.png"; } - - return NULL; - } - - /** - * Import an entity. - * This function checks the passed XML doc (as array) to see if it is a user, if so it constructs a new - * elgg user and returns "true" to inform the importer that it's been handled. - */ - function import_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) - { - $element = $params['element']; - - $tmp = NULL; - - if ($element instanceof ODDEntity) - { - $tmp = oddentity_to_elggentity($element); - - if ($tmp) - { - if (!$tmp->save()) // Make sure its saved - throw new ImportException(sprintf(elgg_echo('ImportException:ProblemSaving'), $element->getAttribute('uuid'))); - - // Belts and braces - if (!$tmp->guid) - throw new ImportException(elgg_echo('ImportException:NoGUID')); - - add_uuid_to_guid($tmp->guid, $element->getAttribute('uuid')); // We have saved, so now tag - - return $tmp; - } - + + if (@file_exists($CONFIG->path . $url)) { + return $CONFIG->url . $url; } } - - /** - * Determines whether or not the specified user can edit the specified entity. - * - * This is extendible by registering a plugin hook taking in the parameters 'entity' and 'user', - * which are the entity and user entities respectively - * - * @see register_plugin_hook - * - * @param int $entity_guid The GUID of the entity - * @param int $user_guid The GUID of the user - * @return true|false Whether the specified user can edit the specified entity. - */ - function can_edit_entity($entity_guid, $user_guid = 0) { - global $CONFIG; - - $user_guid = (int)$user_guid; - $user = get_entity($user_guid); - if (!$user) $user = get_loggedin_user(); - - if ($entity = get_entity($entity_guid)) { - - $return = false; - - // Test user if possible - should default to false unless a plugin hook says otherwise - if (!is_null($user)) - { - if ($entity->getOwner() == $user->getGUID()) $return = true; - if ($entity->container_guid == $user->getGUID()) $return = true; - if ($entity->type == "user" && $entity->getGUID() == $user->getGUID()) $return = true; - if ($container_entity = get_entity($entity->container_guid)) { - if ($container_entity->canEdit()) $return = true; - } - } - - return trigger_plugin_hook('permissions_check',$entity->type,array('entity' => $entity, 'user' => $user), $return); - - } else { - return false; - - } - +} + +/** + * Registers and entity type and subtype to return in search and other places. + * A description in the elgg_echo languages file of the form item:type:subtype + * is also expected. + * + * @param string $type The type of entity (object, site, user, group) + * @param string $subtype The subtype to register (may be blank) + * @return true|false Depending on success + */ +function register_entity_type($type, $subtype) { + global $CONFIG; + + $type = strtolower($type); + if (!in_array($type,array('object','site','group','user'))) { + return false; } - - /** - * Determines whether or not the specified user can edit metadata on the specified entity. - * - * This is extendible by registering a plugin hook taking in the parameters 'entity' and 'user', - * which are the entity and user entities respectively - * - * @see register_plugin_hook - * - * @param int $entity_guid The GUID of the entity - * @param int $user_guid The GUID of the user - * @param ElggMetadata $metadata The metadata to specifically check (if any; default null) - * @return true|false Whether the specified user can edit the specified entity. - */ - function can_edit_entity_metadata($entity_guid, $user_guid = 0, $metadata = null) { - - if ($entity = get_entity($entity_guid)) { - - $return = null; - - if ($metadata->owner_guid == 0) $return = true; - if (is_null($return)) - $return = can_edit_entity($entity_guid, $user_guid); - - $user = get_entity($user_guid); - $return = trigger_plugin_hook('permissions_check:metadata',$entity->type,array('entity' => $entity, 'user' => $user, 'metadata' => $metadata),$return); - return $return; - } else { - return false; - } - + if (!isset($CONFIG->registered_entities)) { + $CONFIG->registered_entities = array(); } - - - /** - * Get the icon for an entity - * - * @param ElggEntity $entity The entity (passed an entity rather than a guid to handle non-created entities) - * @param string $size - */ - function get_entity_icon_url(ElggEntity $entity, $size = 'medium') - { - global $CONFIG; - - $size = sanitise_string($size); - switch (strtolower($size)) - { - case 'master': $size = 'master'; break; - - case 'large' : $size = 'large'; break; - - case 'topbar' : $size = 'topbar'; break; - - case 'tiny' : $size = 'tiny'; break; - - case 'small' : $size = 'small'; break; - - case 'medium' : - default: $size = 'medium'; - } - - $url = false; - - $viewtype = elgg_get_viewtype(); - - // Step one, see if anyone knows how to render this in the current view - $url = trigger_plugin_hook('entity:icon:url', $entity->getType(), array('entity' => $entity, 'viewtype' => $viewtype, 'size' => $size), $url); - - // Fail, so use default - if (!$url) { - - $type = $entity->getType(); - $subtype = $entity->getSubtype(); - - if (!empty($subtype)) { - $overrideurl = elgg_view("icon/{$type}/{$subtype}/{$size}",array('entity' => $entity)); - if (!empty($overrideurl)) return $overrideurl; - } + $CONFIG->registered_entities[$type][] = $subtype; - $overrideurl = elgg_view("icon/{$type}/default/{$size}",array('entity' => $entity)); - if (!empty($overrideurl)) return $overrideurl; - - $url = $CONFIG->url . "_graphics/icons/default/$size.png"; - } - - return $url; + return true; + +} + +/** + * Returns registered entity types and subtypes + * + * @see register_entity_type + * + * @param string $type The type of entity (object, site, user, group) or blank for all + * @return array|false Depending on whether entities have been registered + */ +function get_registered_entity_types($type = '') { + global $CONFIG; + + if (!isset($CONFIG->registered_entities)) { + return false; + } + if (!empty($type)) { + $type = strtolower($type); + } + if (!empty($type) && empty($CONFIG->registered_entities[$type])) { + return false; } - - /** - * Gets the URL for an entity, given a particular GUID - * - * @param int $entity_guid The GUID of the entity - * @return string The URL of the entity - */ - function get_entity_url($entity_guid) { - - global $CONFIG; - if ($entity = get_entity($entity_guid)) { - - $url = ""; - - if (isset($CONFIG->entity_url_handler[$entity->getType()][$entity->getSubType()])) { - $function = $CONFIG->entity_url_handler[$entity->getType()][$entity->getSubType()]; - if (is_callable($function)) { - $url = $function($entity); - } - } elseif (isset($CONFIG->entity_url_handler[$entity->getType()]['all'])) { - $function = $CONFIG->entity_url_handler[$entity->getType()]['all']; - if (is_callable($function)) { - $url = $function($entity); - } - } elseif (isset($CONFIG->entity_url_handler['all']['all'])) { - $function = $CONFIG->entity_url_handler['all']['all']; - if (is_callable($function)) { - $url = $function($entity); - } - } - if ($url == "") { - $url = $CONFIG->url . "pg/view/" . $entity_guid; - } - return $url; - - } + if (empty($type)) { + return $CONFIG->registered_entities; + } + + return $CONFIG->registered_entities[$type]; +} + +/** + * Determines whether or not the specified entity type and subtype have been registered in the system + * + * @param string $type The type of entity (object, site, user, group) + * @param string $subtype The subtype (may be blank) + * @return true|false Depending on whether or not the type has been registered + */ +function is_registered_entity_type($type, $subtype) { + global $CONFIG; + + if (!isset($CONFIG->registered_entities)) { return false; - } - - /** - * Sets the URL handler for a particular entity type and subtype - * - * @param string $function_name The function to register - * @param string $entity_type The entity type - * @param string $entity_subtype The entity subtype - * @return true|false Depending on success - */ - function register_entity_url_handler($function_name, $entity_type = "all", $entity_subtype = "all") { - global $CONFIG; - - if (!is_callable($function_name)) return false; - - if (!isset($CONFIG->entity_url_handler)) { - $CONFIG->entity_url_handler = array(); - } - if (!isset($CONFIG->entity_url_handler[$entity_type])) { - $CONFIG->entity_url_handler[$entity_type] = array(); - } - $CONFIG->entity_url_handler[$entity_type][$entity_subtype] = $function_name; - - return true; - + $type = strtolower($type); + if (empty($CONFIG->registered_entities[$type])) { + return false; } - - /** - * Default Icon URL handler for entities. - * This will attempt to find a default entity for the current view and return a url. This is registered at - * a low priority so that other handlers will pick it up first. - * - * @param unknown_type $hook - * @param unknown_type $entity_type - * @param unknown_type $returnvalue - * @param unknown_type $params - */ - function default_entity_icon_hook($hook, $entity_type, $returnvalue, $params) - { - global $CONFIG; - - if ((!$returnvalue) && ($hook == 'entity:icon:url')) - { - $entity = $params['entity']; - $type = $entity->type; - $subtype = get_subtype_from_id($entity->subtype); - $viewtype = $params['viewtype']; - $size = $params['size']; - - $url = "views/$viewtype/graphics/icons/$type/$subtype/$size.png"; - - if (!@file_exists($CONFIG->path . $url)) - $url = "views/$viewtype/graphics/icons/$type/default/$size.png"; - - if(!@file_exists($CONFIG->path . $url)) - $url = "views/$viewtype/graphics/icons/default/$size.png"; - - if (@file_exists($CONFIG->path . $url)) - return $CONFIG->url . $url; - } - } - - /** - * Registers and entity type and subtype to return in search and other places. - * A description in the elgg_echo languages file of the form item:type:subtype - * is also expected. - * - * @param string $type The type of entity (object, site, user, group) - * @param string $subtype The subtype to register (may be blank) - * @return true|false Depending on success - */ - function register_entity_type($type, $subtype) { - - global $CONFIG; - - $type = strtolower($type); - if (!in_array($type,array('object','site','group','user'))) return false; - - if (!isset($CONFIG->registered_entities)) $CONFIG->registered_entities = array(); - $CONFIG->registered_entities[$type][] = $subtype; - + if (in_array($subtype, $CONFIG->registered_entities[$type])) { return true; - } - - /** - * Returns registered entity types and subtypes - * - * @see register_entity_type - * - * @param string $type The type of entity (object, site, user, group) or blank for all - * @return array|false Depending on whether entities have been registered - */ - function get_registered_entity_types($type = '') { - - global $CONFIG; - - if (!isset($CONFIG->registered_entities)) return false; - if (!empty($type)) $type = strtolower($type); - if (!empty($type) && empty($CONFIG->registered_entities[$type])) return false; - - if (empty($type)) - return $CONFIG->registered_entities; - - return $CONFIG->registered_entities[$type]; - - } - - /** - * Determines whether or not the specified entity type and subtype have been registered in the system - * - * @param string $type The type of entity (object, site, user, group) - * @param string $subtype The subtype (may be blank) - * @return true|false Depending on whether or not the type has been registered - */ - function is_registered_entity_type($type, $subtype) { - + +} + +/** + * Page handler for generic entities view system + * + * @param array $page Page elements from pain page handler + */ +function entities_page_handler($page) { + if (isset($page[0])) { global $CONFIG; - - if (!isset($CONFIG->registered_entities)) return false; - $type = strtolower($type); - if (empty($CONFIG->registered_entities[$type])) return false; - if (in_array($subtype, $CONFIG->registered_entities[$type])) return true; - - } - - /** - * Page handler for generic entities view system - * - * @param array $page Page elements from pain page handler - */ - function entities_page_handler($page) { - if (isset($page[0])) { - global $CONFIG; - set_input('guid',$page[0]); - include($CONFIG->path . "entities/index.php"); - } + set_input('guid',$page[0]); + include($CONFIG->path . "entities/index.php"); } - - /** - * Returns a viewable list of entities based on the registered types - * - * @see elgg_view_entity_list - * - * @param string $type The type of entity (eg "user", "object" etc) - * @param string $subtype The arbitrary subtype of the entity - * @param int $owner_guid The GUID of the owning user - * @param int $limit The number of entities to display per page (default: 10) - * @param true|false $fullview Whether or not to display the full view (default: true) - * @param true|false $viewtypetoggle Whether or not to allow gallery view - * @return string A viewable list of entities - */ - function list_registered_entities($owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $allowedtypes = true) { - - $typearray = array(); - - if ($object_types = get_registered_entity_types()) { - foreach($object_types as $object_type => $subtype_array) { - if (is_array($subtype_array) && sizeof($subtype_array) && (in_array($object_type,$allowedtypes) || $allowedtypes === true)) - foreach($subtype_array as $object_subtype) { - $typearray[$object_type][] = $object_subtype; - } +} + +/** + * Returns a viewable list of entities based on the registered types + * + * @see elgg_view_entity_list + * + * @param string $type The type of entity (eg "user", "object" etc) + * @param string $subtype The arbitrary subtype of the entity + * @param int $owner_guid The GUID of the owning user + * @param int $limit The number of entities to display per page (default: 10) + * @param true|false $fullview Whether or not to display the full view (default: true) + * @param true|false $viewtypetoggle Whether or not to allow gallery view + * @return string A viewable list of entities + */ +function list_registered_entities($owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $allowedtypes = true) { + $typearray = array(); + + if ($object_types = get_registered_entity_types()) { + foreach($object_types as $object_type => $subtype_array) { + if (is_array($subtype_array) && sizeof($subtype_array) && (in_array($object_type,$allowedtypes) || $allowedtypes === true)) { + foreach($subtype_array as $object_subtype) { + $typearray[$object_type][] = $object_subtype; + } } } - - $offset = (int) get_input('offset'); - $count = get_entities('', $typearray, $owner_guid, "", $limit, $offset, true); - $entities = get_entities('', $typearray,$owner_guid, "", $limit, $offset); + } + + $offset = (int) get_input('offset'); + $count = get_entities('', $typearray, $owner_guid, "", $limit, $offset, true); + $entities = get_entities('', $typearray,$owner_guid, "", $limit, $offset); + + return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle); +} - return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle); - +/** + * Get entities based on their private data, in a similar way to metadata. + * + * @param string $name The name of the setting + * @param string $value The value of the setting + * @param string $type The type of entity (eg "user", "object" etc) + * @param string $subtype The arbitrary subtype of the entity + * @param int $owner_guid The GUID of the owning user + * @param string $order_by The field to order by; by default, time_created desc + * @param int $limit The number of entities to return; 10 by default + * @param int $offset The indexing offset, 0 by default + * @param boolean $count Set to true to get a count rather than the entities themselves (limits and offsets don't apply in this context). Defaults to false. + * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites. + * @param int|array $container_guid The container or containers to get entities from (default: all containers). + * @return array A list of entities. + */ +function get_entities_from_private_setting($name = "", $value = "", $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) { + global $CONFIG; + + if ($subtype === false || $subtype === null || $subtype === 0) { + return false; } - - /** - * Get entities based on their private data, in a similar way to metadata. - * - * @param string $name The name of the setting - * @param string $value The value of the setting - * @param string $type The type of entity (eg "user", "object" etc) - * @param string $subtype The arbitrary subtype of the entity - * @param int $owner_guid The GUID of the owning user - * @param string $order_by The field to order by; by default, time_created desc - * @param int $limit The number of entities to return; 10 by default - * @param int $offset The indexing offset, 0 by default - * @param boolean $count Set to true to get a count rather than the entities themselves (limits and offsets don't apply in this context). Defaults to false. - * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites. - * @param int|array $container_guid The container or containers to get entities from (default: all containers). - * @return array A list of entities. - */ - function get_entities_from_private_setting($name = "", $value = "", $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) - { - global $CONFIG; - - if ($subtype === false || $subtype === null || $subtype === 0) - return false; - - $name = sanitise_string($name); - $value = sanitise_string($value); - - if ($order_by == "") $order_by = "e.time_created desc"; - $order_by = sanitise_string($order_by); - $limit = (int)$limit; - $offset = (int)$offset; - $site_guid = (int) $site_guid; - if ($site_guid == 0) - $site_guid = $CONFIG->site_guid; - - $where = array(); - - if (is_array($type)) { - $tempwhere = ""; - if (sizeof($type)) + + $name = sanitise_string($name); + $value = sanitise_string($value); + + if ($order_by == "") { + $order_by = "e.time_created desc"; + } + $order_by = sanitise_string($order_by); + $limit = (int)$limit; + $offset = (int)$offset; + $site_guid = (int) $site_guid; + if ($site_guid == 0) { + $site_guid = $CONFIG->site_guid; + } + + $where = array(); + + if (is_array($type)) { + $tempwhere = ""; + if (sizeof($type)) { foreach($type as $typekey => $subtypearray) { foreach($subtypearray as $subtypeval) { $typekey = sanitise_string($typekey); @@ -2459,114 +2618,133 @@ } if (!empty($tempwhere)) $tempwhere .= " or "; $tempwhere .= "(e.type = '{$typekey}' and e.subtype = {$subtypeval})"; - } - } - if (!empty($tempwhere)) $where[] = "({$tempwhere})"; - - } else { - - $type = sanitise_string($type); - if ($subtype AND !$subtype = get_subtype_id($type, $subtype)) { - return false; - } - - if ($type != "") - $where[] = "e.type='$type'"; - if ($subtype!=="") - $where[] = "e.subtype=$subtype"; - - } - - if ($owner_guid != "") { - if (!is_array($owner_guid)) { - $owner_array = array($owner_guid); - $owner_guid = (int) $owner_guid; - // $where[] = "owner_guid = '$owner_guid'"; - } else if (sizeof($owner_guid) > 0) { - $owner_array = array_map('sanitise_int', $owner_guid); - // Cast every element to the owner_guid array to int - // $owner_guid = array_map("sanitise_int", $owner_guid); - // $owner_guid = implode(",",$owner_guid); - // $where[] = "owner_guid in ({$owner_guid})"; - } - if (is_null($container_guid)) { - $container_guid = $owner_array; + } } } - if ($site_guid > 0) - $where[] = "e.site_guid = {$site_guid}"; - - if (!is_null($container_guid)) { - if (is_array($container_guid)) { - foreach($container_guid as $key => $val) $container_guid[$key] = (int) $val; - $where[] = "e.container_guid in (" . implode(",",$container_guid) . ")"; - } else { - $container_guid = (int) $container_guid; - $where[] = "e.container_guid = {$container_guid}"; - } + if (!empty($tempwhere)) { + $where[] = "({$tempwhere})"; } - - if ($name!="") - $where[] = "s.name = '$name'"; - if ($value!="") - $where[] = "s.value='$value'"; - - if (!$count) { - $query = "SELECT distinct e.* from {$CONFIG->dbprefix}entities e JOIN {$CONFIG->dbprefix}private_settings s ON e.guid=s.entity_guid where "; - } else { - $query = "SELECT count(distinct e.guid) as total from {$CONFIG->dbprefix}entities e JOIN {$CONFIG->dbprefix}private_settings s ON e.guid=s.entity_guid where "; - } - foreach ($where as $w) - $query .= " $w and "; - $query .= get_access_sql_suffix('e'); // Add access controls - if (!$count) { - $query .= " order by $order_by"; - if ($limit) $query .= " limit $offset, $limit"; // Add order and limit - - $dt = get_data($query, "entity_row_to_elggstar"); - return $dt; + } else { + $type = sanitise_string($type); + if ($subtype AND !$subtype = get_subtype_id($type, $subtype)) { + return false; + } + + if ($type != "") { + $where[] = "e.type='$type'"; + } + if ($subtype!=="") { + $where[] = "e.subtype=$subtype"; + } + } + + if ($owner_guid != "") { + if (!is_array($owner_guid)) { + $owner_array = array($owner_guid); + $owner_guid = (int) $owner_guid; + // $where[] = "owner_guid = '$owner_guid'"; + } else if (sizeof($owner_guid) > 0) { + $owner_array = array_map('sanitise_int', $owner_guid); + // Cast every element to the owner_guid array to int + // $owner_guid = array_map("sanitise_int", $owner_guid); + // $owner_guid = implode(",",$owner_guid); + // $where[] = "owner_guid in ({$owner_guid})"; + } + if (is_null($container_guid)) { + $container_guid = $owner_array; + } + } + + if ($site_guid > 0) { + $where[] = "e.site_guid = {$site_guid}"; + } + + if (!is_null($container_guid)) { + if (is_array($container_guid)) { + foreach($container_guid as $key => $val) $container_guid[$key] = (int) $val; + $where[] = "e.container_guid in (" . implode(",",$container_guid) . ")"; } else { - $total = get_data_row($query); - return $total->total; + $container_guid = (int) $container_guid; + $where[] = "e.container_guid = {$container_guid}"; } } - - /** - * Get entities based on their private data by multiple keys, in a similar way to metadata. - * - * @param string $name The name of the setting - * @param string $value The value of the setting - * @param string|array $type The type of entity (eg "user", "object" etc) or array(type1 => array('subtype1', ...'subtypeN'), ...) - * @param string $subtype The arbitrary subtype of the entity - * @param int $owner_guid The GUID of the owning user - * @param string $order_by The field to order by; by default, time_created desc - * @param int $limit The number of entities to return; 10 by default - * @param int $offset The indexing offset, 0 by default - * @param boolean $count Set to true to get a count rather than the entities themselves (limits and offsets don't apply in this context). Defaults to false. - * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites. - * @param int|array $container_guid The container or containers to get entities from (default: all containers). - * @return array A list of entities. - */ - function get_entities_from_private_setting_multi(array $name, $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) - { - global $CONFIG; - - if ($subtype === false || $subtype === null || $subtype === 0) - return false; - - if ($order_by == "") $order_by = "e.time_created desc"; - $order_by = sanitise_string($order_by); - $limit = (int)$limit; - $offset = (int)$offset; - $site_guid = (int) $site_guid; - if ($site_guid == 0) - $site_guid = $CONFIG->site_guid; - - $where = array(); - - if (is_array($type)) { - $tempwhere = ""; - if (sizeof($type)) + + if ($name!="") { + $where[] = "s.name = '$name'"; + } + + if ($value!="") { + $where[] = "s.value='$value'"; + } + + if (!$count) { + $query = "SELECT distinct e.* + from {$CONFIG->dbprefix}entities e + JOIN {$CONFIG->dbprefix}private_settings s ON e.guid=s.entity_guid where "; + } else { + $query = "SELECT count(distinct e.guid) as total + from {$CONFIG->dbprefix}entities e JOIN {$CONFIG->dbprefix}private_settings s + ON e.guid=s.entity_guid where "; + } + foreach ($where as $w) { + $query .= " $w and "; + } + // Add access controls + $query .= get_access_sql_suffix('e'); + if (!$count) { + $query .= " order by $order_by"; + if ($limit) { + // Add order and limit + $query .= " limit $offset, $limit"; + } + + $dt = get_data($query, "entity_row_to_elggstar"); + return $dt; + } else { + $total = get_data_row($query); + return $total->total; + } +} + +/** + * Get entities based on their private data by multiple keys, in a similar way to metadata. + * + * @param string $name The name of the setting + * @param string $value The value of the setting + * @param string|array $type The type of entity (eg "user", "object" etc) or array(type1 => array('subtype1', ...'subtypeN'), ...) + * @param string $subtype The arbitrary subtype of the entity + * @param int $owner_guid The GUID of the owning user + * @param string $order_by The field to order by; by default, time_created desc + * @param int $limit The number of entities to return; 10 by default + * @param int $offset The indexing offset, 0 by default + * @param boolean $count Set to true to get a count rather than the entities themselves (limits and offsets don't apply in this context). Defaults to false. + * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites. + * @param int|array $container_guid The container or containers to get entities from (default: all containers). + * @return array A list of entities. + */ +function get_entities_from_private_setting_multi(array $name, $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) { + global $CONFIG; + + if ($subtype === false || $subtype === null || $subtype === 0) { + return false; + } + + if ($order_by == "") { + $order_by = "e.time_created desc"; + } + $order_by = sanitise_string($order_by); + $limit = (int)$limit; + $offset = (int)$offset; + $site_guid = (int) $site_guid; + if ($site_guid == 0) { + $site_guid = $CONFIG->site_guid; + } + + $where = array(); + + if (is_array($type)) { + $tempwhere = ""; + if (sizeof($type)) { foreach($type as $typekey => $subtypearray) { foreach($subtypearray as $subtypeval) { $typekey = sanitise_string($typekey); @@ -2581,247 +2759,270 @@ $tempwhere .= "(e.type = '{$typekey}' and e.subtype = {$subtypeval})"; } } - if (!empty($tempwhere)) $where[] = "({$tempwhere})"; - - } else { - $type = sanitise_string($type); - if ($subtype AND !$subtype = get_subtype_id($type, $subtype)) - return false; - - if ($type != "") - $where[] = "e.type='$type'"; - if ($subtype!=="") - $where[] = "e.subtype=$subtype"; - - } - - if ($owner_guid != "") { - if (!is_array($owner_guid)) { - $owner_array = array($owner_guid); - $owner_guid = (int) $owner_guid; - // $where[] = "owner_guid = '$owner_guid'"; - } else if (sizeof($owner_guid) > 0) { - $owner_array = array_map('sanitise_int', $owner_guid); - // Cast every element to the owner_guid array to int - // $owner_guid = array_map("sanitise_int", $owner_guid); - // $owner_guid = implode(",",$owner_guid); - // $where[] = "owner_guid in ({$owner_guid})"; - } - if (is_null($container_guid)) { - $container_guid = $owner_array; - } } - if ($site_guid > 0) - $where[] = "e.site_guid = {$site_guid}"; - - if (!is_null($container_guid)) { - if (is_array($container_guid)) { - foreach($container_guid as $key => $val) $container_guid[$key] = (int) $val; - $where[] = "e.container_guid in (" . implode(",",$container_guid) . ")"; - } else { - $container_guid = (int) $container_guid; - $where[] = "e.container_guid = {$container_guid}"; - } + if (!empty($tempwhere)) { + $where[] = "({$tempwhere})"; } - - if ($name) - { - $s_join = ""; - $i = 1; - foreach ($name as $k => $n) - { - $k = sanitise_string($k); - $s_join .= " JOIN {$CONFIG->dbprefix}private_settings s$i ON e.guid=s$i.entity_guid"; - $where[] = "s$i.name = '$k'"; - $where[] = "s$i.value = '$n'"; - $i++; - } + + } else { + $type = sanitise_string($type); + if ($subtype AND !$subtype = get_subtype_id($type, $subtype)) { + return false; } - - if (!$count) { - $query = "SELECT distinct e.* from {$CONFIG->dbprefix}entities e $s_join where "; - } else { - $query = "SELECT count(distinct e.guid) as total from {$CONFIG->dbprefix}entities e $s_join where "; - } - foreach ($where as $w) - $query .= " $w and "; - $query .= get_access_sql_suffix('e'); // Add access controls - if (!$count) { - $query .= " order by $order_by"; - if ($limit) $query .= " limit $offset, $limit"; // Add order and limit - - $dt = get_data($query, "entity_row_to_elggstar"); - return $dt; + + if ($type != "") { + $where[] = "e.type='$type'"; + } + + if ($subtype!=="") { + $where[] = "e.subtype=$subtype"; + } + } + + if ($owner_guid != "") { + if (!is_array($owner_guid)) { + $owner_array = array($owner_guid); + $owner_guid = (int) $owner_guid; + // $where[] = "owner_guid = '$owner_guid'"; + } else if (sizeof($owner_guid) > 0) { + $owner_array = array_map('sanitise_int', $owner_guid); + // Cast every element to the owner_guid array to int + // $owner_guid = array_map("sanitise_int", $owner_guid); + // $owner_guid = implode(",",$owner_guid); + // $where[] = "owner_guid in ({$owner_guid})"; + } + if (is_null($container_guid)) { + $container_guid = $owner_array; + } + } + if ($site_guid > 0) { + $where[] = "e.site_guid = {$site_guid}"; + } + + if (!is_null($container_guid)) { + if (is_array($container_guid)) { + foreach($container_guid as $key => $val) $container_guid[$key] = (int) $val; + $where[] = "e.container_guid in (" . implode(",",$container_guid) . ")"; } else { - $total = get_data_row($query); - return $total->total; + $container_guid = (int) $container_guid; + $where[] = "e.container_guid = {$container_guid}"; } } - - /** - * Gets a private setting for an entity. - * - * @param int $entity_guid The entity GUID - * @param string $name The name of the setting - * @return mixed The setting value, or false on failure - */ - function get_private_setting($entity_guid, $name) { - - global $CONFIG; - $entity_guid = (int) $entity_guid; - $name = sanitise_string($name); - - if ($setting = get_data_row("SELECT value from {$CONFIG->dbprefix}private_settings where name = '{$name}' and entity_guid = {$entity_guid}")) { - return $setting->value; + + if ($name) { + $s_join = ""; + $i = 1; + foreach ($name as $k => $n) { + $k = sanitise_string($k); + $s_join .= " JOIN {$CONFIG->dbprefix}private_settings s$i ON e.guid=s$i.entity_guid"; + $where[] = "s$i.name = '$k'"; + $where[] = "s$i.value = '$n'"; + $i++; } - return false; - } - - /** - * Return an array of all private settings for a given - * - * @param int $entity_guid The entity GUID - */ - function get_all_private_settings($entity_guid) { - global $CONFIG; - - $entity_guid = (int) $entity_guid; - - $result = get_data("SELECT * from {$CONFIG->dbprefix}private_settings where entity_guid = {$entity_guid}"); - if ($result) - { - $return = array(); - foreach ($result as $r) - $return[$r->name] = $r->value; - - return $return; - } - - return false; + + if (!$count) { + $query = "SELECT distinct e.* from {$CONFIG->dbprefix}entities e $s_join where "; + } else { + $query = "SELECT count(distinct e.guid) as total + from {$CONFIG->dbprefix}entities e $s_join where "; } - - /** - * Sets a private setting for an entity. - * - * @param int $entity_guid The entity GUID - * @param string $name The name of the setting - * @param string $value The value of the setting - * @return mixed The setting ID, or false on failure - */ - function set_private_setting($entity_guid, $name, $value) { - - global $CONFIG; - $entity_guid = (int) $entity_guid; - $name = sanitise_string($name); - $value = sanitise_string($value); - - $result = insert_data("INSERT into {$CONFIG->dbprefix}private_settings (entity_guid, name, value) VALUES ($entity_guid, '{$name}', '{$value}') ON DUPLICATE KEY UPDATE value='$value'"); - if ($result === 0) return true; - return $result; - - } - - /** - * Deletes a private setting for an entity. - * - * @param int $entity_guid The Entity GUID - * @param string $name The name of the setting - * @return true|false depending on success - * - */ - function remove_private_setting($entity_guid, $name) { - - global $CONFIG; - $entity_guid = (int) $entity_guid; - $name = sanitise_string($name); - return delete_data("DELETE from {$CONFIG->dbprefix}private_settings where name = '{$name}' and entity_guid = {$entity_guid}"); - + + foreach ($where as $w) { + $query .= " $w and "; } - - /** - * Deletes all private settings for an entity. - * - * @param int $entity_guid The Entity GUID - * @return true|false depending on success - * - */ - function remove_all_private_settings($entity_guid) { - - global $CONFIG; - $entity_guid = (int) $entity_guid; - return delete_data("DELETE from {$CONFIG->dbprefix}private_settings where entity_guid = {$entity_guid}"); + + // Add access controls + $query .= get_access_sql_suffix('e'); + + if (!$count) { + $query .= " order by $order_by"; + // Add order and limit + if ($limit) { + $query .= " limit $offset, $limit"; + } + + $dt = get_data($query, "entity_row_to_elggstar"); + return $dt; + } else { + $total = get_data_row($query); + return $total->total; } - - function recursive_delete_permissions_check($hook, $entity_type, $returnvalue, $params) - { - static $__RECURSIVE_DELETE_TOKEN; - - $entity = $params['entity']; - - if ((isloggedin()) && ($__RECURSIVE_DELETE_TOKEN) && (strcmp($__RECURSIVE_DELETE_TOKEN, md5(get_loggedin_userid())))) - return true; - +} + +/** + * Gets a private setting for an entity. + * + * @param int $entity_guid The entity GUID + * @param string $name The name of the setting + * @return mixed The setting value, or false on failure + */ +function get_private_setting($entity_guid, $name) { + global $CONFIG; + $entity_guid = (int) $entity_guid; + $name = sanitise_string($name); + + if ($setting = get_data_row("SELECT value from {$CONFIG->dbprefix}private_settings where name = '{$name}' and entity_guid = {$entity_guid}")) { + return $setting->value; } - - /** - * Garbage collect stub and fragments from any broken delete/create calls - * - * @param unknown_type $hook - * @param unknown_type $user - * @param unknown_type $returnvalue - * @param unknown_type $tag - */ - function entities_gc($hook, $user, $returnvalue, $tag) { - global $CONFIG; - - $tables = array ('sites_entity', 'objects_entity', 'groups_entity', 'users_entity'); - - foreach ($tables as $table) { - delete_data("DELETE from {$CONFIG->dbprefix}{$table} where guid NOT IN (SELECT guid from {$CONFIG->dbprefix}entities)"); + return false; +} + +/** + * Return an array of all private settings for a given + * + * @param int $entity_guid The entity GUID + */ +function get_all_private_settings($entity_guid) { + global $CONFIG; + + $entity_guid = (int) $entity_guid; + + $result = get_data("SELECT * from {$CONFIG->dbprefix}private_settings where entity_guid = {$entity_guid}"); + if ($result) { + $return = array(); + foreach ($result as $r) { + $return[$r->name] = $r->value; } + + return $return; } - - /** - * Runs unit tests for the entities object. - */ - function entities_test($hook, $type, $value, $params) { - global $CONFIG; - $value[] = $CONFIG->path . 'engine/tests/objects/entities.php'; - return $value; + + return false; +} + +/** + * Sets a private setting for an entity. + * + * @param int $entity_guid The entity GUID + * @param string $name The name of the setting + * @param string $value The value of the setting + * @return mixed The setting ID, or false on failure + */ +function set_private_setting($entity_guid, $name, $value) { + global $CONFIG; + + $entity_guid = (int) $entity_guid; + $name = sanitise_string($name); + $value = sanitise_string($value); + + $result = insert_data("INSERT into {$CONFIG->dbprefix}private_settings + (entity_guid, name, value) VALUES + ($entity_guid, '{$name}', '{$value}') + ON DUPLICATE KEY UPDATE value='$value'"); + if ($result === 0) { + return true; } - - /** - * Entities init function; establishes the page handler - * - */ - function entities_init() - { - register_page_handler('view','entities_page_handler'); - - register_plugin_hook('unit_test', 'system', 'entities_test'); - - // Allow a permission override for recursive entity deletion - // TODO: Can this be done better? - register_plugin_hook('permissions_check','all','recursive_delete_permissions_check'); - register_plugin_hook('permissions_check:metadata','all','recursive_delete_permissions_check'); - - register_plugin_hook('gc','system','entities_gc'); - } - - /** Register the import hook */ - register_plugin_hook("import", "all", "import_entity_plugin_hook", 0); - - /** Register the hook, ensuring entities are serialised first */ - register_plugin_hook("export", "all", "export_entity_plugin_hook", 0); - - /** Hook to get certain named bits of volatile data about an entity */ - register_plugin_hook('volatile', 'metadata', 'volatile_data_export_plugin_hook'); - - /** Hook for rendering a default icon for entities */ - register_plugin_hook('entity:icon:url', 'all', 'default_entity_icon_hook', 1000); - - /** Register init system event **/ - register_elgg_event_handler('init','system','entities_init'); - -?> + return $result; +} + +/** + * Deletes a private setting for an entity. + * + * @param int $entity_guid The Entity GUID + * @param string $name The name of the setting + * @return true|false depending on success + * + */ +function remove_private_setting($entity_guid, $name) { + global $CONFIG; + + $entity_guid = (int) $entity_guid; + $name = sanitise_string($name); + + return delete_data("DELETE from {$CONFIG->dbprefix}private_settings + where name = '{$name}' + and entity_guid = {$entity_guid}"); +} + +/** + * Deletes all private settings for an entity. + * + * @param int $entity_guid The Entity GUID + * @return true|false depending on success + * + */ +function remove_all_private_settings($entity_guid) { + global $CONFIG; + + $entity_guid = (int) $entity_guid; + return delete_data("DELETE from {$CONFIG->dbprefix}private_settings + where entity_guid = {$entity_guid}"); +} + +/* + * Check the recurisve delete permissions token. + * + * @return bool + */ +function recursive_delete_permissions_check($hook, $entity_type, $returnvalue, $params) { + static $__RECURSIVE_DELETE_TOKEN; + + $entity = $params['entity']; + + if ((isloggedin()) && ($__RECURSIVE_DELETE_TOKEN) && (strcmp($__RECURSIVE_DELETE_TOKEN, md5(get_loggedin_userid())))) { + return true; + } + + return false; +} + +/** + * Garbage collect stub and fragments from any broken delete/create calls + * + * @param unknown_type $hook + * @param unknown_type $user + * @param unknown_type $returnvalue + * @param unknown_type $tag + */ +function entities_gc($hook, $user, $returnvalue, $tag) { + global $CONFIG; + + $tables = array ('sites_entity', 'objects_entity', 'groups_entity', 'users_entity'); + + foreach ($tables as $table) { + delete_data("DELETE from {$CONFIG->dbprefix}{$table} + where guid NOT IN (SELECT guid from {$CONFIG->dbprefix}entities)"); + } +} + +/** + * Runs unit tests for the entities object. + */ +function entities_test($hook, $type, $value, $params) { + global $CONFIG; + $value[] = $CONFIG->path . 'engine/tests/objects/entities.php'; + return $value; +} + +/** + * Entities init function; establishes the page handler + * + */ +function entities_init() { + register_page_handler('view','entities_page_handler'); + + register_plugin_hook('unit_test', 'system', 'entities_test'); + + // Allow a permission override for recursive entity deletion + // TODO: Can this be done better? + register_plugin_hook('permissions_check','all','recursive_delete_permissions_check'); + register_plugin_hook('permissions_check:metadata','all','recursive_delete_permissions_check'); + + register_plugin_hook('gc','system','entities_gc'); +} + +/** Register the import hook */ +register_plugin_hook("import", "all", "import_entity_plugin_hook", 0); + +/** Register the hook, ensuring entities are serialised first */ +register_plugin_hook("export", "all", "export_entity_plugin_hook", 0); + +/** Hook to get certain named bits of volatile data about an entity */ +register_plugin_hook('volatile', 'metadata', 'volatile_data_export_plugin_hook'); + +/** Hook for rendering a default icon for entities */ +register_plugin_hook('entity:icon:url', 'all', 'default_entity_icon_hook', 1000); + +/** Register init system event **/ +register_elgg_event_handler('init','system','entities_init'); \ No newline at end of file -- cgit v1.2.3