aboutsummaryrefslogtreecommitdiff
path: root/engine/lib
diff options
context:
space:
mode:
Diffstat (limited to 'engine/lib')
-rw-r--r--engine/lib/access.php975
-rw-r--r--engine/lib/actions.php520
-rw-r--r--engine/lib/admin.php745
-rw-r--r--engine/lib/annotations.php1246
-rw-r--r--engine/lib/cache.php694
-rw-r--r--engine/lib/calendar.php332
-rw-r--r--engine/lib/configuration.php638
-rw-r--r--engine/lib/cron.php106
-rw-r--r--engine/lib/database.php686
-rw-r--r--engine/lib/deprecated-1.7.php1164
-rw-r--r--engine/lib/deprecated-1.8.php4820
-rw-r--r--engine/lib/deprecated-1.9.php582
-rw-r--r--engine/lib/elgglib.php3234
-rw-r--r--engine/lib/entities.php3732
-rw-r--r--engine/lib/exceptions.php161
-rw-r--r--engine/lib/export.php165
-rw-r--r--engine/lib/extender.php360
-rw-r--r--engine/lib/filestore.php1392
-rw-r--r--engine/lib/group.php898
-rw-r--r--engine/lib/input.php391
-rw-r--r--engine/lib/install.php140
-rw-r--r--engine/lib/languages.php216
-rw-r--r--engine/lib/location.php309
-rw-r--r--engine/lib/mb_wrapper.php242
-rw-r--r--engine/lib/memcache.php179
-rw-r--r--engine/lib/metadata.php1157
-rw-r--r--engine/lib/metastrings.php746
-rw-r--r--engine/lib/navigation.php527
-rw-r--r--engine/lib/notification.php248
-rw-r--r--engine/lib/objects.php351
-rw-r--r--engine/lib/opendd.php316
-rw-r--r--engine/lib/output.php447
-rw-r--r--engine/lib/pagehandler.php139
-rw-r--r--engine/lib/pageowner.php340
-rw-r--r--engine/lib/pam.php105
-rw-r--r--engine/lib/plugins.php1538
-rw-r--r--engine/lib/private_settings.php414
-rw-r--r--engine/lib/query.php889
-rw-r--r--engine/lib/relationships.php895
-rw-r--r--engine/lib/river.php1104
-rw-r--r--engine/lib/sessions.php406
-rw-r--r--engine/lib/sites.php614
-rw-r--r--engine/lib/social.php119
-rw-r--r--engine/lib/statistics.php61
-rw-r--r--engine/lib/system_log.php197
-rw-r--r--engine/lib/tags.php232
-rw-r--r--engine/lib/upgrade.php365
-rw-r--r--engine/lib/upgrades/2008100701.php13
-rw-r--r--engine/lib/upgrades/2008101303.php16
-rw-r--r--engine/lib/upgrades/2009022701.php13
-rw-r--r--engine/lib/upgrades/2009041701.php14
-rw-r--r--engine/lib/upgrades/2009070101.php16
-rw-r--r--engine/lib/upgrades/2009102801.php177
-rw-r--r--engine/lib/upgrades/2010033101.php19
-rw-r--r--engine/lib/upgrades/2010040201.php3
-rw-r--r--engine/lib/upgrades/2010050701.php17
-rw-r--r--engine/lib/upgrades/2010052601.php12
-rw-r--r--engine/lib/upgrades/2010060101.php2
-rw-r--r--engine/lib/upgrades/2010060401.php14
-rw-r--r--engine/lib/upgrades/2010061501.php51
-rw-r--r--engine/lib/upgrades/2010062301.php33
-rw-r--r--engine/lib/upgrades/2010062302.php33
-rw-r--r--engine/lib/upgrades/2010070301.php9
-rw-r--r--engine/lib/upgrades/2010071001.php58
-rw-r--r--engine/lib/upgrades/2010071002.php50
-rw-r--r--engine/lib/upgrades/2010111501.php33
-rw-r--r--engine/lib/upgrades/2010121601.php9
-rw-r--r--engine/lib/upgrades/2010121602.php10
-rw-r--r--engine/lib/upgrades/2010121701.php10
-rw-r--r--engine/lib/upgrades/2010123101.php9
-rw-r--r--engine/lib/upgrades/2011010101.php98
-rw-r--r--engine/lib/upgrades/2011021800-1.8_svn-goodbye_walled_garden-083121a656d06894.php34
-rw-r--r--engine/lib/upgrades/2011022000-1.8_svn-custom_profile_fields-390ac967b0bb5665.php59
-rw-r--r--engine/lib/upgrades/2011030700-1.8_svn-blog_status_metadata-4645225d7b440876.php24
-rw-r--r--engine/lib/upgrades/2011031300-1.8_svn-twitter_api-12b832a5a7a3e1bd.php54
-rw-r--r--engine/lib/upgrades/2011031600-1.8_svn-datalist_grows_up-0b8aec5a55cc1e1c.php18
-rw-r--r--engine/lib/upgrades/2011032000-1.8_svn-widgets_arent_plugins-61836261fa280a5c.php10
-rw-r--r--engine/lib/upgrades/2011032200-1.8_svn-admins_like_widgets-7f19d2783c1680d3.php13
-rw-r--r--engine/lib/upgrades/2011052801.php46
-rw-r--r--engine/lib/upgrades/2011061200-1.8b1-sites_need_a_site_guid-6d9dcbf46c0826cc.php31
-rw-r--r--engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php12
-rw-r--r--engine/lib/upgrades/2011123100-1.8.2-fix_friend_river-b17e7ff8345c2269.php12
-rw-r--r--engine/lib/upgrades/2011123101-1.8.2-fix_blog_status-b14c2a0e7b9e7d55.php25
-rw-r--r--engine/lib/upgrades/2012012000-1.8.3-ip_in_syslog-87fe0f068cf62428.php12
-rw-r--r--engine/lib/upgrades/2012012100-1.8.3-system_cache-93100e7d55a24a11.php13
-rw-r--r--engine/lib/upgrades/2012041800-1.8.3-dont_filter_passwords-c0ca4a18b38ae2bc.php11
-rw-r--r--engine/lib/upgrades/2012041801-1.8.3-multiple_user_tokens-852225f7fd89f6c5.php13
-rw-r--r--engine/lib/upgrades/2013030600-1.8.13-update_user_location-8999eb8bf1bdd9a3.php24
-rw-r--r--engine/lib/upgrades/2013051700-1.8.15-add_missing_group_index-52a63a3a3ffaced2.php28
-rw-r--r--engine/lib/upgrades/2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php12
-rw-r--r--engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php16
-rw-r--r--engine/lib/upgrades/create_upgrade.php152
-rw-r--r--engine/lib/user_settings.php360
-rw-r--r--engine/lib/users.php1918
-rw-r--r--engine/lib/usersettings.php76
-rw-r--r--engine/lib/version.php132
-rw-r--r--engine/lib/views.php1818
-rw-r--r--engine/lib/web_services.php (renamed from engine/lib/api.php)834
-rw-r--r--engine/lib/widgets.php690
-rw-r--r--engine/lib/xml-rpc.php732
-rw-r--r--engine/lib/xml.php258
101 files changed, 24107 insertions, 19186 deletions
diff --git a/engine/lib/access.php b/engine/lib/access.php
index b8d8820e1..de0693ea8 100644
--- a/engine/lib/access.php
+++ b/engine/lib/access.php
@@ -1,68 +1,62 @@
<?php
/**
- * Elgg access permissions
- * For users, objects, collections and all metadata
+ * Functions for Elgg's access system for entities, metadata, and annotations.
*
- * @package Elgg
- * @subpackage Core
-
- * @author Curverider Ltd
-
- * @link http://elgg.org/
+ * Access is generally saved in the database as access_id. This corresponds to
+ * one of the ACCESS_* constants defined in {@link elgglib.php} or the ID of an
+ * access collection.
+ *
+ * @package Elgg.Core
+ * @subpackage Access
+ * @link http://docs.elgg.org/Access
*/
/**
- * Temporary class used to determing if access is being ignored
+ * Return an ElggCache static variable cache for the access caches
+ *
+ * @staticvar ElggStaticVariableCache $access_cache
+ * @return \ElggStaticVariableCache
+ * @access private
*/
-class ElggAccess {
+function _elgg_get_access_cache() {
/**
- * Bypass Elgg's access control if true.
- * @var bool
+ * A default filestore cache using the dataroot.
*/
- private $ignore_access;
+ static $access_cache;
- /**
- * Get current ignore access setting.
- * @return bool
- */
- public function get_ignore_access() {
- return $this->ignore_access;
+ if (!$access_cache) {
+ $access_cache = new ElggStaticVariableCache('access');
}
- /**
- * Set ignore access.
- *
- * @param $ignore bool true || false to ignore
- * @return bool Previous setting
- */
- public function set_ignore_access($ignore = true) {
- $prev = $this->ignore_access;
- $this->ignore_access = $ignore;
-
- return $prev;
- }
+ return $access_cache;
}
-
/**
* Return a string of access_ids for $user_id appropriate for inserting into an SQL IN clause.
*
* @uses get_access_array
- * @param int $user_id User ID; defaults to currently logged in user
- * @param int $site_id Site ID; defaults to current site
- * @param boolean $flush If set to true, will refresh the access list from the database
- * @return string A list of access collections suitable for injection in an SQL call
+ *
+ * @link http://docs.elgg.org/Access
+ * @see get_access_array()
+ *
+ * @param int $user_id User ID; defaults to currently logged in user
+ * @param int $site_id Site ID; defaults to current site
+ * @param bool $flush If set to true, will refresh the access list from the
+ * database rather than using this function's cache.
+ *
+ * @return string A list of access collections suitable for using in an SQL call
+ * @access private
*/
function get_access_list($user_id = 0, $site_id = 0, $flush = false) {
- global $CONFIG, $init_finished, $SESSION;
- static $access_list;
-
- if (!isset($access_list) || !$init_finished) {
- $access_list = array();
+ global $CONFIG, $init_finished;
+ $cache = _elgg_get_access_cache();
+
+ if ($flush) {
+ $cache->clear();
}
if ($user_id == 0) {
- $user_id = $SESSION['id'];
+ $user_id = elgg_get_logged_in_user_guid();
}
if (($site_id == 0) && (isset($CONFIG->site_id))) {
@@ -71,36 +65,55 @@ function get_access_list($user_id = 0, $site_id = 0, $flush = false) {
$user_id = (int) $user_id;
$site_id = (int) $site_id;
- if (isset($access_list[$user_id])) {
- return $access_list[$user_id];
- }
+ $hash = $user_id . $site_id . 'get_access_list';
- $access_list[$user_id] = "(" . implode(",", get_access_array($user_id, $site_id, $flush)) . ")";
+ if ($cache[$hash]) {
+ return $cache[$hash];
+ }
+
+ $access_array = get_access_array($user_id, $site_id, $flush);
+ $access = "(" . implode(",", $access_array) . ")";
- return $access_list[$user_id];
+ if ($init_finished) {
+ $cache[$hash] = $access;
+ }
+
+ return $access;
}
/**
- * Gets an array of access restrictions the given user is allowed to see on this site
+ * Returns an array of access IDs a user is permitted to see.
+ *
+ * Can be overridden with the 'access:collections:read', 'user' plugin hook.
+ *
+ * This returns a list of all the collection ids a user owns or belongs
+ * to plus public and logged in access levels. If the user is an admin, it includes
+ * the private access level.
*
- * @param int $user_id User ID; defaults to currently logged in user
- * @param int $site_id Site ID; defaults to current site
- * @param boolean $flush If set to true, will refresh the access list from the database
- * @return array An array of access collections suitable for injection in an SQL call
+ * @internal this is only used in core for creating the SQL where clause when
+ * retrieving content from the database. The friends access level is handled by
+ * get_access_sql_suffix().
+ *
+ * @see get_write_access_array() for the access levels that a user can write to.
+ *
+ * @param int $user_id User ID; defaults to currently logged in user
+ * @param int $site_id Site ID; defaults to current site
+ * @param bool $flush If set to true, will refresh the access ids from the
+ * database rather than using this function's cache.
+ *
+ * @return array An array of access collections ids
*/
function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
global $CONFIG, $init_finished;
- // @todo everything from the db is cached.
- // this cache might be redundant.
- static $access_array;
+ $cache = _elgg_get_access_cache();
- if (!isset($access_array) || (!isset($init_finished)) || (!$init_finished)) {
- $access_array = array();
+ if ($flush) {
+ $cache->clear();
}
if ($user_id == 0) {
- $user_id = get_loggedin_userid();
+ $user_id = elgg_get_logged_in_user_guid();
}
if (($site_id == 0) && (isset($CONFIG->site_guid))) {
@@ -110,34 +123,41 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
$user_id = (int) $user_id;
$site_id = (int) $site_id;
- if (empty($access_array[$user_id]) || $flush == true) {
- $tmp_access_array = array(ACCESS_PUBLIC);
- if (isloggedin()) {
- $tmp_access_array[] = ACCESS_LOGGED_IN;
+ $hash = $user_id . $site_id . 'get_access_array';
+
+ if ($cache[$hash]) {
+ $access_array = $cache[$hash];
+ } else {
+ $access_array = array(ACCESS_PUBLIC);
- // The following can only return sensible data if the user is logged in.
+ // The following can only return sensible data if the user is logged in.
+ if (elgg_is_logged_in()) {
+ $access_array[] = ACCESS_LOGGED_IN;
// Get ACL memberships
- $query = "SELECT am.access_collection_id FROM {$CONFIG->dbprefix}access_collection_membership am ";
- $query .= " LEFT JOIN {$CONFIG->dbprefix}access_collections ag ON ag.id = am.access_collection_id ";
- $query .= " WHERE am.user_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
-
- if ($collections = get_data($query)) {
- foreach($collections as $collection) {
+ $query = "SELECT am.access_collection_id"
+ . " FROM {$CONFIG->dbprefix}access_collection_membership am"
+ . " LEFT JOIN {$CONFIG->dbprefix}access_collections ag ON ag.id = am.access_collection_id"
+ . " WHERE am.user_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)";
+
+ $collections = get_data($query);
+ if ($collections) {
+ foreach ($collections as $collection) {
if (!empty($collection->access_collection_id)) {
- $tmp_access_array[] = $collection->access_collection_id;
+ $access_array[] = (int)$collection->access_collection_id;
}
}
}
// Get ACLs owned.
- $query = "SELECT ag.id FROM {$CONFIG->dbprefix}access_collections ag ";
- $query .= " WHERE ag.owner_guid = {$user_id} AND (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
+ $query = "SELECT ag.id FROM {$CONFIG->dbprefix}access_collections ag ";
+ $query .= "WHERE ag.owner_guid = $user_id AND (ag.site_guid = $site_id OR ag.site_guid = 0)";
- if ($collections = get_data($query)) {
- foreach($collections as $collection) {
+ $collections = get_data($query);
+ if ($collections) {
+ foreach ($collections as $collection) {
if (!empty($collection->id)) {
- $tmp_access_array[] = $collection->id;
+ $access_array[] = (int)$collection->id;
}
}
}
@@ -145,26 +165,32 @@ function get_access_array($user_id = 0, $site_id = 0, $flush = false) {
$ignore_access = elgg_check_access_overrides($user_id);
if ($ignore_access == true) {
- $tmp_access_array[] = ACCESS_PRIVATE;
+ $access_array[] = ACCESS_PRIVATE;
}
-
- $access_array[$user_id] = $tmp_access_array;
- } else {
- // No user id logged in so we can only access public info
- $tmp_return = $tmp_access_array;
}
- } else {
- $tmp_access_array = $access_array[$user_id];
+ if ($init_finished) {
+ $cache[$hash] = $access_array;
+ }
}
- return trigger_plugin_hook('access:collections:read','user',array('user_id' => $user_id, 'site_id' => $site_id),$tmp_access_array);
+ $options = array(
+ 'user_id' => $user_id,
+ 'site_id' => $site_id
+ );
+
+ return elgg_trigger_plugin_hook('access:collections:read', 'user', $options, $access_array);
}
/**
- * Gets the default access permission for new content
+ * Gets the default access permission.
+ *
+ * This returns the default access level for the site or optionally for the user.
+ *
+ * @param ElggUser $user Get the user's default access. Defaults to logged in user.
*
* @return int default access id (see ACCESS defines in elgglib.php)
+ * @link http://docs.elgg.org/Access
*/
function get_default_access(ElggUser $user = null) {
global $CONFIG;
@@ -173,7 +199,7 @@ function get_default_access(ElggUser $user = null) {
return $CONFIG->default_access;
}
- if (!($user) && (!$user = get_loggedin_user())) {
+ if (!($user) && (!$user = elgg_get_logged_in_user_entity())) {
return $CONFIG->default_access;
}
@@ -185,17 +211,20 @@ function get_default_access(ElggUser $user = null) {
}
/**
- * Override the default behaviour and allow results to show hidden entities as well.
- * THIS IS A HACK.
+ * Allow disabled entities and metadata to be returned by getter functions
*
- * TODO: Replace this with query object!
+ * @todo Replace this with query object!
+ * @global bool $ENTITY_SHOW_HIDDEN_OVERRIDE
+ * @access private
*/
$ENTITY_SHOW_HIDDEN_OVERRIDE = false;
/**
- * This will be replaced. Do not use in plugins!
+ * Show or hide disabled entities.
*
- * @param bool $show
+ * @param bool $show_hidden Show disabled entities.
+ * @return void
+ * @access private
*/
function access_show_hidden_entities($show_hidden) {
global $ENTITY_SHOW_HIDDEN_OVERRIDE;
@@ -203,7 +232,10 @@ function access_show_hidden_entities($show_hidden) {
}
/**
- * This will be replaced. Do not use in plugins!
+ * Return current status of showing disabled entities.
+ *
+ * @return bool
+ * @access private
*/
function access_get_show_hidden_status() {
global $ENTITY_SHOW_HIDDEN_OVERRIDE;
@@ -211,45 +243,17 @@ function access_get_show_hidden_status() {
}
/**
- * Add annotation restriction
- *
- * Returns an SQL fragment that is true (or optionally false) if the given user has
- * added an annotation with the given name to the given entity.
+ * Returns the SQL where clause for a table with a access_id and enabled columns.
*
- * TODO: This is fairly generic so perhaps it could be moved to annotations.php
- *
- * @param string $annotation_name name of the annotation
- * @param string $entity_guid SQL string that evaluates to the GUID of the entity the annotation should be attached to
- * @param string $owner_guid SQL string that evaluates to the GUID of the owner of the annotation *
- * @param boolean $exists If set to true, will return true if the annotation exists, otherwise returns false
- * @return string An SQL fragment suitable for inserting into a WHERE clause
- */
-function get_annotation_sql($annotation_name, $entity_guid, $owner_guid, $exists) {
- global $CONFIG;
-
- if ($exists) {
- $not = '';
- } else {
- $not = 'NOT';
- }
-
- $sql = <<<END
-$not EXISTS (SELECT * FROM {$CONFIG->dbprefix}annotations a
-INNER JOIN {$CONFIG->dbprefix}metastrings ms ON (a.name_id = ms.id)
-WHERE ms.string = '$annotation_name'
-AND a.entity_guid = $entity_guid
-AND a.owner_guid = $owner_guid)
-END;
- return $sql;
-}
-
-/**
- * Add access restriction sql code to a given query.
- * Note that if this code is executed in privileged mode it will return blank.
- * @TODO: DELETE once Query classes are fully integrated
+ * This handles returning where clauses for ACCESS_FRIENDS and the currently
+ * unused block and filter lists in addition to using get_access_list() for
+ * access collections and the standard access levels.
*
* @param string $table_prefix Optional table. prefix for the access code.
- * @param int $owner
+ * @param int $owner The guid to check access for. Defaults to logged in user.
+ *
+ * @return string The SQL for a where clause
+ * @access private
*/
function get_access_sql_suffix($table_prefix = '', $owner = null) {
global $ENTITY_SHOW_HIDDEN_OVERRIDE, $CONFIG;
@@ -259,11 +263,11 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) {
$enemies_bit = "";
if ($table_prefix) {
- $table_prefix = sanitise_string($table_prefix) . ".";
+ $table_prefix = sanitise_string($table_prefix) . ".";
}
if (!isset($owner)) {
- $owner = get_loggedin_userid();
+ $owner = elgg_get_logged_in_user_guid();
}
if (!$owner) {
@@ -276,22 +280,24 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) {
if ($ignore_access) {
$sql = " (1 = 1) ";
} else if ($owner != -1) {
+ // we have an entity's guid and auto check for friend relationships
$friends_bit = "{$table_prefix}access_id = " . ACCESS_FRIENDS . "
AND {$table_prefix}owner_guid IN (
SELECT guid_one FROM {$CONFIG->dbprefix}entity_relationships
WHERE relationship='friend' AND guid_two=$owner
)";
- $friends_bit = '('.$friends_bit.') OR ';
+ $friends_bit = '(' . $friends_bit . ') OR ';
+ // @todo untested and unsupported at present
if ((isset($CONFIG->user_block_and_filter_enabled)) && ($CONFIG->user_block_and_filter_enabled)) {
// check to see if the user is in the entity owner's block list
// or if the entity owner is in the user's filter list
// if so, disallow access
- $enemies_bit = get_annotation_sql('elgg_block_list', "{$table_prefix}owner_guid", $owner, false);
+ $enemies_bit = get_access_restriction_sql('elgg_block_list', "{$table_prefix}owner_guid", $owner, false);
$enemies_bit = '('
. $enemies_bit
- . ' AND ' . get_annotation_sql('elgg_filter_list', $owner, "{$table_prefix}owner_guid", false)
+ . ' AND ' . get_access_restriction_sql('elgg_filter_list', $owner, "{$table_prefix}owner_guid", false)
. ')';
}
}
@@ -310,18 +316,68 @@ function get_access_sql_suffix($table_prefix = '', $owner = null) {
$sql = "$enemies_bit AND ($sql)";
}
- if (!$ENTITY_SHOW_HIDDEN_OVERRIDE)
+ if (!$ENTITY_SHOW_HIDDEN_OVERRIDE) {
$sql .= " and {$table_prefix}enabled='yes'";
- return '('.$sql.')';
+ }
+
+ return '(' . $sql . ')';
+}
+
+/**
+ * Get the where clause for an access restriction based on annotations
+ *
+ * Returns an SQL fragment that is true (or optionally false) if the given user has
+ * added an annotation with the given name to the given entity.
+ *
+ * @warning this is a private function for an untested capability and will likely
+ * be removed from a future version of Elgg.
+ *
+ * @param string $annotation_name Name of the annotation
+ * @param string $entity_guid SQL GUID of entity the annotation is attached to.
+ * @param string $owner_guid SQL string that evaluates to the GUID of the annotation owner
+ * @param boolean $exists If true, returns BOOL if the annotation exists
+ *
+ * @return string An SQL fragment suitable for inserting into a WHERE clause
+ * @access private
+ */
+function get_access_restriction_sql($annotation_name, $entity_guid, $owner_guid, $exists) {
+ global $CONFIG;
+
+ if ($exists) {
+ $not = '';
+ } else {
+ $not = 'NOT';
+ }
+
+ $sql = <<<END
+$not EXISTS (SELECT * FROM {$CONFIG->dbprefix}annotations a
+INNER JOIN {$CONFIG->dbprefix}metastrings ms ON (a.name_id = ms.id)
+WHERE ms.string = '$annotation_name'
+AND a.entity_guid = $entity_guid
+AND a.owner_guid = $owner_guid)
+END;
+ return $sql;
}
/**
- * Determines whether the given user has access to the given entity
+ * Can a user access an entity.
+ *
+ * @warning If a logged in user doesn't have access to an entity, the
+ * core engine will not load that entity.
+ *
+ * @tip This is mostly useful for checking if a user other than the logged in
+ * user has access to an entity that is currently loaded.
+ *
+ * @todo This function would be much more useful if we could pass the guid of the
+ * entity to test access for. We need to be able to tell whether the entity exists
+ * and whether the user has access to the entity.
*
* @param ElggEntity $entity The entity to check access for.
- * @param ElggUser $user Optionally the user to check access for.
+ * @param ElggUser $user Optionally user to check access for. Defaults to
+ * logged in user (which is a useless default).
*
- * @return boolean True if the user can access the entity
+ * @return bool
+ * @link http://docs.elgg.org/Access
*/
function has_access_to_entity($entity, $user = null) {
global $CONFIG;
@@ -333,7 +389,8 @@ function has_access_to_entity($entity, $user = null) {
}
$query = "SELECT guid from {$CONFIG->dbprefix}entities e WHERE e.guid = " . $entity->getGUID();
- $query .= " AND " . $access_bit; // Add access controls
+ // Add access controls
+ $query .= " AND " . $access_bit;
if (get_data($query)) {
return true;
} else {
@@ -342,22 +399,41 @@ function has_access_to_entity($entity, $user = null) {
}
/**
- * Returns an array of access permissions that the specified user is allowed to save objects with.
- * Permissions are of the form ('id' => 'Description')
+ * Returns an array of access permissions that the user is allowed to save content with.
+ * Permissions returned are of the form (id => 'name').
+ *
+ * Example return value in English:
+ * array(
+ * 0 => 'Private',
+ * -2 => 'Friends',
+ * 1 => 'Logged in users',
+ * 2 => 'Public',
+ * 34 => 'My favorite friends',
+ * );
*
- * @param int $user_id The user's GUID.
- * @param int $site_id The current site.
- * @param true|false $flush If this is set to true, this will shun any cached version
+ * Plugin hook of 'access:collections:write', 'user'
+ *
+ * @warning this only returns access collections that the user owns plus the
+ * standard access levels. It does not return access collections that the user
+ * belongs to such as the access collection for a group.
+ *
+ * @param int $user_id The user's GUID.
+ * @param int $site_id The current site.
+ * @param bool $flush If this is set to true, this will ignore a cached access array
*
* @return array List of access permissions
+ * @link http://docs.elgg.org/Access
*/
function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) {
- global $CONFIG;
- //@todo this is probably not needed since caching happens at the DB level.
- static $access_array;
+ global $CONFIG, $init_finished;
+ $cache = _elgg_get_access_cache();
+
+ if ($flush) {
+ $cache->clear();
+ }
if ($user_id == 0) {
- $user_id = get_loggedin_userid();
+ $user_id = elgg_get_logged_in_user_guid();
}
if (($site_id == 0) && (isset($CONFIG->site_id))) {
@@ -367,40 +443,99 @@ function get_write_access_array($user_id = 0, $site_id = 0, $flush = false) {
$user_id = (int) $user_id;
$site_id = (int) $site_id;
- if (empty($access_array[$user_id]) || $flush == true) {
+ $hash = $user_id . $site_id . 'get_write_access_array';
+
+ if ($cache[$hash]) {
+ $access_array = $cache[$hash];
+ } else {
+ // @todo is there such a thing as public write access?
+ $access_array = array(
+ ACCESS_PRIVATE => elgg_echo("PRIVATE"),
+ ACCESS_FRIENDS => elgg_echo("access:friends:label"),
+ ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"),
+ ACCESS_PUBLIC => elgg_echo("PUBLIC")
+ );
+
$query = "SELECT ag.* FROM {$CONFIG->dbprefix}access_collections ag ";
- $query .= " WHERE (ag.site_guid = {$site_id} OR ag.site_guid = 0)";
- $query .= " AND (ag.owner_guid = {$user_id})";
- $query .= " AND ag.id >= 3";
-
- $tmp_access_array = array( ACCESS_PRIVATE => elgg_echo("PRIVATE"),
- ACCESS_FRIENDS => elgg_echo("access:friends:label"),
- ACCESS_LOGGED_IN => elgg_echo("LOGGED_IN"),
- ACCESS_PUBLIC => elgg_echo("PUBLIC"));
- if ($collections = get_data($query)) {
- foreach($collections as $collection) {
- $tmp_access_array[$collection->id] = $collection->name;
+ $query .= " WHERE (ag.site_guid = $site_id OR ag.site_guid = 0)";
+ $query .= " AND (ag.owner_guid = $user_id)";
+
+ $collections = get_data($query);
+ if ($collections) {
+ foreach ($collections as $collection) {
+ $access_array[$collection->id] = $collection->name;
}
}
- $access_array[$user_id] = $tmp_access_array;
+ if ($init_finished) {
+ $cache[$hash] = $access_array;
+ }
+ }
+
+ $options = array(
+ 'user_id' => $user_id,
+ 'site_id' => $site_id
+ );
+ return elgg_trigger_plugin_hook('access:collections:write', 'user',
+ $options, $access_array);
+}
+
+/**
+ * Can the user change this access collection?
+ *
+ * Use the plugin hook of 'access:collections:write', 'user' to change this.
+ * @see get_write_access_array() for details on the hook.
+ *
+ * Respects access control disabling for admin users and {@see elgg_set_ignore_access()}
+ *
+ * @see get_write_access_array()
+ *
+ * @param int $collection_id The collection id
+ * @param mixed $user_guid The user GUID to check for. Defaults to logged in user.
+ * @return bool
+ */
+function can_edit_access_collection($collection_id, $user_guid = null) {
+ if ($user_guid) {
+ $user = get_entity((int) $user_guid);
} else {
- $tmp_access_array = $access_array[$user_id];
+ $user = elgg_get_logged_in_user_entity();
+ }
+
+ $collection = get_access_collection($collection_id);
+
+ if (!($user instanceof ElggUser) || !$collection) {
+ return false;
}
- $tmp_access_array = trigger_plugin_hook('access:collections:write','user',array('user_id' => $user_id, 'site_id' => $site_id),$tmp_access_array);
+ $write_access = get_write_access_array($user->getGUID(), 0, true);
- return $tmp_access_array;
+ // don't ignore access when checking users.
+ if ($user_guid) {
+ return array_key_exists($collection_id, $write_access);
+ } else {
+ return elgg_get_ignore_access() || array_key_exists($collection_id, $write_access);
+ }
}
/**
- * Creates a new access control collection owned by the specified user.
+ * Creates a new access collection.
+ *
+ * Access colletions allow plugins and users to create granular access
+ * for entities.
+ *
+ * Triggers plugin hook 'access:collections:addcollection', 'collection'
+ *
+ * @internal Access collections are stored in the access_collections table.
+ * Memberships to collections are in access_collections_membership.
*
- * @param string $name The name of the collection.
- * @param int $owner_guid The GUID of the owner (default: currently logged in user).
- * @param int $site_guid The GUID of the site (default: current site).
+ * @param string $name The name of the collection.
+ * @param int $owner_guid The GUID of the owner (default: currently logged in user).
+ * @param int $site_guid The GUID of the site (default: current site).
*
- * @return int|false Depending on success (the collection ID if successful).
+ * @return int|false The collection ID if successful and false on failure.
+ * @link http://docs.elgg.org/Access/Collections
+ * @see update_access_collection()
+ * @see delete_access_collection()
*/
function create_access_collection($name, $owner_guid = 0, $site_guid = 0) {
global $CONFIG;
@@ -411,7 +546,7 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) {
}
if ($owner_guid == 0) {
- $owner_guid = get_loggedin_userid();
+ $owner_guid = elgg_get_logged_in_user_guid();
}
if (($site_guid == 0) && (isset($CONFIG->site_guid))) {
$site_guid = $CONFIG->site_guid;
@@ -422,7 +557,8 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) {
SET name = '{$name}',
owner_guid = {$owner_guid},
site_guid = {$site_guid}";
- if (!$id = insert_data($q)) {
+ $id = insert_data($q);
+ if (!$id) {
return false;
}
@@ -430,7 +566,7 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) {
'collection_id' => $id
);
- if (!trigger_plugin_hook('access:collections:addcollection', 'collection', $params, true)) {
+ if (!elgg_trigger_plugin_hook('access:collections:addcollection', 'collection', $params, true)) {
return false;
}
@@ -440,168 +576,198 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) {
/**
* Updates the membership in an access collection.
*
- * @param int $collection_id The ID of the collection.
- * @param array $members Array of member GUIDs
- * @return true|false Depending on success
+ * @warning Expects a full list of all members that should
+ * be part of the access collection
+ *
+ * @note This will run all hooks associated with adding or removing
+ * members to access collections.
+ *
+ * @param int $collection_id The ID of the collection.
+ * @param array $members Array of member GUIDs
+ *
+ * @return bool
+ * @link http://docs.elgg.org/Access/Collections
+ * @see add_user_to_access_collection()
+ * @see remove_user_from_access_collection()
*/
function update_access_collection($collection_id, $members) {
- global $CONFIG;
+ $acl = get_access_collection($collection_id);
- $collection_id = (int) $collection_id;
+ if (!$acl) {
+ return false;
+ }
$members = (is_array($members)) ? $members : array();
- $collections = get_write_access_array();
+ $cur_members = get_members_of_access_collection($collection_id, true);
+ $cur_members = (is_array($cur_members)) ? $cur_members : array();
- if (array_key_exists($collection_id, $collections)) {
- $cur_members = get_members_of_access_collection($collection_id, true);
- $cur_members = (is_array($cur_members)) ? $cur_members : array();
+ $remove_members = array_diff($cur_members, $members);
+ $add_members = array_diff($members, $cur_members);
- $remove_members = array_diff($cur_members, $members);
- $add_members = array_diff($members, $cur_members);
+ $result = true;
- $params = array(
- 'collection_id' => $collection_id,
- 'members' => $members,
- 'add_members' => $add_members,
- 'remove_members' => $remove_members
- );
-
- foreach ($add_members as $guid) {
- add_user_to_access_collection($guid, $collection_id);
- }
-
- foreach ($remove_members as $guid) {
- remove_user_from_access_collection($guid, $collection_id);
- }
+ foreach ($add_members as $guid) {
+ $result = $result && add_user_to_access_collection($guid, $collection_id);
+ }
- return true;
+ foreach ($remove_members as $guid) {
+ $result = $result && remove_user_from_access_collection($guid, $collection_id);
}
- return false;
+ return $result;
}
/**
- * Deletes a specified access collection
+ * Deletes a specified access collection and its membership.
*
* @param int $collection_id The collection ID
- * @return true|false Depending on success
+ *
+ * @return bool
+ * @link http://docs.elgg.org/Access/Collections
+ * @see create_access_collection()
+ * @see update_access_collection()
*/
function delete_access_collection($collection_id) {
+ global $CONFIG;
$collection_id = (int) $collection_id;
- $collections = get_write_access_array(null, null, TRUE);
$params = array('collection_id' => $collection_id);
- if (!trigger_plugin_hook('access:collections:deletecollection', 'collection', $params, true)) {
+ if (!elgg_trigger_plugin_hook('access:collections:deletecollection', 'collection', $params, true)) {
return false;
}
- if (array_key_exists($collection_id, $collections)) {
- global $CONFIG;
- delete_data("delete from {$CONFIG->dbprefix}access_collection_membership where access_collection_id = {$collection_id}");
- delete_data("delete from {$CONFIG->dbprefix}access_collections where id = {$collection_id}");
- return true;
- } else {
- return false;
- }
+ // Deleting membership doesn't affect result of deleting ACL.
+ $q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership
+ WHERE access_collection_id = {$collection_id}";
+ delete_data($q);
+
+ $q = "DELETE FROM {$CONFIG->dbprefix}access_collections
+ WHERE id = {$collection_id}";
+ $result = delete_data($q);
+ return (bool)$result;
}
/**
* Get a specified access collection
*
+ * @note This doesn't return the members of an access collection,
+ * just the database row of the actual collection.
+ *
+ * @see get_members_of_access_collection()
+ *
* @param int $collection_id The collection ID
- * @return array|false Depending on success
+ *
+ * @return object|false
*/
function get_access_collection($collection_id) {
global $CONFIG;
$collection_id = (int) $collection_id;
- $get_collection = get_data_row("SELECT * FROM {$CONFIG->dbprefix}access_collections WHERE id = {$collection_id}");
+ $query = "SELECT * FROM {$CONFIG->dbprefix}access_collections WHERE id = {$collection_id}";
+ $get_collection = get_data_row($query);
return $get_collection;
}
/**
- * Adds a user to the specified user collection
+ * Adds a user to an access collection.
+ *
+ * Triggers the 'access:collections:add_user', 'collection' plugin hook.
*
- * @param int $user_guid The GUID of the user to add
+ * @param int $user_guid The GUID of the user to add
* @param int $collection_id The ID of the collection to add them to
- * @return true|false Depending on success
+ *
+ * @return bool
+ * @see update_access_collection()
+ * @see remove_user_from_access_collection()
+ * @link http://docs.elgg.org/Access/Collections
*/
function add_user_to_access_collection($user_guid, $collection_id) {
+ global $CONFIG;
+
$collection_id = (int) $collection_id;
$user_guid = (int) $user_guid;
- $collections = get_write_access_array();
-
- if (!($collection = get_access_collection($collection_id)))
- return false;
+ $user = get_user($user_guid);
- if ((array_key_exists($collection_id, $collections) || $collection->owner_guid == 0)
- && $user = get_user($user_guid)) {
- global $CONFIG;
+ $collection = get_access_collection($collection_id);
- $params = array(
- 'collection_id' => $collection_id,
- 'user_guid' => $user_guid
- );
-
- if (!trigger_plugin_hook('access:collections:add_user', 'collection', $params, true)) {
- return false;
- }
+ if (!($user instanceof Elgguser) || !$collection) {
+ return false;
+ }
- try {
- insert_data("insert into {$CONFIG->dbprefix}access_collection_membership set access_collection_id = {$collection_id}, user_guid = {$user_guid}");
- } catch (DatabaseException $e) {
- // nothing.
- }
- return true;
+ $params = array(
+ 'collection_id' => $collection_id,
+ 'user_guid' => $user_guid
+ );
+ $result = elgg_trigger_plugin_hook('access:collections:add_user', 'collection', $params, true);
+ if ($result == false) {
+ return false;
}
- return false;
+ // if someone tries to insert the same data twice, we do a no-op on duplicate key
+ $q = "INSERT INTO {$CONFIG->dbprefix}access_collection_membership
+ SET access_collection_id = $collection_id, user_guid = $user_guid
+ ON DUPLICATE KEY UPDATE user_guid = user_guid";
+ $result = insert_data($q);
+
+ return $result !== false;
}
/**
- * Removes a user from an access collection
+ * Removes a user from an access collection.
+ *
+ * Triggers the 'access:collections:remove_user', 'collection' plugin hook.
*
- * @param int $user_guid The user GUID
+ * @param int $user_guid The user GUID
* @param int $collection_id The access collection ID
- * @return true|false Depending on success
+ *
+ * @return bool
+ * @see update_access_collection()
+ * @see remove_user_from_access_collection()
+ * @link http://docs.elgg.org/Access/Collections
*/
function remove_user_from_access_collection($user_guid, $collection_id) {
+ global $CONFIG;
+
$collection_id = (int) $collection_id;
$user_guid = (int) $user_guid;
- $collections = get_write_access_array();
+ $user = get_user($user_guid);
- if (!($collection = get_access_collection($collection_id)))
- return false;
-
- if ((array_key_exists($collection_id, $collections) || $collection->owner_guid == 0) && $user = get_user($user_guid)) {
- global $CONFIG;
- $params = array(
- 'collection_id' => $collection_id,
- 'user_guid' => $user_guid
- );
+ $collection = get_access_collection($collection_id);
- if (!trigger_plugin_hook('access:collections:remove_user', 'collection', $params, true)) {
- return false;
- }
+ if (!($user instanceof Elgguser) || !$collection) {
+ return false;
+ }
- delete_data("delete from {$CONFIG->dbprefix}access_collection_membership where access_collection_id = {$collection_id} and user_guid = {$user_guid}");
- return true;
+ $params = array(
+ 'collection_id' => $collection_id,
+ 'user_guid' => $user_guid
+ );
+ if (!elgg_trigger_plugin_hook('access:collections:remove_user', 'collection', $params, true)) {
+ return false;
}
- return false;
+ $q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership
+ WHERE access_collection_id = {$collection_id}
+ AND user_guid = {$user_guid}";
+
+ return (bool)delete_data($q);
}
/**
- * Get all of a users collections
+ * Returns an array of database row objects of the access collections owned by $owner_guid.
+ *
+ * @param int $owner_guid The entity guid
+ * @param int $site_guid The GUID of the site (default: current site).
*
- * @param int $owner_guid The user ID
- * @param int $site_guid The GUID of the site (default: current site).
- * @return true|false Depending on success
+ * @return array|false
+ * @see add_access_collection()
+ * @see get_members_of_access_collection()
+ * @link http://docs.elgg.org/Access/Collections
*/
function get_user_access_collections($owner_guid, $site_guid = 0) {
global $CONFIG;
@@ -622,26 +788,33 @@ function get_user_access_collections($owner_guid, $site_guid = 0) {
}
/**
- * Get all of members of a friend collection
+ * Get all of members of an access collection
*
- * @param int $collection The collection's ID
- * @param true|false $idonly If set to true, will only return the members' IDs (default: false)
- * @return ElggUser entities if successful, false if not
+ * @param int $collection The collection's ID
+ * @param bool $idonly If set to true, will only return the members' GUIDs (default: false)
+ *
+ * @return array ElggUser guids or entities if successful, false if not
+ * @see add_user_to_access_collection()
+ * @see http://docs.elgg.org/Access/Collections
*/
function get_members_of_access_collection($collection, $idonly = FALSE) {
global $CONFIG;
$collection = (int)$collection;
if (!$idonly) {
- $query = "SELECT e.* FROM {$CONFIG->dbprefix}access_collection_membership m JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.user_guid WHERE m.access_collection_id = {$collection}";
+ $query = "SELECT e.* FROM {$CONFIG->dbprefix}access_collection_membership m"
+ . " JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.user_guid"
+ . " WHERE m.access_collection_id = {$collection}";
$collection_members = get_data($query, "entity_row_to_elggstar");
} else {
- $query = "SELECT e.guid FROM {$CONFIG->dbprefix}access_collection_membership m JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.user_guid WHERE m.access_collection_id = {$collection}";
+ $query = "SELECT e.guid FROM {$CONFIG->dbprefix}access_collection_membership m"
+ . " JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.user_guid"
+ . " WHERE m.access_collection_id = {$collection}";
$collection_members = get_data($query);
if (!$collection_members) {
return FALSE;
}
- foreach($collection_members as $key => $val) {
+ foreach ($collection_members as $key => $val) {
$collection_members[$key] = $val->guid;
}
}
@@ -650,93 +823,16 @@ function get_members_of_access_collection($collection, $idonly = FALSE) {
}
/**
- * Displays a user's access collections, using the friends/collections view
+ * Return entities based upon access id.
*
- * @param int $owner_guid The GUID of the owning user
- * @return string A formatted rendition of the collections
- */
-function elgg_view_access_collections($owner_guid) {
- if ($collections = get_user_access_collections($owner_guid)) {
- foreach($collections as $key => $collection) {
- $collections[$key]->members = get_members_of_access_collection($collection->id, true);
- $collections[$key]->entities = get_user_friends($owner_guid,"",9999);
- }
- }
-
- return elgg_view('friends/collections',array('collections' => $collections));
-}
-
-/**
- * Get entities with the specified access collection id.
+ * @param array $options Any options accepted by {@link elgg_get_entities()} and
+ * access_id => int The access ID of the entity.
*
- * @deprecated 1.7. Use elgg_get_entities_from_access_id()
- *
- * @param $collection_id
- * @param $entity_type
- * @param $entity_subtype
- * @param $owner_guid
- * @param $limit
- * @param $offset
- * @param $order_by
- * @param $site_guid
- * @param $count
- * @return unknown_type
- */
-function get_entities_from_access_id($collection_id, $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) {
- // log deprecated warning
- elgg_deprecated_notice('get_entities_from_access_id() was deprecated by elgg_get_entities()!', 1.7);
-
- if (!$collection_id) {
- return FALSE;
- }
-
- // build the options using given parameters
- $options = array();
- $options['limit'] = $limit;
- $options['offset'] = $offset;
- $options['count'] = $count;
-
- if ($entity_type) {
- $options['type'] = sanitise_string($entity_type);
- }
-
- if ($entity_subtype) {
- $options['subtype'] = $entity_subtype;
- }
-
- if ($site_guid) {
- $options['site_guid'] = $site_guid;
- }
-
- if ($order_by) {
- $options['order_by'] = sanitise_string("e.time_created, $order_by");
- }
-
- if ((is_array($owner_guid) && (count($owner_guid)))) {
- $options['owner_guids'] = array();
- foreach($owner_guid as $guid) {
- $options['owner_guids'][] = $guid;
- }
- }
-
- if ($site_guid) {
- $options['site_guid'] = $site_guid;
- }
-
- $options['access_id'] = $collection_id;
-
- return elgg_get_entities_from_access_id($options);
-}
-
-/**
- * Retrieve entities for a given access collection
- *
- * @param int $collection_id
- * @param array $options @see elgg_get_entities()
- * @return array
- * @since 1.7
+ * @see elgg_get_entities()
+ * @return mixed If count, int. If not count, array. false on errors.
+ * @since 1.7.0
*/
-function elgg_get_entities_from_access_id(array $options=array()) {
+function elgg_get_entities_from_access_id(array $options = array()) {
// restrict the resultset to access collection provided
if (!isset($options['access_id'])) {
return FALSE;
@@ -761,70 +857,101 @@ function elgg_get_entities_from_access_id(array $options=array()) {
/**
* Lists entities from an access collection
*
- * @param $collection_id
- * @param $entity_type
- * @param $entity_subtype
- * @param $owner_guid
- * @param $limit
- * @param $fullview
- * @param $viewtypetoggle
- * @param $pagination
- * @return str
- */
-function list_entities_from_access_id($collection_id, $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = true, $pagination = true) {
- $offset = (int) get_input('offset');
- $limit = (int) $limit;
- $count = get_entities_from_access_id($collection_id, $entity_type, $entity_subtype, $owner_guid, $limit, $offset, "", 0, true);
- $entities = get_entities_from_access_id($collection_id, $entity_type, $entity_subtype, $owner_guid, $limit, $offset, "", 0, false);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination);
+ * @param array $options See elgg_list_entities() and elgg_get_entities_from_access_id()
+ *
+ * @see elgg_list_entities()
+ * @see elgg_get_entities_from_access_id()
+ *
+ * @return string
+ */
+function elgg_list_entities_from_access_id(array $options = array()) {
+ return elgg_list_entities($options, 'elgg_get_entities_from_access_id');
}
/**
- * Return a humanreadable version of an entity's access level
+ * Return the name of an ACCESS_* constant or a access collection,
+ * but only if the user has write access on that ACL.
+ *
+ * @warning This function probably doesn't work how it's meant to.
*
- * @param $entity_accessid (int) The entity's access id
- * @return string e.g. Public, Private etc
- **/
-function get_readable_access_level($entity_accessid){
- $access = (int) $entity_accessid;
+ * @param int $entity_access_id The entity's access id
+ *
+ * @return string 'Public', 'Private', etc.
+ * @since 1.7.0
+ * @todo I think this probably wants get_access_array() instead of get_write_access_array(),
+ * but those two functions return different types of arrays.
+ */
+function get_readable_access_level($entity_access_id) {
+ $access = (int) $entity_access_id;
+
//get the access level for object in readable string
$options = get_write_access_array();
- foreach($options as $key => $option) {
- if($key == $access){
- $entity_acl = htmlentities($option, ENT_QUOTES, 'UTF-8');
- return $entity_acl;
- break;
- }
+
+ if (array_key_exists($access, $options)) {
+ return $options[$access];
}
- return false;
+
+ // return 'Limited' if the user does not have access to the access collection
+ return elgg_echo('access:limited:label');
}
/**
* Set if entity access system should be ignored.
*
+ * The access system will not return entities in any getter
+ * functions if the user doesn't have access.
+ *
+ * @internal For performance reasons this is done at the database access clause level.
+ *
+ * @tip Use this to access entities in automated scripts
+ * when no user is logged in.
+ *
+ * @note This clears the access cache.
+ *
+ * @warning This will not show disabled entities.
+ * Use {@link access_show_hidden_entities()} to access disabled entities.
+ *
+ * @param bool $ignore If true, disables all access checks.
+ *
* @return bool Previous ignore_access setting.
+ * @since 1.7.0
+ * @see http://docs.elgg.org/Access/IgnoreAccess
+ * @see elgg_get_ignore_access()
*/
function elgg_set_ignore_access($ignore = true) {
+ $cache = _elgg_get_access_cache();
+ $cache->clear();
$elgg_access = elgg_get_access_object();
- return $elgg_access->set_ignore_access($ignore);
+ return $elgg_access->setIgnoreAccess($ignore);
}
/**
* Get current ignore access setting.
*
* @return bool
+ * @since 1.7.0
+ * @see http://docs.elgg.org/Access/IgnoreAccess
+ * @see elgg_set_ignore_access()
*/
function elgg_get_ignore_access() {
- return elgg_get_access_object()->get_ignore_access();
+ return elgg_get_access_object()->getIgnoreAccess();
}
/**
- * Decides if the access system is being ignored.
+ * Decides if the access system should be ignored for a user.
+ *
+ * Returns true (meaning ignore access) if either of these 2 conditions are true:
+ * 1) an admin user guid is passed to this function.
+ * 2) {@link elgg_get_ignore_access()} returns true.
+ *
+ * @see elgg_set_ignore_access()
+ *
+ * @param int $user_guid The user to check against.
*
* @return bool
+ * @since 1.7.0
*/
-function elgg_check_access_overrides($user_guid = null) {
+function elgg_check_access_overrides($user_guid = 0) {
if (!$user_guid || $user_guid <= 0) {
$is_admin = false;
} else {
@@ -837,7 +964,12 @@ function elgg_check_access_overrides($user_guid = null) {
/**
* Returns the ElggAccess object.
*
+ * // @todo comment is incomplete
+ * This is used to
+ *
* @return ElggAccess
+ * @since 1.7.0
+ * @access private
*/
function elgg_get_access_object() {
static $elgg_access;
@@ -849,12 +981,23 @@ function elgg_get_access_object() {
return $elgg_access;
}
-global $init_finished;
+/**
+ * A flag to set if Elgg's access initialization is finished.
+ *
+ * @global bool $init_finished
+ * @access private
+ * @todo This is required to tell the access system to start caching because
+ * calls are made while in ignore access mode and before the user is logged in.
+ */
$init_finished = false;
/**
* A quick and dirty way to make sure the access permissions have been correctly set up
*
+ * @elgg_event_handler init system
+ * @todo Invesigate
+ *
+ * @return void
*/
function access_init() {
global $init_finished;
@@ -862,12 +1005,35 @@ function access_init() {
}
/**
- * Override permissions system
+ * Overrides the access system if appropriate.
*
+ * Allows admin users and calls after {@link elgg_set_ignore_access} to
+ * bypass the access system.
+ *
+ * Registered for the 'permissions_check', 'all' and the
+ * 'container_permissions_check', 'all' plugin hooks.
+ *
+ * Returns true to override the access system or null if no change is needed.
+ *
+ * @param string $hook
+ * @param string $type
+ * @param bool $value
+ * @param array $params
* @return true|null
+ * @access private
*/
-function elgg_override_permissions_hook($hook, $type, $returnval, $params) {
- $user_guid = get_loggedin_userid();
+function elgg_override_permissions($hook, $type, $value, $params) {
+ $user = elgg_extract('user', $params);
+ if ($user) {
+ $user_guid = $user->getGUID();
+ } else {
+ $user_guid = elgg_get_logged_in_user_guid();
+ }
+
+ // don't do this so ignore access still works with no one logged in
+ //if (!$user instanceof ElggUser) {
+ // return false;
+ //}
// check for admin
if ($user_guid && elgg_is_admin_user($user_guid)) {
@@ -883,9 +1049,30 @@ function elgg_override_permissions_hook($hook, $type, $returnval, $params) {
return NULL;
}
-// This function will let us know when 'init' has finished
-register_elgg_event_handler('init', 'system', 'access_init', 9999);
+/**
+ * Runs unit tests for the entities object.
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $value
+ * @param array $params
+ * @return array
+ *
+ * @access private
+ */
+function access_test($hook, $type, $value, $params) {
+ global $CONFIG;
+
+ $value[] = $CONFIG->path . 'engine/tests/api/access_collections.php';
+ return $value;
+}
+
+// Tell the access functions the system has booted, plugins are loaded,
+// and the user is logged in so it can start caching
+elgg_register_event_handler('ready', 'system', 'access_init');
// For overrided permissions
-register_plugin_hook('permissions_check', 'all', 'elgg_override_permissions_hook');
-register_plugin_hook('container_permissions_check', 'all', 'elgg_override_permissions_hook');
+elgg_register_plugin_hook_handler('permissions_check', 'all', 'elgg_override_permissions');
+elgg_register_plugin_hook_handler('container_permissions_check', 'all', 'elgg_override_permissions');
+
+elgg_register_plugin_hook_handler('unit_test', 'system', 'access_test'); \ No newline at end of file
diff --git a/engine/lib/actions.php b/engine/lib/actions.php
index 57da1389f..8047914ac 100644
--- a/engine/lib/actions.php
+++ b/engine/lib/actions.php
@@ -1,95 +1,153 @@
<?php
/**
- * Elgg actions
- * Allows system modules to specify actions
+ * Elgg Actions
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * Actions are one of the primary controllers (The C in MVC) in Elgg. They are
+ * registered by {@link register_elgg_action()} and are called by URL
+ * http://elggsite.org/action/action_name. For URLs, a rewrite rule in
+ * .htaccess passes the action name to engine/handlers/action_handler.php,
+ * which dispatches the request for the action.
+ *
+ * An action name must be registered to a file in the system. Core actions are
+ * found in /actions/ and plugin actions are usually under /mod/<plugin>/actions/.
+ * It is recommended that actions be namespaced to avoid collisions.
+ *
+ * All actions require security tokens. Using the {@elgg_view input/form} view
+ * will automatically add tokens as hidden inputs as will the elgg_view_form()
+ * function. To manually add hidden inputs, use the {@elgg_view input/securitytoken} view.
+ *
+ * To include security tokens for actions called via GET, use
+ * {@link elgg_add_security_tokens_to_url()} or specify is_action as true when
+ * using {@lgg_view output/url}.
+ *
+ * Action tokens can be manually generated by using {@link generate_action_token()}.
+ *
+ * @tip When registered, actions can be restricted to logged in or admin users.
+ *
+ * @tip Action URLs should be called with a trailing / to prevent 301 redirects.
+ *
+ * @package Elgg.Core
+ * @subpackage Actions
+ * @link http://docs.elgg.org/Actions
+ * @link http://docs.elgg.org/Actions/Tokens
*/
-// Action setting and run *************************************************
-
/**
-* Loads an action script, if it exists, then forwards elsewhere
-*
-* @param string $action The requested action
-* @param string $forwarder Optionally, the location to forward to
-*/
-
+ * Perform an action.
+ *
+ * This function executes the action with name $action as registered
+ * by {@link elgg_register_action()}.
+ *
+ * The plugin hook 'action', $action_name will be triggered before the action
+ * is executed. If a handler returns false, it will prevent the action script
+ * from being called.
+ *
+ * @note If an action isn't registered in the system or is registered
+ * to an unavailable file the user will be forwarded to the site front
+ * page and an error will be emitted via {@link register_error()}.
+ *
+ * @warning All actions require {@link http://docs.elgg.org/Actions/Tokens Action Tokens}.
+ *
+ * @param string $action The requested action
+ * @param string $forwarder Optionally, the location to forward to
+ *
+ * @link http://docs.elgg.org/Actions
+ * @see elgg_register_action()
+ *
+ * @return void
+ * @access private
+ */
function action($action, $forwarder = "") {
global $CONFIG;
+ $action = rtrim($action, '/');
+
// @todo REMOVE THESE ONCE #1509 IS IN PLACE.
// Allow users to disable plugins without a token in order to
- // remove plugins that are imcompatible.
- // Installation cannot use tokens because it requires site secret to be
- // working. (#1462)
- // Login and logout are for convenience.
+ // remove plugins that are incompatible.
+ // Logout for convenience.
// file/download (see #2010)
$exceptions = array(
- 'systemsettings/install',
'admin/plugins/disable',
'logout',
- 'login',
'file/download',
);
if (!in_array($action, $exceptions)) {
- // All actions require a token.
- action_gatekeeper();
+ action_gatekeeper($action);
}
- $forwarder = str_replace($CONFIG->url, "", $forwarder);
+ $forwarder = str_replace(elgg_get_site_url(), "", $forwarder);
$forwarder = str_replace("http://", "", $forwarder);
$forwarder = str_replace("@", "", $forwarder);
-
- if (substr($forwarder,0,1) == "/") {
- $forwarder = substr($forwarder,1);
+ if (substr($forwarder, 0, 1) == "/") {
+ $forwarder = substr($forwarder, 1);
}
- if (isset($CONFIG->actions[$action])) {
- if ((isadminloggedin()) || (!$CONFIG->actions[$action]['admin'])) {
- if ($CONFIG->actions[$action]['public'] || get_loggedin_userid()) {
-
- // Trigger action event TODO: This is only called before the primary action is called. We need to rethink actions for 1.5
- $event_result = true;
- $event_result = trigger_plugin_hook('action', $action, null, $event_result);
-
- // Include action
- // Event_result being false doesn't produce an error -
- // since i assume this will be handled in the hook itself.
- // TODO make this better!
- if ($event_result) {
- if (!include($CONFIG->actions[$action]['file'])) {
- register_error(sprintf(elgg_echo('actionundefined'),$action));
- }
- }
- } else {
- register_error(elgg_echo('actionloggedout'));
+ if (!isset($CONFIG->actions[$action])) {
+ register_error(elgg_echo('actionundefined', array($action)));
+ } elseif (!elgg_is_admin_logged_in() && ($CONFIG->actions[$action]['access'] === 'admin')) {
+ register_error(elgg_echo('actionunauthorized'));
+ } elseif (!elgg_is_logged_in() && ($CONFIG->actions[$action]['access'] !== 'public')) {
+ register_error(elgg_echo('actionloggedout'));
+ } else {
+ // Returning falsy doesn't produce an error
+ // We assume this will be handled in the hook itself.
+ if (elgg_trigger_plugin_hook('action', $action, null, true)) {
+ if (!include($CONFIG->actions[$action]['file'])) {
+ register_error(elgg_echo('actionnotfound', array($action)));
}
- } else {
- register_error(elgg_echo('actionunauthorized'));
}
- } else {
- register_error(sprintf(elgg_echo('actionundefined'),$action));
}
- forward($CONFIG->url . $forwarder);
+ $forwarder = empty($forwarder) ? REFERER : $forwarder;
+ forward($forwarder);
}
/**
- * Registers a particular action in memory
+ * Registers an action.
+ *
+ * Actions are registered to a script in the system and are executed
+ * either by the URL http://elggsite.org/action/action_name/.
+ *
+ * $filename must be the full path of the file to register, or a path relative
+ * to the core actions/ dir.
+ *
+ * Actions should be namedspaced for your plugin. Example:
+ * <code>
+ * elgg_register_action('myplugin/save_settings', ...);
+ * </code>
+ *
+ * @tip Put action files under the actions/<plugin_name> directory of your plugin.
+ *
+ * @tip You don't need to include engine/start.php in your action files.
+ *
+ * @internal Actions are saved in $CONFIG->actions as an array in the form:
+ * <code>
+ * array(
+ * 'file' => '/location/to/file.php',
+ * 'access' => 'public', 'logged_in', or 'admin'
+ * )
+ * </code>
*
- * @param string $action The name of the action (eg "register", "account/settings/save")
- * @param boolean $public Can this action be accessed by people not logged into the system?
- * @param string $filename Optionally, the filename where this action is located
- * @param boolean $admin_only Whether this action is only available to admin users.
+ * @param string $action The name of the action (eg "register", "account/settings/save")
+ * @param string $filename Optionally, the filename where this action is located. If not specified,
+ * will assume the action is in elgg/actions/<action>.php
+ * @param string $access Who is allowed to execute this action: public, logged_in, admin.
+ * (default: logged_in)
+ *
+ * @see action()
+ * @see http://docs.elgg.org/Actions
+ *
+ * @return bool
*/
-function register_action($action, $public = false, $filename = "", $admin_only = false) {
+function elgg_register_action($action, $filename = "", $access = 'logged_in') {
global $CONFIG;
+ // plugins are encouraged to call actions with a trailing / to prevent 301
+ // redirects but we store the actions without it
+ $action = rtrim($action, '/');
+
if (!isset($CONFIG->actions)) {
$CONFIG->actions = array();
}
@@ -103,48 +161,92 @@ function register_action($action, $public = false, $filename = "", $admin_only =
$filename = $path . "actions/" . $action . ".php";
}
- $CONFIG->actions[$action] = array('file' => $filename, 'public' => $public, 'admin' => $admin_only);
+ $CONFIG->actions[$action] = array(
+ 'file' => $filename,
+ 'access' => $access,
+ );
return true;
}
/**
- * Actions to perform on initialisation
+ * Unregisters an action
*
- * @param string $event Events API required parameters
- * @param string $object_type Events API required parameters
- * @param string $object Events API required parameters
+ * @param string $action Action name
+ * @return bool
+ * @since 1.8.1
*/
-function actions_init($event, $object_type, $object) {
- register_action("error");
- return true;
+function elgg_unregister_action($action) {
+ global $CONFIG;
+
+ if (isset($CONFIG->actions[$action])) {
+ unset($CONFIG->actions[$action]);
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Is the token timestamp within acceptable range?
+ *
+ * @param int $ts timestamp from the CSRF token
+ *
+ * @return bool
+ */
+function _elgg_validate_token_timestamp($ts) {
+ $action_token_timeout = elgg_get_config('action_token_timeout');
+ // default is 2 hours
+ $timeout = ($action_token_timeout !== null) ? $action_token_timeout : 2;
+
+ $hour = 60 * 60;
+ $timeout = $timeout * $hour;
+ $now = time();
+
+ // Validate time to ensure its not crazy
+ return ($timeout == 0 || ($ts > $now - $timeout) && ($ts < $now + $timeout));
}
/**
- * Validate an action token, returning true if valid and false if not
+ * Validate an action token.
*
- * @return unknown
+ * Calls to actions will automatically validate tokens. If tokens are not
+ * present or invalid, the action will be denied and the user will be redirected.
+ *
+ * Plugin authors should never have to manually validate action tokens.
+ *
+ * @param bool $visibleerrors Emit {@link register_error()} errors on failure?
+ * @param mixed $token The token to test against. Default: $_REQUEST['__elgg_token']
+ * @param mixed $ts The time stamp to test against. Default: $_REQUEST['__elgg_ts']
+ *
+ * @return bool
+ * @see generate_action_token()
+ * @link http://docs.elgg.org/Actions/Tokens
+ * @access private
*/
-function validate_action_token($visibleerrors = true) {
- $token = get_input('__elgg_token');
- $ts = get_input('__elgg_ts');
+function validate_action_token($visibleerrors = TRUE, $token = NULL, $ts = NULL) {
+ if (!$token) {
+ $token = get_input('__elgg_token');
+ }
+
+ if (!$ts) {
+ $ts = get_input('__elgg_ts');
+ }
+
$session_id = session_id();
if (($token) && ($ts) && ($session_id)) {
// generate token, check with input and forward if invalid
- $generated_token = generate_action_token($ts);
+ $required_token = generate_action_token($ts);
// Validate token
- if ($token == $generated_token) {
- $hour = 60*60;
- $now = time();
-
- // Validate time to ensure its not crazy
- if (($ts>$now-$hour) && ($ts<$now+$hour)) {
+ if ($token == $required_token) {
+
+ if (_elgg_validate_token_timestamp($ts)) {
// We have already got this far, so unless anything
- // else says something to the contry we assume we're ok
+ // else says something to the contrary we assume we're ok
$returnval = true;
- $returnval = trigger_plugin_hook('action_gatekeeper:permissions:check', 'all', array(
+ $returnval = elgg_trigger_plugin_hook('action_gatekeeper:permissions:check', 'all', array(
'token' => $token,
'time' => $ts
), $returnval);
@@ -155,63 +257,126 @@ function validate_action_token($visibleerrors = true) {
register_error(elgg_echo('actiongatekeeper:pluginprevents'));
}
} else if ($visibleerrors) {
- register_error(elgg_echo('actiongatekeeper:timeerror'));
+ // this is necessary because of #5133
+ if (elgg_is_xhr()) {
+ register_error(elgg_echo('js:security:token_refresh_failed', array(elgg_get_site_url())));
+ } else {
+ register_error(elgg_echo('actiongatekeeper:timeerror'));
+ }
}
} else if ($visibleerrors) {
- register_error(elgg_echo('actiongatekeeper:tokeninvalid'));
+ // this is necessary because of #5133
+ if (elgg_is_xhr()) {
+ register_error(elgg_echo('js:security:token_refresh_failed', array(elgg_get_site_url())));
+ } else {
+ register_error(elgg_echo('actiongatekeeper:tokeninvalid'));
+ }
+ }
+ } else {
+ if (! empty($_SERVER['CONTENT_LENGTH']) && empty($_POST)) {
+ // The size of $_POST or uploaded file has exceed the size limit
+ $error_msg = elgg_trigger_plugin_hook('action_gatekeeper:upload_exceeded_msg', 'all', array(
+ 'post_size' => $_SERVER['CONTENT_LENGTH'],
+ 'visible_errors' => $visibleerrors,
+ ), elgg_echo('actiongatekeeper:uploadexceeded'));
+ } else {
+ $error_msg = elgg_echo('actiongatekeeper:missingfields');
+ }
+ if ($visibleerrors) {
+ register_error($error_msg);
}
- }
- else if ($visibleerrors) {
- register_error(elgg_echo('actiongatekeeper:missingfields'));
}
return FALSE;
}
/**
-* Action gatekeeper.
-* This function verifies form input for security features (like a generated token), and forwards
-* the page if they are invalid.
-*
-* Place at the head of actions.
-*/
-function action_gatekeeper() {
- if (validate_action_token()) {
- return TRUE;
+ * Validates the presence of action tokens.
+ *
+ * This function is called for all actions. If action tokens are missing,
+ * the user will be forwarded to the site front page and an error emitted.
+ *
+ * This function verifies form input for security features (like a generated token),
+ * and forwards if they are invalid.
+ *
+ * @param string $action The action being performed
+ *
+ * @return mixed True if valid or redirects.
+ * @access private
+ */
+function action_gatekeeper($action) {
+ if ($action === 'login') {
+ if (validate_action_token(false)) {
+ return true;
+ }
+
+ $token = get_input('__elgg_token');
+ $ts = (int)get_input('__elgg_ts');
+ if ($token && _elgg_validate_token_timestamp($ts)) {
+ // The tokens are present and the time looks valid: this is probably a mismatch due to the
+ // login form being on a different domain.
+ register_error(elgg_echo('actiongatekeeper:crosssitelogin'));
+
+
+ forward('login', 'csrf');
+ }
+
+ // let the validator send an appropriate msg
+ validate_action_token();
+
+ } elseif (validate_action_token()) {
+ return true;
}
- forward();
- exit;
+ forward(REFERER, 'csrf');
}
/**
- * Generate a token for the current user suitable for being placed in a hidden field in action forms.
+ * Generate an action token.
+ *
+ * Action tokens are based on timestamps as returned by {@link time()}.
+ * They are valid for one hour.
+ *
+ * Action tokens should be passed to all actions name __elgg_ts and __elgg_token.
+ *
+ * @warning Action tokens are required for all actions.
*
* @param int $timestamp Unix timestamp
+ *
+ * @see @elgg_view input/securitytoken
+ * @see @elgg_view input/form
+ * @example actions/manual_tokens.php
+ *
+ * @return string|false
+ * @access private
*/
function generate_action_token($timestamp) {
- // Get input values
$site_secret = get_site_secret();
-
- // Current session id
$session_id = session_id();
-
// Session token
$st = $_SESSION['__elgg_session'];
if (($site_secret) && ($session_id)) {
- return md5($site_secret.$timestamp.$session_id.$st);
+ return md5($site_secret . $timestamp . $session_id . $st);
}
return FALSE;
}
/**
- * Initialise the site secret.
+ * Initialise the site secret (32 bytes: "z" to indicate format + 186-bit key in Base64 URL).
+ *
+ * Used during installation and saves as a datalist.
+ *
+ * Note: Old secrets were hex encoded.
*
+ * @return mixed The site secret hash or false
+ * @access private
+ * @todo Move to better file.
*/
function init_site_secret() {
- $secret = md5(rand().microtime());
+ $secret = 'z' . ElggCrypto::getRandomString(31);
+
if (datalist_set('__site_secret__', $secret)) {
return $secret;
}
@@ -220,8 +385,13 @@ function init_site_secret() {
}
/**
- * Retrieve the site secret.
+ * Returns the site secret.
+ *
+ * Used to generate difficult to guess hashes for sessions and action tokens.
*
+ * @return string Site secret.
+ * @access private
+ * @todo Move to better file.
*/
function get_site_secret() {
$secret = datalist_get('__site_secret__');
@@ -233,17 +403,147 @@ function get_site_secret() {
}
/**
- * Check if an action is registered and its file exists.
+ * Get the strength of the site secret
*
- * @param string $action
- * @return BOOL
- * @since 1.8
+ * @return string "strong", "moderate", or "weak"
+ * @access private
*/
-function elgg_action_exist($action) {
+function _elgg_get_site_secret_strength() {
+ $secret = get_site_secret();
+ if ($secret[0] !== 'z') {
+ $rand_max = getrandmax();
+ if ($rand_max < pow(2, 16)) {
+ return 'weak';
+ }
+ if ($rand_max < pow(2, 32)) {
+ return 'moderate';
+ }
+ }
+ return 'strong';
+}
+
+/**
+ * Check if an action is registered and its script exists.
+ *
+ * @param string $action Action name
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_action_exists($action) {
global $CONFIG;
return (isset($CONFIG->actions[$action]) && file_exists($CONFIG->actions[$action]['file']));
}
-// Register some actions ***************************************************
-register_elgg_event_handler("init","system","actions_init");
+/**
+ * Checks whether the request was requested via ajax
+ *
+ * @return bool whether page was requested via ajax
+ * @since 1.8.0
+ */
+function elgg_is_xhr() {
+ return isset($_SERVER['HTTP_X_REQUESTED_WITH'])
+ && strtolower($_SERVER['HTTP_X_REQUESTED_WITH']) == 'xmlhttprequest' ||
+ get_input('X-Requested-With') === 'XMLHttpRequest';
+}
+
+/**
+ * Catch calls to forward() in ajax request and force an exit.
+ *
+ * Forces response is json of the following form:
+ * <pre>
+ * {
+ * "current_url": "the.url.we/were/coming/from",
+ * "forward_url": "the.url.we/were/going/to",
+ * "system_messages": {
+ * "messages": ["msg1", "msg2", ...],
+ * "errors": ["err1", "err2", ...]
+ * },
+ * "status": -1 //or 0 for success if there are no error messages present
+ * }
+ * </pre>
+ * where "system_messages" is all message registers at the point of forwarding
+ *
+ * @param string $hook
+ * @param string $type
+ * @param string $reason
+ * @param array $params
+ * @return void
+ * @access private
+ */
+function ajax_forward_hook($hook, $type, $reason, $params) {
+ if (elgg_is_xhr()) {
+ // always pass the full structure to avoid boilerplate JS code.
+ $params = array(
+ 'output' => '',
+ 'status' => 0,
+ 'system_messages' => array(
+ 'error' => array(),
+ 'success' => array()
+ )
+ );
+
+ //grab any data echo'd in the action
+ $output = ob_get_clean();
+
+ //Avoid double-encoding in case data is json
+ $json = json_decode($output);
+ if (isset($json)) {
+ $params['output'] = $json;
+ } else {
+ $params['output'] = $output;
+ }
+
+ //Grab any system messages so we can inject them via ajax too
+ $system_messages = system_messages(NULL, "");
+
+ if (isset($system_messages['success'])) {
+ $params['system_messages']['success'] = $system_messages['success'];
+ }
+
+ if (isset($system_messages['error'])) {
+ $params['system_messages']['error'] = $system_messages['error'];
+ $params['status'] = -1;
+ }
+
+ // Check the requester can accept JSON responses, if not fall back to
+ // returning JSON in a plain-text response. Some libraries request
+ // JSON in an invisible iframe which they then read from the iframe,
+ // however some browsers will not accept the JSON MIME type.
+ if (stripos($_SERVER['HTTP_ACCEPT'], 'application/json') === FALSE) {
+ header("Content-type: text/plain");
+ } else {
+ header("Content-type: application/json");
+ }
+
+ echo json_encode($params);
+ exit;
+ }
+}
+
+/**
+ * Buffer all output echo'd directly in the action for inclusion in the returned JSON.
+ * @return void
+ * @access private
+ */
+function ajax_action_hook() {
+ if (elgg_is_xhr()) {
+ ob_start();
+ }
+}
+
+/**
+ * Initialize some ajaxy actions features
+ * @access private
+ */
+function actions_init() {
+ elgg_register_action('security/refreshtoken', '', 'public');
+
+ elgg_register_simplecache_view('js/languages/en');
+
+ elgg_register_plugin_hook_handler('action', 'all', 'ajax_action_hook');
+ elgg_register_plugin_hook_handler('forward', 'all', 'ajax_forward_hook');
+}
+
+elgg_register_event_handler('init', 'system', 'actions_init');
diff --git a/engine/lib/admin.php b/engine/lib/admin.php
index ad7896cb7..f36f29668 100644
--- a/engine/lib/admin.php
+++ b/engine/lib/admin.php
@@ -1,298 +1,663 @@
<?php
/**
* Elgg admin functions.
- * Functions for adding and manipulating options on the admin panel.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * Admin menu items
+ * Elgg has a convenience function for adding menu items to the sidebar of the
+ * admin area. @see elgg_register_admin_menu_item()
+ *
+ * Admin pages
+ * Plugins no not need to provide their own page handler to add a page to the
+ * admin area. A view placed at admin/<section>/<subsection> can be access
+ * at http://example.org/admin/<section>/<subsection>. The title of the page
+ * will be elgg_echo('admin:<section>:<subsection>'). For an example of how to
+ * add a page to the admin area, see the diagnostics plugin.
+ *
+ * Admin notices
+ * System messages (success and error messages) are used in both the main site
+ * and the admin area. There is a special presistent message for the admin area
+ * called an admin notice. It should be used when a plugin requires an
+ * administrator to take an action. An example is the categories plugin
+ * requesting that the administrator set site categories after the plugin has
+ * been activated. @see elgg_add_admin_notice()
+ *
+ *
+ * @package Elgg.Core
+ * @subpackage Admin
*/
-
/**
- * Register an admin page with the admin panel.
- * This function extends the view "admin/main" with the provided view. This view should provide a description
- * and either a control or a link to.
- *
- * Usage:
- * - To add a control to the main admin panel then extend admin/main
- * - To add a control to a new page create a page which renders a view admin/subpage
- * (where subpage is your new page -
- * nb. some pages already exist that you can extend), extend the main view to point to it,
- * and add controls to your new view.
- *
- * At the moment this is essentially a wrapper around elgg_extend_view().
- *
- * @param string $new_admin_view The view associated with the control you're adding
- * @param string $view The view to extend, by default this is 'admin/main'.
- * @param int $priority Optional priority to govern the appearance in the list.
+ * Get the admin users
+ *
+ * @param array $options Options array, @see elgg_get_entities() for parameters
+ *
+ * @return mixed Array of admin users or false on failure. If a count, returns int.
+ * @since 1.8.0
*/
-function extend_elgg_admin_page($new_admin_view, $view = 'admin/main', $priority = 500) {
- elgg_deprecated_notice('extend_elgg_admin_page() does nothing now. Extend admin views manually. See http://docs.elgg.org/', 1.8);
- //return elgg_extend_view($view, $new_admin_view, $priority);
+function elgg_get_admins(array $options = array()) {
+ global $CONFIG;
+
+ if (isset($options['joins'])) {
+ if (!is_array($options['joins'])) {
+ $options['joins'] = array($options['joins']);
+ }
+ $options['joins'][] = "join {$CONFIG->dbprefix}users_entity u on e.guid=u.guid";
+ } else {
+ $options['joins'] = array("join {$CONFIG->dbprefix}users_entity u on e.guid=u.guid");
+ }
+
+ if (isset($options['wheres'])) {
+ if (!is_array($options['wheres'])) {
+ $options['wheres'] = array($options['wheres']);
+ }
+ $options['wheres'][] = "u.admin = 'yes'";
+ } else {
+ $options['wheres'][] = "u.admin = 'yes'";
+ }
+
+ return elgg_get_entities($options);
}
/**
- * Calculate the plugin settings submenu.
- * This is done in a separate function called from the admin
- * page handler because of performance concerns.
+ * Write a persistent message to the admin view.
+ * Useful to alert the admin to take a certain action.
+ * The id is a unique ID that can be cleared once the admin
+ * completes the action.
*
+ * eg: add_admin_notice('twitter_services_no_api',
+ * 'Before your users can use Twitter services on this site, you must set up
+ * the Twitter API key in the <a href="link">Twitter Services Settings</a>');
+ *
+ * @param string $id A unique ID that your plugin can remember
+ * @param string $message Body of the message
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function elgg_admin_add_plugin_settings_sidemenu() {
- global $CONFIG;
+function elgg_add_admin_notice($id, $message) {
+ if ($id && $message) {
+ if (elgg_admin_notice_exists($id)) {
+ return false;
+ }
- if (!$installed_plugins = get_installed_plugins()) {
- // nothing added because no items
- return FALSE;
- }
+ // need to handle when no one is logged in
+ $old_ia = elgg_set_ignore_access(true);
- $parent_item = array(
- 'text' => elgg_echo('admin:plugin_settings'),
- 'id' => 'admin:plugin_settings'
- );
+ $admin_notice = new ElggObject();
+ $admin_notice->subtype = 'admin_notice';
+ // admins can see ACCESS_PRIVATE but no one else can.
+ $admin_notice->access_id = ACCESS_PRIVATE;
+ $admin_notice->admin_notice_id = $id;
+ $admin_notice->description = $message;
- elgg_add_submenu_item($parent_item, 'admin');
+ $result = $admin_notice->save();
- foreach ($installed_plugins as $plugin_id => $info) {
- if (!$info['active']) {
- continue;
- }
+ elgg_set_ignore_access($old_ia);
+
+ return (bool)$result;
+ }
+
+ return false;
+}
- if (elgg_view_exists("settings/{$plugin_id}/edit")) {
- $item = array(
- 'text' => $info['manifest']['name'],
- 'href' => "{$CONFIG->url}pg/admin/plugin_settings/$plugin_id",
- 'parent_id' => 'admin:plugin_settings'
- );
+/**
+ * Remove an admin notice by ID.
+ *
+ * eg In actions/twitter_service/save_settings:
+ * if (is_valid_twitter_api_key()) {
+ * delete_admin_notice('twitter_services_no_api');
+ * }
+ *
+ * @param string $id The unique ID assigned in add_admin_notice()
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_delete_admin_notice($id) {
+ if (!$id) {
+ return FALSE;
+ }
+ $result = TRUE;
+ $notices = elgg_get_entities_from_metadata(array(
+ 'metadata_name' => 'admin_notice_id',
+ 'metadata_value' => $id
+ ));
- elgg_add_submenu_item($item, 'admin');
+ if ($notices) {
+ // in case a bad plugin adds many, let it remove them all at once.
+ foreach ($notices as $notice) {
+ $result = ($result && $notice->delete());
}
+ return $result;
}
+ return FALSE;
+}
+
+/**
+ * Get admin notices. An admin must be logged in since the notices are private.
+ *
+ * @param int $limit Limit
+ *
+ * @return array Array of admin notices
+ * @since 1.8.0
+ */
+function elgg_get_admin_notices($limit = 10) {
+ return elgg_get_entities_from_metadata(array(
+ 'type' => 'object',
+ 'subtype' => 'admin_notice',
+ 'limit' => $limit
+ ));
+}
+
+/**
+ * Check if an admin notice is currently active.
+ *
+ * @param string $id The unique ID used to register the notice.
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_admin_notice_exists($id) {
+ $old_ia = elgg_set_ignore_access(true);
+ $notice = elgg_get_entities_from_metadata(array(
+ 'type' => 'object',
+ 'subtype' => 'admin_notice',
+ 'metadata_name_value_pair' => array('name' => 'admin_notice_id', 'value' => $id)
+ ));
+ elgg_set_ignore_access($old_ia);
+
+ return ($notice) ? TRUE : FALSE;
}
/**
* Add an admin area section or child section.
- * This is a wrapper for elgg_add_admin_item(array(...), 'admin').
+ * This is a wrapper for elgg_register_menu_item().
*
* Used in conjuction with http://elgg.org/admin/section_id/child_section style
- * page handler.
+ * page handler. See the documentation at the top of this file for more details
+ * on that.
+ *
+ * The text of the menu item is obtained from elgg_echo(admin:$parent_id:$menu_id)
+ *
+ * This function handles registering the parent if it has not been registered.
+ *
+ * @param string $section The menu section to add to
+ * @param string $menu_id The unique ID of section
+ * @param string $parent_id If a child section, the parent section id
+ * @param int $priority The menu item priority
*
- * @param string $section_id
- * @param string $section_title Human readable section title.
- * @param string $parent_id If a child section, the parent section id.
+ * @return bool
+ * @since 1.8.0
*/
-function elgg_add_admin_submenu_item($section_id, $section_title, $parent_id = NULL) {
- global $CONFIG;
+function elgg_register_admin_menu_item($section, $menu_id, $parent_id = NULL, $priority = 100) {
+
+ // make sure parent is registered
+ if ($parent_id && !elgg_is_menu_item_registered('page', $parent_id)) {
+ elgg_register_admin_menu_item($section, $parent_id);
+ }
// in the admin section parents never have links
if ($parent_id) {
- $href = "{$CONFIG->url}pg/admin/$parent_id/$section_id";
- } elseif ($section_id == 'overview') {
- $href = "{$CONFIG->url}pg/admin/$section_id";
-
+ $href = "admin/$parent_id/$menu_id";
} else {
$href = NULL;
}
- $item = array(
- 'text' => $section_title,
- 'href' => $href,
- 'id' => $section_id,
- 'parent_id' => $parent_id
- );
+ $name = $menu_id;
+ if ($parent_id) {
+ $name = "$parent_id:$name";
+ }
- return elgg_add_submenu_item($item, 'admin');
+ return elgg_register_menu_item('page', array(
+ 'name' => $name,
+ 'href' => $href,
+ 'text' => elgg_echo("admin:$name"),
+ 'context' => 'admin',
+ 'parent_name' => $parent_id,
+ 'priority' => $priority,
+ 'section' => $section
+ ));
}
/**
- * Initialise the admin page.
+ * Initialize the admin backend.
+ * @return void
+ * @access private
*/
function admin_init() {
- register_action('admin/user/ban', FALSE, "", TRUE);
- register_action('admin/user/unban', FALSE, "", TRUE);
- register_action('admin/user/delete', FALSE, "", TRUE);
- register_action('admin/user/resetpassword', FALSE, "", TRUE);
- register_action('admin/user/makeadmin', FALSE, "", TRUE);
- register_action('admin/user/removeadmin', FALSE, "", TRUE);
+ elgg_register_action('admin/user/ban', '', 'admin');
+ elgg_register_action('admin/user/unban', '', 'admin');
+ elgg_register_action('admin/user/delete', '', 'admin');
+ elgg_register_action('admin/user/resetpassword', '', 'admin');
+ elgg_register_action('admin/user/makeadmin', '', 'admin');
+ elgg_register_action('admin/user/removeadmin', '', 'admin');
+
+ elgg_register_action('admin/site/update_basic', '', 'admin');
+ elgg_register_action('admin/site/update_advanced', '', 'admin');
+ elgg_register_action('admin/site/flush_cache', '', 'admin');
+ elgg_register_action('admin/site/unlock_upgrade', '', 'admin');
+ elgg_register_action('admin/site/regenerate_secret', '', 'admin');
+
+ elgg_register_action('admin/menu/save', '', 'admin');
+
+ elgg_register_action('admin/delete_admin_notice', '', 'admin');
+
+ elgg_register_action('profile/fields/reset', '', 'admin');
+ elgg_register_action('profile/fields/add', '', 'admin');
+ elgg_register_action('profile/fields/edit', '', 'admin');
+ elgg_register_action('profile/fields/delete', '', 'admin');
+ elgg_register_action('profile/fields/reorder', '', 'admin');
+
+ elgg_register_simplecache_view('css/admin');
+ elgg_register_simplecache_view('js/admin');
+ $url = elgg_get_simplecache_url('js', 'admin');
+ elgg_register_js('elgg.admin', $url);
+ elgg_register_js('jquery.jeditable', 'vendors/jquery/jquery.jeditable.mini.js');
+
+ // administer
+ // dashboard
+ elgg_register_menu_item('page', array(
+ 'name' => 'dashboard',
+ 'href' => 'admin/dashboard',
+ 'text' => elgg_echo('admin:dashboard'),
+ 'context' => 'admin',
+ 'priority' => 10,
+ 'section' => 'administer'
+ ));
+ // statistics
+ elgg_register_admin_menu_item('administer', 'statistics', null, 20);
+ elgg_register_admin_menu_item('administer', 'overview', 'statistics');
+ elgg_register_admin_menu_item('administer', 'server', 'statistics');
- register_action('admin/site/update_basic', FALSE, "", TRUE);
- register_action('admin/site/update_advanced', FALSE, "", TRUE);
+ // users
+ elgg_register_admin_menu_item('administer', 'users', null, 20);
+ elgg_register_admin_menu_item('administer', 'online', 'users', 10);
+ elgg_register_admin_menu_item('administer', 'admins', 'users', 20);
+ elgg_register_admin_menu_item('administer', 'newest', 'users', 30);
+ elgg_register_admin_menu_item('administer', 'add', 'users', 40);
- register_action('admin/menu_items', FALSE, "", TRUE);
+ // configure
+ // plugins
+ elgg_register_menu_item('page', array(
+ 'name' => 'plugins',
+ 'href' => 'admin/plugins',
+ 'text' => elgg_echo('admin:plugins'),
+ 'context' => 'admin',
+ 'priority' => 75,
+ 'section' => 'configure'
+ ));
- register_action('admin/plugins/simple_update_states', FALSE, '', TRUE);
+ // settings
+ elgg_register_admin_menu_item('configure', 'appearance', null, 50);
+ elgg_register_admin_menu_item('configure', 'settings', null, 100);
+ elgg_register_admin_menu_item('configure', 'basic', 'settings', 10);
+ elgg_register_admin_menu_item('configure', 'advanced', 'settings', 20);
+ elgg_register_admin_menu_item('configure', 'advanced/site_secret', 'settings', 25);
+ elgg_register_admin_menu_item('configure', 'menu_items', 'appearance', 30);
+ elgg_register_admin_menu_item('configure', 'profile_fields', 'appearance', 40);
+ // default widgets is added via an event handler elgg_default_widgets_init() in widgets.php
+ // because it requires additional setup.
+
+ // plugin settings are added in elgg_admin_add_plugin_settings_menu() via the admin page handler
+ // for performance reasons.
+
+ // we want plugin settings menu items to be sorted alphabetical
+ if (elgg_in_context('admin')) {
+ elgg_register_plugin_hook_handler('prepare', 'menu:page', 'elgg_admin_sort_page_menu');
+ }
+
+ if (elgg_is_admin_logged_in()) {
+ elgg_register_menu_item('topbar', array(
+ 'name' => 'administration',
+ 'href' => 'admin',
+ 'text' => elgg_view_icon('settings') . elgg_echo('admin'),
+ 'priority' => 100,
+ 'section' => 'alt',
+ ));
+ }
+
+ // widgets
+ $widgets = array('online_users', 'new_users', 'content_stats', 'admin_welcome', 'control_panel');
+ foreach ($widgets as $widget) {
+ elgg_register_widget_type(
+ $widget,
+ elgg_echo("admin:widget:$widget"),
+ elgg_echo("admin:widget:$widget:help"),
+ 'admin'
+ );
+ }
- // admin area overview and basic site settings
- elgg_add_admin_submenu_item('overview', elgg_echo('admin:overview'));
+ // automatic adding of widgets for admin
+ elgg_register_event_handler('make_admin', 'user', 'elgg_add_admin_widgets');
- elgg_add_admin_submenu_item('site', elgg_echo('admin:site'));
- elgg_add_admin_submenu_item('basic', elgg_echo('admin:site:basic'), 'site');
- elgg_add_admin_submenu_item('advanced', elgg_echo('admin:site:advanced'), 'site');
+ elgg_register_page_handler('admin', 'admin_page_handler');
+ elgg_register_page_handler('admin_plugin_screenshot', 'admin_plugin_screenshot_page_handler');
+ elgg_register_page_handler('admin_plugin_text_file', 'admin_markdown_page_handler');
+}
- // appearance
- elgg_add_admin_submenu_item('appearance', elgg_echo('admin:appearance'));
+/**
+ * Create the plugin settings page menu.
+ *
+ * This is done in a separate function called from the admin
+ * page handler because of performance concerns.
+ *
+ * @return void
+ * @access private
+ * @since 1.8.0
+ */
+function elgg_admin_add_plugin_settings_menu() {
- //elgg_add_admin_submenu_item('basic', elgg_echo('admin:appearance'), 'appearance');
- elgg_add_admin_submenu_item('menu_items', elgg_echo('admin:menu_items'), 'appearance');
+ $active_plugins = elgg_get_plugins('active');
+ if (!$active_plugins) {
+ // nothing added because no items
+ return;
+ }
- // users
- elgg_add_admin_submenu_item('users', elgg_echo('admin:users'));
- elgg_add_admin_submenu_item('online', elgg_echo('admin:users:online'), 'users');
- elgg_add_admin_submenu_item('newest', elgg_echo('admin:users:newest'), 'users');
- elgg_add_admin_submenu_item('add', elgg_echo('admin:users:add'), 'users');
+ foreach ($active_plugins as $plugin) {
+ $plugin_id = $plugin->getID();
+ $settings_view_old = 'settings/' . $plugin_id . '/edit';
+ $settings_view_new = 'plugins/' . $plugin_id . '/settings';
+ if (elgg_view_exists($settings_view_new) || elgg_view_exists($settings_view_old)) {
+ elgg_register_menu_item('page', array(
+ 'name' => $plugin_id,
+ 'href' => "admin/plugin_settings/$plugin_id",
+ 'text' => $plugin->getManifest()->getName(),
+ 'parent_name' => 'settings',
+ 'context' => 'admin',
+ 'section' => 'configure',
+ ));
+ }
+ }
+}
- // plugins
- elgg_add_admin_submenu_item('plugins', elgg_echo('admin:plugins'));
- elgg_add_admin_submenu_item('simple', elgg_echo('admin:plugins:simple'), 'plugins');
- elgg_add_admin_submenu_item('advanced', elgg_echo('admin:plugins:advanced'), 'plugins');
+/**
+ * Sort the plugin settings menu items
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $return
+ * @param array $params
+ *
+ * @return void
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_admin_sort_page_menu($hook, $type, $return, $params) {
+ $configure_items = $return['configure'];
+ /* @var ElggMenuItem[] $configure_items */
+ foreach ($configure_items as $menu_item) {
+ if ($menu_item->getName() == 'settings') {
+ $settings = $menu_item;
+ }
+ }
- // handled in the admin sidemenu so we don't have to generate this on every page load.
- //elgg_add_admin_submenu_item('plugin_settings', elgg_echo('admin:plugin_settings'));
+ // keep the basic and advanced settings at the top
+ /* @var ElggMenuItem $settings */
+ $children = $settings->getChildren();
+ $site_settings = array_splice($children, 0, 2);
+ usort($children, array('ElggMenuBuilder', 'compareByText'));
+ array_splice($children, 0, 0, $site_settings);
+ $settings->setChildren($children);
+}
- register_page_handler('admin', 'admin_settings_page_handler');
+/**
+ * Handles any set up required for administration pages
+ *
+ * @return void
+ * @access private
+ */
+function admin_pagesetup() {
+ if (elgg_in_context('admin')) {
+ $url = elgg_get_simplecache_url('css', 'admin');
+ elgg_register_css('elgg.admin', $url);
+ elgg_load_css('elgg.admin');
+ elgg_unregister_css('elgg');
+
+ // setup footer menu
+ elgg_register_menu_item('admin_footer', array(
+ 'name' => 'faq',
+ 'text' => elgg_echo('admin:footer:faq'),
+ 'href' => 'http://docs.elgg.org/wiki/Category:Administration_FAQ',
+ ));
+
+ elgg_register_menu_item('admin_footer', array(
+ 'name' => 'manual',
+ 'text' => elgg_echo('admin:footer:manual'),
+ 'href' => 'http://docs.elgg.org/wiki/Administration_Manual',
+ ));
+
+ elgg_register_menu_item('admin_footer', array(
+ 'name' => 'community_forums',
+ 'text' => elgg_echo('admin:footer:community_forums'),
+ 'href' => 'http://community.elgg.org/groups/all/',
+ ));
+
+ elgg_register_menu_item('admin_footer', array(
+ 'name' => 'blog',
+ 'text' => elgg_echo('admin:footer:blog'),
+ 'href' => 'http://blog.elgg.org/',
+ ));
+ }
}
/**
* Handle admin pages. Expects corresponding views as admin/section/subsection
*
- * @param $page
- * @return unknown_type
+ * @param array $page Array of pages
+ *
+ * @return bool
+ * @access private
*/
-function admin_settings_page_handler($page) {
- global $CONFIG;
+function admin_page_handler($page) {
admin_gatekeeper();
- elgg_admin_add_plugin_settings_sidemenu();
- set_context('admin');
+ elgg_admin_add_plugin_settings_menu();
+ elgg_set_context('admin');
- // default to overview
+ elgg_unregister_css('elgg');
+ elgg_load_js('elgg.admin');
+ elgg_load_js('jquery.jeditable');
+
+ // default to dashboard
if (!isset($page[0]) || empty($page[0])) {
- $page = array('overview');
+ $page = array('dashboard');
}
// was going to fix this in the page_handler() function but
// it's commented to explicitly return a string if there's a trailing /
- if (empty($page[count($page)-1])) {
+ if (empty($page[count($page) - 1])) {
array_pop($page);
}
$vars = array('page' => $page);
// special page for plugin settings since we create the form for them
- if ($page[0] == 'plugin_settings' && isset($page[1]) && elgg_view_exists("settings/{$page[1]}/edit")) {
- $view = '/admin/components/plugin_settings';
- $vars['plugin'] = $page[1];
- $vars['entity'] = find_plugin_settings($page[1]);
- $title = elgg_echo("admin:plugin_settings:{$page[1]}");
+ if ($page[0] == 'plugin_settings') {
+ if (isset($page[1]) && (elgg_view_exists("settings/{$page[1]}/edit") ||
+ elgg_view_exists("plugins/{$page[1]}/settings"))) {
+
+ $view = 'admin/plugin_settings';
+ $plugin = elgg_get_plugin_from_id($page[1]);
+ $vars['plugin'] = $plugin;
+
+ $title = elgg_echo("admin:{$page[0]}");
+ } else {
+ forward('', '404');
+ }
} else {
$view = 'admin/' . implode('/', $page);
- $title = elgg_echo('admin:' . implode(':', $page));
+ $title = elgg_echo("admin:{$page[0]}");
+ if (count($page) > 1) {
+ $title .= ' : ' . elgg_echo('admin:' . implode(':', $page));
+ }
}
- // allow a place to store helper views outside of the web-accessible views
+ // gets content and prevents direct access to 'components' views
if ($page[0] == 'components' || !($content = elgg_view($view, $vars))) {
$title = elgg_echo('admin:unknown_section');
$content = elgg_echo('admin:unknown_section');
}
- //$body = elgg_view('admin/components/admin_page_layout', array('content' => $content, 'page' => $page));
+ $body = elgg_view_layout('admin', array('content' => $content, 'title' => $title));
+ echo elgg_view_page($title, $body, 'admin');
+ return true;
+}
- $notices_html = '';
- if ($notices = elgg_get_admin_notices()) {
- foreach ($notices as $notice) {
- $notices_html .= elgg_view_entity($notice);
- }
+/**
+ * Serves up screenshots for plugins from
+ * admin_plugin_screenshot/<plugin_id>/<size>/<ss_name>.<ext>
+ *
+ * @param array $pages The pages array
+ * @return bool
+ * @access private
+ */
+function admin_plugin_screenshot_page_handler($pages) {
+ // only admins can use this for security
+ admin_gatekeeper();
+
+ $plugin_id = elgg_extract(0, $pages);
+ // only thumbnail or full.
+ $size = elgg_extract(1, $pages, 'thumbnail');
- $content = "<div class=\"admin_notices\">$notices_html</div>$content";
+ // the rest of the string is the filename
+ $filename_parts = array_slice($pages, 2);
+ $filename = implode('/', $filename_parts);
+ $filename = sanitise_filepath($filename, false);
+
+ $plugin = new ElggPlugin($plugin_id);
+ if (!$plugin) {
+ $file = elgg_get_root_path() . '_graphics/icons/default/medium.png';
+ } else {
+ $file = $plugin->getPath() . $filename;
+ if (!file_exists($file)) {
+ $file = elgg_get_root_path() . '_graphics/icons/default/medium.png';
+ }
}
- $body = elgg_view_layout('administration', $content);
- page_draw($title, $body, "", 'page_shells/admin');
+ header("Content-type: image/jpeg");
+
+ // resize to 100x100 for thumbnails
+ switch ($size) {
+ case 'thumbnail':
+ echo get_resized_image_from_existing_file($file, 100, 100, true);
+ break;
+
+ case 'full':
+ default:
+ echo file_get_contents($file);
+ break;
+ }
+ return true;
}
/**
- * Write a persistent message to the admin view.
- * Useful to alert the admin to take a certain action.
- * The id is a unique ID that can be cleared once the admin
- * completes the action.
+ * Formats and serves out markdown files from plugins.
*
- * eg: add_admin_notice('twitter_services_no_api',
- * 'Before your users can use Twitter services on this site, you must set up
- * the Twitter API key in the <a href="link">Twitter Services Settings</a>');
+ * URLs in format like admin_plugin_text_file/<plugin_id>/filename.ext
*
- * @param string $id A unique ID that your plugin can remember
- * @param string $message Body of the message
+ * The only valid files are:
+ * * README.txt
+ * * CHANGES.txt
+ * * INSTALL.txt
+ * * COPYRIGHT.txt
+ * * LICENSE.txt
+ *
+ * @param array $pages
+ * @return bool
+ * @access private
*/
-function elgg_add_admin_notice($id, $message) {
- if ($id && $message) {
- $admin_notice = new ElggObject();
- $admin_notice->subtype = 'admin_notice';
- // admins can see ACCESS_PRIVATE but no one else can.
- $admin_notice->access_id = ACCESS_PRIVATE;
- $admin_notice->admin_notice_id = $id;
- $admin_notice->description = $message;
+function admin_markdown_page_handler($pages) {
+ admin_gatekeeper();
- return $admin_notice->save();
+ elgg_set_context('admin');
+
+ elgg_unregister_css('elgg');
+ elgg_load_js('elgg.admin');
+ elgg_load_js('jquery.jeditable');
+ elgg_load_library('elgg:markdown');
+
+ $plugin_id = elgg_extract(0, $pages);
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ $filename = elgg_extract(1, $pages);
+
+ $error = false;
+ if (!$plugin) {
+ $error = elgg_echo('admin:plugins:markdown:unknown_plugin');
+ $body = elgg_view_layout('admin', array('content' => $error, 'title' => $error));
+ echo elgg_view_page($error, $body, 'admin');
+ return true;
}
- return FALSE;
-}
+ $text_files = $plugin->getAvailableTextFiles();
+ if (!array_key_exists($filename, $text_files)) {
+ $error = elgg_echo('admin:plugins:markdown:unknown_file');
+ }
-/**
- * Remove an admin notice by ID.
- *
- * eg In actions/twitter_service/save_settings:
- * if (is_valid_twitter_api_key()) {
- * delete_admin_notice('twitter_services_no_api');
- * }
- *
- * @param string $id The unique ID assigned in add_admin_notice()
- */
-function elgg_delete_admin_notice($id) {
- if (!$id) {
- return FALSE;
+ $file = $text_files[$filename];
+ $file_contents = file_get_contents($file);
+
+ if (!$file_contents) {
+ $error = elgg_echo('admin:plugins:markdown:unknown_file');
}
- $result = TRUE;
- if ($notices = elgg_get_entities_from_metadata(array('metadata_name' => 'admin_notice_id', 'metadata_value' => $id))) {
- // in case a bad plugin adds many, let it remove them all at once.
- foreach ($notices as $notice) {
- $result = ($result && $notice->delete());
- }
- return $result;
+
+ if ($error) {
+ $title = $error;
+ $body = elgg_view_layout('admin', array('content' => $error, 'title' => $title));
+ echo elgg_view_page($title, $body, 'admin');
+ return true;
}
- return FALSE;
-}
-/**
- * List all admin messages.
- *
- * @param int $limit Limit
- */
-function elgg_get_admin_notices($limit = 10) {
- return elgg_get_entities_from_metadata(array(
- 'type' => 'object',
- 'subtype' => 'admin_notice',
- 'limit' => $limit
+ $title = $plugin->getManifest()->getName() . ": $filename";
+ $text = Markdown($file_contents);
+
+ $body = elgg_view_layout('admin', array(
+ // setting classes here because there's no way to pass classes
+ // to the layout
+ 'content' => '<div class="elgg-markdown">' . $text . '</div>',
+ 'title' => $title
));
+
+ echo elgg_view_page($title, $body, 'admin');
+ return true;
}
/**
- * Check if an admin notice is currently active.
- * @param string $id The unique ID used to register the notice.
+ * Adds default admin widgets to the admin dashboard.
+ *
+ * @param string $event
+ * @param string $type
+ * @param ElggUser $user
+ *
+ * @return null|true
+ * @access private
*/
-function elgg_admin_notice_exists($id) {
- $notice = elgg_get_entities_from_metadata(array(
- 'type' => 'object',
- 'subtype' => 'admin_notice',
- 'metadata_name_value_pair' => array('name' => 'admin_notice_id', 'value' => $id)
- ));
+function elgg_add_admin_widgets($event, $type, $user) {
+ elgg_set_ignore_access(true);
- return ($notice) ? TRUE : FALSE;
-}
+ // check if the user already has widgets
+ if (elgg_get_widgets($user->getGUID(), 'admin')) {
+ return true;
+ }
+ // In the form column => array of handlers in order, top to bottom
+ $adminWidgets = array(
+ 1 => array('control_panel', 'admin_welcome'),
+ 2 => array('online_users', 'new_users', 'content_stats'),
+ );
+
+ foreach ($adminWidgets as $column => $handlers) {
+ foreach ($handlers as $position => $handler) {
+ $guid = elgg_create_widget($user->getGUID(), $handler, 'admin');
+ if ($guid) {
+ $widget = get_entity($guid);
+ /* @var ElggWidget $widget */
+ $widget->move($column, $position);
+ }
+ }
+ }
+ elgg_set_ignore_access(false);
+}
-// Register init functions
-register_elgg_event_handler('init', 'system', 'admin_init');
-register_elgg_event_handler('pagesetup', 'system', 'admin_pagesetup');
+elgg_register_event_handler('init', 'system', 'admin_init');
+elgg_register_event_handler('pagesetup', 'system', 'admin_pagesetup', 1000);
diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php
index ac002f394..5e9b530de 100644
--- a/engine/lib/annotations.php
+++ b/engine/lib/annotations.php
@@ -5,130 +5,19 @@
*
* @package Elgg
* @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
*/
/**
- * Include the ElggExtender superclass
- *
- */
-require_once('extender.php');
-
-/**
- * ElggAnnotation
- *
- * An annotation is similar to metadata each entity can contain more than one of each annotation.
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- */
-class ElggAnnotation extends ElggExtender {
-
- /**
- * Construct a new site object, optionally from a given id value or db row.
- *
- * @param mixed $id
- */
- function __construct($id = null) {
- $this->attributes = array();
-
- if (!empty($id)) {
- if ($id instanceof stdClass) {
- $annotation = $id;
- } else {
- $annotation = get_annotation($id);
- }
-
- if ($annotation) {
- $objarray = (array) $annotation;
-
- foreach($objarray as $key => $value) {
- $this->attributes[$key] = $value;
- }
-
- $this->attributes['type'] = "annotation";
- }
- }
- }
-
- /**
- * Class member get overloading
- *
- * @param string $name
- * @return mixed
- */
- function __get($name) {
- return $this->get($name);
- }
-
- /**
- * Class member set overloading
- *
- * @param string $name
- * @param mixed $value
- * @return void
- */
- function __set($name, $value) {
- return $this->set($name, $value);
- }
-
- /**
- * Save this instance
- *
- * @return int an object id
- */
- function save() {
- if ($this->id > 0) {
- return update_annotation($this->id, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id);
- } else {
- $this->id = create_annotation($this->entity_guid, $this->name, $this->value,
- $this->value_type, $this->owner_guid, $this->access_id);
-
- if (!$this->id) {
- throw new IOException(sprintf(elgg_new('IOException:UnableToSaveNew'), get_class()));
- }
- return $this->id;
- }
- }
-
- /**
- * Delete a given site.
- */
- function delete() {
- return delete_annotation($this->id);
- }
-
- /**
- * Get a url for this annotation.
- *
- * @return string
- */
- public function getURL() {
- return get_annotation_url($this->id);
- }
-
- // SYSTEM LOG INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * For a given ID, return the object associated with it.
- * This is used by the river functionality primarily.
- * This is useful for checking access permissions etc on objects.
- */
- public function getObjectFromID($id) {
- return get_annotation($id);
- }
-}
-
-/**
* Convert a database row to a new ElggAnnotation
*
- * @param stdClass $row
- * @return stdClass or ElggAnnotation
+ * @param stdClass $row Db row result object
+ *
+ * @return ElggAnnotation
+ * @access private
*/
function row_to_elggannotation($row) {
if (!($row instanceof stdClass)) {
+ // @todo should throw in this case?
return $row;
}
@@ -136,30 +25,46 @@ function row_to_elggannotation($row) {
}
/**
- * Get a specific annotation.
+ * Get a specific annotation by its id.
+ * If you want multiple annotation objects, use
+ * {@link elgg_get_annotations()}.
+ *
+ * @param int $id The id of the annotation object being retrieved.
*
- * @param int $annotation_id
+ * @return ElggAnnotation|false
*/
-function get_annotation($annotation_id) {
- global $CONFIG;
-
- $annotation_id = (int) $annotation_id;
- $access = get_access_sql_suffix("a");
+function elgg_get_annotation_from_id($id) {
+ return elgg_get_metastring_based_object_from_id($id, 'annotations');
+}
- return row_to_elggannotation(get_data_row("SELECT a.*, n.string as name, v.string as value from {$CONFIG->dbprefix}annotations a JOIN {$CONFIG->dbprefix}metastrings n on a.name_id = n.id JOIN {$CONFIG->dbprefix}metastrings v on a.value_id = v.id where a.id=$annotation_id and $access"));
+/**
+ * Deletes an annotation using its ID.
+ *
+ * @param int $id The annotation ID to delete.
+ * @return bool
+ */
+function elgg_delete_annotation_by_id($id) {
+ $annotation = elgg_get_annotation_from_id($id);
+ if (!$annotation) {
+ return false;
+ }
+ return $annotation->delete();
}
/**
* Create a new annotation.
*
- * @param int $entity_guid
- * @param string $name
- * @param string $value
- * @param string $value_type
- * @param int $owner_guid
- * @param int $access_id
+ * @param int $entity_guid Entity Guid
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value (default is auto detection)
+ * @param int $owner_guid Owner of annotation (default is logged in user)
+ * @param int $access_id Access level of annotation
+ *
+ * @return int|bool id on success or false on failure
*/
-function create_annotation($entity_guid, $name, $value, $value_type, $owner_guid, $access_id = ACCESS_PRIVATE) {
+function create_annotation($entity_guid, $name, $value, $value_type = '',
+$owner_guid = 0, $access_id = ACCESS_PRIVATE) {
global $CONFIG;
$result = false;
@@ -170,8 +75,8 @@ function create_annotation($entity_guid, $name, $value, $value_type, $owner_guid
$value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type)));
$owner_guid = (int)$owner_guid;
- if ($owner_guid==0) {
- $owner_guid = get_loggedin_userid();
+ if ($owner_guid == 0) {
+ $owner_guid = elgg_get_logged_in_user_guid();
}
$access_id = (int)$access_id;
@@ -190,20 +95,20 @@ function create_annotation($entity_guid, $name, $value, $value_type, $owner_guid
$entity = get_entity($entity_guid);
- if (trigger_elgg_event('annotate',$entity->type,$entity)) {
- system_log($entity, 'annotate');
-
+ if (elgg_trigger_event('annotate', $entity->type, $entity)) {
// If ok then add it
$result = insert_data("INSERT into {$CONFIG->dbprefix}annotations
(entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id) VALUES
($entity_guid,'$name',$value,'$value_type', $owner_guid, $time, $access_id)");
- if ($result!==false) {
- $obj = get_annotation($result);
- if (trigger_elgg_event('create', 'annotation', $obj)) {
+ if ($result !== false) {
+ $obj = elgg_get_annotation_from_id($result);
+ if (elgg_trigger_event('create', 'annotation', $obj)) {
return $result;
} else {
- delete_annotation($result);
+ // plugin returned false to reject annotation
+ elgg_delete_annotation_by_id($result);
+ return FALSE;
}
}
}
@@ -214,12 +119,14 @@ function create_annotation($entity_guid, $name, $value, $value_type, $owner_guid
/**
* Update an annotation.
*
- * @param int $annotation_id
- * @param string $name
- * @param string $value
- * @param string $value_type
- * @param int $owner_guid
- * @param int $access_id
+ * @param int $annotation_id Annotation ID
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value
+ * @param int $owner_guid Owner of annotation
+ * @param int $access_id Access level of annotation
+ *
+ * @return bool
*/
function update_annotation($annotation_id, $name, $value, $value_type, $owner_guid, $access_id) {
global $CONFIG;
@@ -230,8 +137,8 @@ function update_annotation($annotation_id, $name, $value, $value_type, $owner_gu
$value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type)));
$owner_guid = (int)$owner_guid;
- if ($owner_guid==0) {
- $owner_guid = get_loggedin_userid();
+ if ($owner_guid == 0) {
+ $owner_guid = elgg_get_logged_in_user_guid();
}
$access_id = (int)$access_id;
@@ -251,201 +158,186 @@ function update_annotation($annotation_id, $name, $value, $value_type, $owner_gu
// If ok then add it
$result = update_data("UPDATE {$CONFIG->dbprefix}annotations
- set value_id='$value', value_type='$value_type', access_id=$access_id, owner_guid=$owner_guid
- where id=$annotation_id and name_id='$name' and $access");
-
- if ($result!==false) {
- $obj = get_annotation($annotation_id);
- if (trigger_elgg_event('update', 'annotation', $obj)) {
- return true;
- } else {
- delete_annotation($annotation_id);
- }
+ set name_id='$name', value_id='$value', value_type='$value_type', access_id=$access_id, owner_guid=$owner_guid
+ where id=$annotation_id and $access");
+
+ if ($result !== false) {
+ // @todo add plugin hook that sends old and new annotation information before db access
+ $obj = elgg_get_annotation_from_id($annotation_id);
+ elgg_trigger_event('update', 'annotation', $obj);
}
return $result;
}
/**
- * Get a list of annotations for a given object/user/annotation type.
+ * Returns annotations. Accepts all elgg_get_entities() options for entity
+ * restraints.
*
- * @param int|array $entity_guid
- * @param string $entity_type
- * @param string $entity_subtype
- * @param string $name
- * @param mixed $value
- * @param int|array $owner_guid
- * @param int $limit
- * @param int $offset
- * @param string $order_by
+ * @see elgg_get_entities
+ *
+ * @param array $options Array in format:
+ *
+ * annotation_names => NULL|ARR Annotation names
+ * annotation_values => NULL|ARR Annotation values
+ * annotation_ids => NULL|ARR annotation ids
+ * annotation_case_sensitive => BOOL Overall Case sensitive
+ * annotation_owner_guids => NULL|ARR guids for annotation owners
+ * annotation_created_time_lower => INT Lower limit for created time.
+ * annotation_created_time_upper => INT Upper limit for created time.
+ * annotation_calculation => STR Perform the MySQL function on the annotation values returned.
+ * Do not confuse this "annotation_calculation" option with the
+ * "calculation" option to elgg_get_entities_from_annotation_calculation().
+ * The "annotation_calculation" option causes this function to
+ * return the result of performing a mathematical calculation on
+ * all annotations that match the query instead of ElggAnnotation
+ * objects.
+ * See the docs for elgg_get_entities_from_annotation_calculation()
+ * for the proper use of the "calculation" option.
+ *
+ *
+ * @return ElggAnnotation[]|mixed
+ * @since 1.8.0
*/
-function get_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "",
-$value = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "asc", $timelower = 0, $timeupper = 0, $entity_owner_guid = 0) {
- global $CONFIG;
-
- $timelower = (int) $timelower;
- $timeupper = (int) $timeupper;
+function elgg_get_annotations(array $options = array()) {
- if (is_array($entity_guid)) {
- if (sizeof($entity_guid) > 0) {
- foreach($entity_guid as $key => $val) {
- $entity_guid[$key] = (int) $val;
- }
- } else {
- $entity_guid = 0;
- }
+ // @todo remove support for count shortcut - see #4393
+ if (isset($options['__egefac']) && $options['__egefac']) {
+ unset($options['__egefac']);
} else {
- $entity_guid = (int)$entity_guid;
- }
-
- $entity_type = sanitise_string($entity_type);
-
- if ($entity_subtype) {
- if (!$entity_subtype = get_subtype_id($entity_type, $entity_subtype)) {
- // requesting a non-existing subtype: return false
- return FALSE;
- }
- }
-
- if ($name) {
- $name = get_metastring_id($name);
-
- if ($name === false) {
- $name = 0;
- }
- }
- if ($value != "") {
- $value = get_metastring_id($value);
- }
-
- if (is_array($owner_guid)) {
- if (sizeof($owner_guid) > 0) {
- foreach($owner_guid as $key => $val) {
- $owner_guid[$key] = (int) $val;
- }
- } else {
- $owner_guid = 0;
- }
- } else {
- $owner_guid = (int)$owner_guid;
- }
-
- if (is_array($entity_owner_guid)) {
- if (sizeof($entity_owner_guid) > 0) {
- foreach($entity_owner_guid as $key => $val) {
- $entity_owner_guid[$key] = (int) $val;
- }
- } else {
- $entity_owner_guid = 0;
- }
- } else {
- $entity_owner_guid = (int)$entity_owner_guid;
- }
-
- $limit = (int)$limit;
- $offset = (int)$offset;
- if($order_by == 'asc') {
- $order_by = "a.time_created asc";
- }
-
- if($order_by == 'desc') {
- $order_by = "a.time_created desc";
- }
-
- $where = array();
-
- if ($entity_guid != 0 && !is_array($entity_guid)) {
- $where[] = "a.entity_guid=$entity_guid";
- } else if (is_array($entity_guid)) {
- $where[] = "a.entity_guid in (". implode(",",$entity_guid) . ")";
- }
-
- if ($entity_type != "") {
- $where[] = "e.type='$entity_type'";
- }
-
- if ($entity_subtype != "") {
- $where[] = "e.subtype='$entity_subtype'";
- }
+ // support shortcut of 'count' => true for 'annotation_calculation' => 'count'
+ if (isset($options['count']) && $options['count']) {
+ $options['annotation_calculation'] = 'count';
+ unset($options['count']);
+ }
+ }
+
+ $options['metastring_type'] = 'annotations';
+ return elgg_get_metastring_based_objects($options);
+}
- if ($owner_guid != 0 && !is_array($owner_guid)) {
- $where[] = "a.owner_guid=$owner_guid";
- } else {
- if (is_array($owner_guid)) {
- $where[] = "a.owner_guid in (" . implode(",",$owner_guid) . ")";
- }
+/**
+ * Deletes annotations based on $options.
+ *
+ * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
+ * This requires at least one constraint: annotation_owner_guid(s),
+ * annotation_name(s), annotation_value(s), or guid(s) must be set.
+ *
+ * @param array $options An options array. {@See elgg_get_annotations()}
+ * @return bool|null true on success, false on failure, null if no annotations to delete.
+ * @since 1.8.0
+ */
+function elgg_delete_annotations(array $options) {
+ if (!elgg_is_valid_options_for_batch_operation($options, 'annotations')) {
+ return false;
}
- if ($entity_owner_guid != 0 && !is_array($entity_owner_guid)) {
- $where[] = "e.owner_guid=$entity_owner_guid";
- } else {
- if (is_array($entity_owner_guid)) {
- $where[] = "e.owner_guid in (" . implode(",",$entity_owner_guid) . ")";
- }
- }
+ $options['metastring_type'] = 'annotations';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false);
+}
- if ($name !== "") {
- $where[] = "a.name_id='$name'";
+/**
+ * Disables annotations based on $options.
+ *
+ * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
+ *
+ * @param array $options An options array. {@See elgg_get_annotations()}
+ * @return bool|null true on success, false on failure, null if no annotations disabled.
+ * @since 1.8.0
+ */
+function elgg_disable_annotations(array $options) {
+ if (!elgg_is_valid_options_for_batch_operation($options, 'annotations')) {
+ return false;
}
+
+ // if we can see hidden (disabled) we need to use the offset
+ // otherwise we risk an infinite loop if there are more than 50
+ $inc_offset = access_get_show_hidden_status();
- if ($value != "") {
- $where[] = "a.value_id='$value'";
- }
+ $options['metastring_type'] = 'annotations';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset);
+}
- if ($timelower) {
- $where[] = "a.time_created >= {$timelower}";
+/**
+ * Enables annotations based on $options.
+ *
+ * @warning Unlike elgg_get_annotations() this will not accept an empty options array!
+ *
+ * @warning In order to enable annotations, you must first use
+ * {@link access_show_hidden_entities()}.
+ *
+ * @param array $options An options array. {@See elgg_get_annotations()}
+ * @return bool|null true on success, false on failure, null if no metadata enabled.
+ * @since 1.8.0
+ */
+function elgg_enable_annotations(array $options) {
+ if (!$options || !is_array($options)) {
+ return false;
}
- if ($timeupper) {
- $where[] = "a.time_created <= {$timeupper}";
- }
+ $options['metastring_type'] = 'annotations';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_enable_callback');
+}
- $query = "SELECT a.*, n.string as name, v.string as value
- FROM {$CONFIG->dbprefix}annotations a
- JOIN {$CONFIG->dbprefix}entities e on a.entity_guid = e.guid
- JOIN {$CONFIG->dbprefix}metastrings v on a.value_id=v.id
- JOIN {$CONFIG->dbprefix}metastrings n on a.name_id = n.id where ";
+/**
+ * Returns a rendered list of annotations with pagination.
+ *
+ * @param array $options Annotation getter and display options.
+ * {@see elgg_get_annotations()} and {@see elgg_list_entities()}.
+ *
+ * @return string The list of entities
+ * @since 1.8.0
+ */
+function elgg_list_annotations($options) {
+ $defaults = array(
+ 'limit' => 25,
+ 'offset' => (int) max(get_input('annoff', 0), 0),
+ );
- foreach ($where as $w) {
- $query .= " $w and ";
- }
- $query .= get_access_sql_suffix("a"); // Add access controls
- $query .= " order by $order_by limit $offset,$limit"; // Add order and limit
+ $options = array_merge($defaults, $options);
- return get_data($query, "row_to_elggannotation");
+ return elgg_list_entities($options, 'elgg_get_annotations', 'elgg_view_annotation_list');
}
+/**
+ * Entities interfaces
+ */
/**
- * Returns entities based upon annotations. Accepts the same values as
- * elgg_get_entities_from_metadata() but uses the annotations table.
+ * Returns entities based upon annotations. Also accepts all options available
+ * to elgg_get_entities() and elgg_get_entities_from_metadata().
*
- * NB: Entity creation time is selected as max_time. To sort based upon
+ * Entity creation time is selected as maxtime. To sort based upon
* this, pass 'order_by' => 'maxtime asc' || 'maxtime desc'
*
- * time_created in this case will be the time the annotation was created.
- *
* @see elgg_get_entities
* @see elgg_get_entities_from_metadata
+ *
* @param array $options Array in format:
*
* annotation_names => NULL|ARR annotations names
*
* annotation_values => NULL|ARR annotations values
*
- * annotation_name_value_pairs => NULL|ARR (name = 'name', value => 'value', 'operand' => '=', 'case_sensitive' => TRUE) entries.
- * Currently if multiple values are sent via an array (value => array('value1', 'value2') the pair's operand will be forced to "IN".
+ * annotation_name_value_pairs => NULL|ARR (name = 'name', value => 'value',
+ * 'operator' => '=', 'case_sensitive' => TRUE) entries.
+ * Currently if multiple values are sent via an array (value => array('value1', 'value2')
+ * the pair's operator will be forced to "IN".
*
- * annotation_name_value_pairs_operator => NULL|STR The operator to use for combining (name = value) OPERATOR (name = value); default AND
+ * annotation_name_value_pairs_operator => NULL|STR The operator to use for combining
+ * (name = value) OPERATOR (name = value); default AND
*
* annotation_case_sensitive => BOOL Overall Case sensitive
*
- * order_by_annotation => NULL|ARR (array('name' => 'annotation_text1', 'direction' => ASC|DESC, 'as' => text|integer),
+ * order_by_annotation => NULL|ARR (array('name' => 'annotation_text1', 'direction' => ASC|DESC,
+ * 'as' => text|integer),
+ *
* Also supports array('name' => 'annotation_text1')
*
* annotation_owner_guids => NULL|ARR guids for annotaiton owners
*
- * @return array
+ * @return mixed If count, int. If not count, array. false on errors.
+ * @since 1.7.0
*/
function elgg_get_entities_from_annotations(array $options = array()) {
$defaults = array(
@@ -457,6 +349,9 @@ function elgg_get_entities_from_annotations(array $options = array()) {
'annotation_case_sensitive' => TRUE,
'order_by_annotation' => array(),
+ 'annotation_created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
+ 'annotation_created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
+
'annotation_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
'order_by' => 'maxtime desc',
@@ -465,11 +360,14 @@ function elgg_get_entities_from_annotations(array $options = array()) {
$options = array_merge($defaults, $options);
- $singulars = array('annotation_name', 'annotation_value', 'annotation_name_value_pair', 'annotation_owner_guid');
+ $singulars = array('annotation_name', 'annotation_value',
+ 'annotation_name_value_pair', 'annotation_owner_guid');
+
$options = elgg_normalise_plural_options_array($options, $singulars);
+ $options = elgg_entities_get_metastrings_options('annotation', $options);
- if (!$options = elgg_entities_get_metastrings_options('annotation', $options)) {
- return FALSE;
+ if (!$options) {
+ return false;
}
// special sorting for annotations
@@ -477,625 +375,116 @@ function elgg_get_entities_from_annotations(array $options = array()) {
$options['selects'][] = "max(n_table.time_created) as maxtime";
$options['group_by'] = 'n_table.entity_guid';
- return elgg_get_entities($options);
-}
-
-/**
- * @deprecated 1.7 Use elgg_get_entities_from_annotations()
- * @param $entity_type
- * @param $entity_subtype
- * @param $name
- * @param $value
- * @param $owner_guid
- * @param $group_guid
- * @param $limit
- * @param $offset
- * @param $order_by
- * @param $count
- * @param $timelower
- * @param $timeupper
- * @return unknown_type
- */
-function get_entities_from_annotations($entity_type = "", $entity_subtype = "", $name = "", $value = "",
-$owner_guid = 0, $group_guid = 0, $limit = 10, $offset = 0, $order_by = "asc", $count = false,
-$timelower = 0, $timeupper = 0) {
- elgg_deprecated_notice('get_entities_from_annotations() was deprecated by elgg_get_entities_from_annotations().', 1.7);
-
- $options = array();
-
- $options['annotation_names'] = $name;
-
- if ($value) {
- $options['annotation_values'] = $value;
- }
-
- if ($entity_type) {
- $options['types'] = $entity_type;
- }
-
- if ($entity_subtype) {
- $options['subtypes'] = $entity_subtype;
- }
-
- if ($owner_guid) {
- $options['annotation_owner_guid'] = $owner_guid;
- }
-
- if ($group_guid) {
- $options['container_guid'] = $group_guid;
- }
-
- if ($limit) {
- $options['limit'] = $limit;
- }
+ $time_wheres = elgg_get_entity_time_where_sql('a', $options['annotation_created_time_upper'],
+ $options['annotation_created_time_lower']);
- if ($offset) {
- $options['offset'] = $offset;
+ if ($time_wheres) {
+ $options['wheres'] = array_merge($options['wheres'], $time_wheres);
}
- if ($order_by) {
- $options['order_by'] = "maxtime $order_by";
- }
-
- if ($count) {
- $options['count'] = $count;
- }
-
- return elgg_get_entities_from_annotations($options);
-}
-
-/**
- * Lists entities
- *
- * @see elgg_view_entity_list
- *
- * @param string $entity_type Type of entity.
- * @param string $entity_subtype Subtype of entity.
- * @param string $name Name of annotation.
- * @param string $value Value of annotation.
- * @param int $limit Maximum number of results to return.
- * @param int $owner_guid Owner.
- * @param int $group_guid Group container. Currently this is only supported if $entity_type == 'object'
- * @param boolean $asc Whether to list in ascending or descending order (default: desc)
- * @param boolean $fullview Whether to display the entities in full
- * @param boolean $viewtypetoggle Determines whether or not the 'gallery' view can be displayed (default: no)
- * @return string Formatted entity list
- */
-function list_entities_from_annotations($entity_type = "", $entity_subtype = "", $name = "", $value = "", $limit = 10, $owner_guid = 0, $group_guid = 0, $asc = false, $fullview = true, $viewtypetoggle = false) {
- elgg_deprecated_notice('list_entities_from_annotations is deprecated by elgg_list_entities_from_annotations', 1.8);
-
- if ($entity_type) {
- $options['types'] = $entity_type;
- }
-
- if ($entity_subtype) {
- $options['subtypes'] = $entity_subtype;
- }
-
- if ($name) {
- $options['annotation_names'] = $name;
- }
-
- if ($value) {
- $options['annotation_values'] = $value;
- }
-
- if ($limit) {
- $options['limit'] = $limit;
- }
-
- if ($owner_guid) {
- $options['annotation_owner_guid'] = $owner_guid;
- }
-
- if ($group_guid) {
- $options['container_guid'] = $group_guid;
- }
-
- if ($asc) {
- $options['order_by'] = 'maxtime desc';
- }
-
- if ($offset = sanitise_int(get_input('offset', null))) {
- $options['offset'] = $offset;
- }
-
- $options['full_view'] = $fullview;
- $options['view_type_toggle'] = $viewtypetoggle;
- $options['pagination'] = $pagination;
-
- return elgg_list_entities_from_annotations($options);
+ return elgg_get_entities_from_metadata($options);
}
/**
* Returns a viewable list of entities from annotations.
*
- * @param array $options Any elgg_get_entity_from_annotation() options plus:
- *
- * offset => INT Start this many from the first result
- *
- * limit => INT Limit results to this
- *
- * full_view => BOOL Display full view entities
+ * @param array $options Options array
*
- * view_type_toggle => BOOL Display gallery / list switch
+ * @see elgg_get_entities_from_annotations()
+ * @see elgg_list_entities()
*
- * pagination => BOOL Display pagination links
- *
- * @return str
+ * @return string
*/
function elgg_list_entities_from_annotations($options = array()) {
- $defaults = array(
- 'offset' => (int) max(get_input('offset', 0), 0),
- 'limit' => (int) max(get_input('limit', 10), 0),
- 'full_view' => TRUE,
- 'view_type_toggle' => FALSE,
- 'pagination' => TRUE
- );
- $options = array_merge($defaults, $options);
-
- $count = elgg_get_entities_from_annotations(array_merge(array('count' => TRUE), $options));
- $entities = elgg_get_entities_from_annotations($options);
-
- return elgg_view_entity_list($entities, $count, $options['offset'],
- $options['limit'], $options['full_view'], $options['view_type_toggle'], $options['pagination']);
-}
-
-/**
- * Returns a human-readable list of annotations on a particular entity.
- *
- * @param int $entity_guid The entity GUID
- * @param string $name The name of the kind of annotation
- * @param int $limit The number of annotations to display at once
- * @param true|false $asc Whether or not the annotations are displayed in ascending order. (Default: true)
- * @return string HTML (etc) version of the annotation list
- */
-function list_annotations($entity_guid, $name = "", $limit = 25, $asc = true) {
- if ($asc) {
- $asc = "asc";
- } else {
- $asc = "desc";
- }
- $count = count_annotations($entity_guid, "", "", $name);
- $offset = (int) get_input("annoff",0);
- $annotations = get_annotations($entity_guid, "", "", $name, "", "", $limit, $offset, $asc);
-
- return elgg_view_annotation_list($annotations, $count, $offset, $limit);
-}
-
-/**
- * Return the sum of a given integer annotation.
- *
- * @param $entity_guid int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- */
-function get_annotations_sum($entity_guid, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0) {
- return __get_annotations_calculate_x("sum", $entity_guid, $entity_type, $entity_subtype, $name, $value, $value_type, $owner_guid);
-}
-
-/**
- * Return the max of a given integer annotation.
- *
- * @param $entity_guid int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- */
-function get_annotations_max($entity_guid, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0) {
- return __get_annotations_calculate_x("max", $entity_guid, $entity_type, $entity_subtype, $name, $value, $value_type, $owner_guid);
-}
-
-/**
- * Return the minumum of a given integer annotation.
- *
- * @param $entity_guid int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- */
-function get_annotations_min($entity_guid, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0) {
- return __get_annotations_calculate_x("min", $entity_guid, $entity_type, $entity_subtype, $name, $value, $value_type, $owner_guid);
-}
-
-/**
- * Return the average of a given integer annotation.
- *
- * @param $entity_guid int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- */
-function get_annotations_avg($entity_guid, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0) {
- return __get_annotations_calculate_x("avg", $entity_guid, $entity_type, $entity_subtype, $name, $value, $value_type, $owner_guid);
-}
-
-/**
- * Count the number of annotations based on search parameters
- *
- * @param int $entity_guid
- * @param string $entity_type
- * @param string $entity_subtype
- * @param string $name
- */
-function count_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0, $timelower = 0, $timeupper = 0) {
- return __get_annotations_calculate_x("count", $entity_guid, $entity_type, $entity_subtype, $name, $value, $value_type, $owner_guid, $timelower, $timeupper);
+ return elgg_list_entities($options, 'elgg_get_entities_from_annotations');
}
/**
- * Perform a mathmatical calculation on integer annotations.
- *
- * @param $sum string
- * @param $entity_id int
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
+ * Get entities ordered by a mathematical calculation on annotation values
+ *
+ * @param array $options An options array:
+ * 'calculation' => The calculation to use. Must be a valid MySQL function.
+ * Defaults to sum. Result selected as 'annotation_calculation'.
+ * Don't confuse this "calculation" option with the
+ * "annotation_calculation" option to elgg_get_annotations().
+ * This "calculation" option is applied to each entity's set of
+ * annotations and is selected as annotation_calculation for that row.
+ * See the docs for elgg_get_annotations() for proper use of the
+ * "annotation_calculation" option.
+ * 'order_by' => The order for the sorting. Defaults to 'annotation_calculation desc'.
+ * 'annotation_names' => The names of annotations on the entity.
+ * 'annotation_values' => The values of annotations on the entity.
+ *
+ * 'metadata_names' => The name of metadata on the entity.
+ * 'metadata_values' => The value of metadata on the entitiy.
+ *
+ * @return mixed If count, int. If not count, array. false on errors.
*/
-function __get_annotations_calculate_x($sum = "avg", $entity_guid, $entity_type = "", $entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0, $timelower = 0, $timeupper = 0) {
- global $CONFIG;
-
- $sum = sanitise_string($sum);
- $entity_guid = (int)$entity_guid;
- $entity_type = sanitise_string($entity_type);
- $timeupper = (int)$timeupper;
- $timelower = (int)$timelower;
-
- if ($entity_subtype) {
- if (!$entity_subtype = get_subtype_id($entity_type, $entity_subtype)) {
- // requesting a non-existing subtype: return false
- return FALSE;
- }
- }
-
- if ($name != '' AND !$name = get_metastring_id($name)) {
- return 0;
- }
-
- if ($value != '' AND !$value = get_metastring_id($value)) {
- return 0;
- }
- $value_type = sanitise_string($value_type);
- $owner_guid = (int)$owner_guid;
-
- // if (empty($name)) return 0;
-
- $where = array();
-
- if ($entity_guid) {
- $where[] = "e.guid=$entity_guid";
- }
-
- if ($entity_type!="") {
- $where[] = "e.type='$entity_type'";
- }
-
- if ($entity_subtype) {
- $where[] = "e.subtype=$entity_subtype";
- }
-
- if ($name!="") {
- $where[] = "a.name_id='$name'";
- }
-
- if ($value!="") {
- $where[] = "a.value_id='$value'";
- }
-
- if ($value_type!="") {
- $where[] = "a.value_type='$value_type'";
- }
-
- if ($owner_guid) {
- $where[] = "a.owner_guid='$owner_guid'";
- }
-
- if ($timelower) {
- $where[] = "a.time_created >= {$timelower}";
- }
-
- if ($timeupper) {
- $where[] = "a.time_created <= {$timeupper}";
- }
-
- if ($sum != "count") {
- $where[] = "a.value_type='integer'"; // Limit on integer types
- }
-
- $query = "SELECT $sum(ms.string) as sum
- FROM {$CONFIG->dbprefix}annotations a
- JOIN {$CONFIG->dbprefix}entities e on a.entity_guid = e.guid
- JOIN {$CONFIG->dbprefix}metastrings ms on a.value_id=ms.id WHERE ";
-
- foreach ($where as $w) {
- $query .= " $w and ";
- }
-
- $query .= get_access_sql_suffix("a"); // now add access
- $query .= ' and ' . get_access_sql_suffix("e"); // now add access
-
- $row = get_data_row($query);
- if ($row) {
- return $row->sum;
- }
-
- return false;
-}
-
-/**
- * Get entities ordered by a mathematical calculation
- *
- * @param $sum string
- * @param $entity_type string
- * @param $entity_subtype string
- * @param $name string
- * @param $mdname string
- * @param $mdvalue string
- * @param $limit int
- * @param string $orderdir Default: asc - the sort order
- * @return unknown
- */
-function __get_entities_from_annotations_calculate_x($sum = "sum", $entity_type = "", $entity_subtype = "", $name = "", $mdname = '', $mdvalue = '', $owner_guid = 0, $limit = 10, $offset = 0, $orderdir = 'desc', $count = false) {
- global $CONFIG;
-
- $sum = sanitise_string($sum);
- $entity_type = sanitise_string($entity_type);
-
- if ($entity_subtype) {
- if (!$entity_subtype = get_subtype_id($entity_type, $entity_subtype)) {
- // requesting a non-existing subtype: return false
- return FALSE;
- }
- }
-
- $name = get_metastring_id($name);
- $limit = (int) $limit;
- $offset = (int) $offset;
- $owner_guid = (int) $owner_guid;
- if (!empty($mdname) && !empty($mdvalue)) {
- $meta_n = get_metastring_id($mdname);
- $meta_v = get_metastring_id($mdvalue);
- }
-
- if (empty($name)) {
- return 0;
- }
-
- $where = array();
-
- if ($entity_type!="") {
- $where[] = "e.type='$entity_type'";
- }
-
- if ($owner_guid > 0) {
- $where[] = "e.container_guid = $owner_guid";
- }
-
- if ($entity_subtype) {
- $where[] = "e.subtype=$entity_subtype";
- }
+function elgg_get_entities_from_annotation_calculation($options) {
+ $db_prefix = elgg_get_config('dbprefix');
+ $defaults = array(
+ 'calculation' => 'sum',
+ 'order_by' => 'annotation_calculation desc'
+ );
- if ($name!="") {
- $where[] = "a.name_id='$name'";
- }
+ $options = array_merge($defaults, $options);
- if (!empty($mdname) && !empty($mdvalue)) {
- if ($mdname!="") {
- $where[] = "m.name_id='$meta_n'";
- }
+ $function = sanitize_string(elgg_extract('calculation', $options, 'sum', false));
- if ($mdvalue!="") {
- $where[] = "m.value_id='$meta_v'";
- }
- }
+ // you must cast this as an int or it sorts wrong.
+ $options['selects'][] = 'e.*';
+ $options['selects'][] = "$function(cast(a_msv.string as signed)) as annotation_calculation";
- if ($sum != "count") {
- // Limit on integer types
- $where[] = "a.value_type='integer'";
- }
+ // need our own join to get the values because the lower level functions don't
+ // add all the joins if it's a different callback.
+ $options['joins'][] = "JOIN {$db_prefix}metastrings a_msv ON n_table.value_id = a_msv.id";
- if (!$count) {
- $query = "SELECT distinct e.*, $sum(ms.string) as sum ";
- } else {
- $query = "SELECT count(distinct e.guid) as num, $sum(ms.string) as sum ";
- }
- $query .= " from {$CONFIG->dbprefix}entities e JOIN {$CONFIG->dbprefix}annotations a on a.entity_guid = e.guid JOIN {$CONFIG->dbprefix}metastrings ms on a.value_id=ms.id ";
+ // don't need access control because it's taken care of by elgg_get_annotations.
+ $options['group_by'] = 'n_table.entity_guid';
- if (!empty($mdname) && !empty($mdvalue)) {
- $query .= " JOIN {$CONFIG->dbprefix}metadata m on m.entity_guid = e.guid ";
- }
+ $options['callback'] = 'entity_row_to_elggstar';
- $query .= " WHERE ";
- foreach ($where as $w) {
- $query .= " $w and ";
- }
+ // see #4393
+ // @todo remove after the 'count' shortcut is removed from elgg_get_annotations()
+ $options['__egefac'] = true;
- $query .= get_access_sql_suffix("a"); // now add access
- $query .= ' and ' . get_access_sql_suffix("e"); // now add access
- if (!$count) {
- $query .= ' group by e.guid';
- }
-
- if (!$count) {
- $query .= ' order by sum ' . $orderdir;
- $query .= ' limit ' . $offset . ' , ' . $limit;
- return get_data($query, "entity_row_to_elggstar");
- } else {
- if ($row = get_data_row($query)) {
- return $row->num;
- }
- }
- return false;
+ return elgg_get_annotations($options);
}
/**
- * Returns entities ordered by the sum of an annotation
+ * List entities from an annotation calculation.
*
- * @param unknown_type $entity_type
- * @param unknown_type $entity_subtype
- * @param unknown_type $name
- * @param string $mdname
- * @param string $mdvalue
- * @param unknown_type $owner_guid
- * @param int $limit
- * @param int $offset
- * @param true|false $count
- * @return unknown
- */
-function get_entities_from_annotation_count($entity_type = "", $entity_subtype = "", $name = "", $mdname = '', $mdvalue = '', $owner_guid = 0, $limit = 10, $offset = 0, $orderdir = 'desc', $count = false) {
- return __get_entities_from_annotations_calculate_x('sum',$entity_type,$entity_subtype,$name,$mdname, $mdvalue, $owner_guid,$limit, $offset, $orderdir, $count);
-}
-
-/**
- * Lists entities by the totals of a particular kind of annotation
+ * @see elgg_get_entities_from_annotation_calculation()
*
- * @param string $entity_type Type of entity.
- * @param string $entity_subtype Subtype of entity.
- * @param string $name Name of annotation.
- * @param int $limit Maximum number of results to return.
- * @param int $owner_guid Owner.
- * @param int $group_guid Group container. Currently this is only supported if $entity_type == 'object'
- * @param boolean $asc Whether to list in ascending or descending order (default: desc)
- * @param boolean $fullview Whether to display the entities in full
- * @param boolean $viewtypetoggle Determines whether or not the 'gallery' view can be displayed (default: no)
- * @return string Formatted entity list
- */
-function list_entities_from_annotation_count($entity_type = "", $entity_subtype = "", $name = "", $limit = 10, $owner_guid = 0, $group_guid = 0, $asc = false, $fullview = true, $viewtypetoggle = false, $pagination = true, $orderdir = 'desc') {
- if ($asc) {
- $asc = "asc";
- } else {
- $asc = "desc";
- }
-
- $offset = (int) get_input("offset",0);
- $count = get_entities_from_annotation_count($entity_type, $entity_subtype, $name, '', '', $owner_guid, $limit, $offset, $orderdir, true);
- $entities = get_entities_from_annotation_count($entity_type, $entity_subtype, $name, '', '', $owner_guid, $limit, $offset, $orderdir, false);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination);
-}
-
-/**
- * Lists entities by the totals of a particular kind of annotation AND the value of a piece of metadata
+ * @param array $options An options array.
*
- * @param string $entity_type Type of entity.
- * @param string $entity_subtype Subtype of entity.
- * @param string $name Name of annotation.
- * @param string $mdname Metadata name
- * @param string $mdvalue Metadata value
- * @param int $limit Maximum number of results to return.
- * @param int $owner_guid Owner.
- * @param int $group_guid Group container. Currently this is only supported if $entity_type == 'object'
- * @param boolean $asc Whether to list in ascending or descending order (default: desc)
- * @param boolean $fullview Whether to display the entities in full
- * @param boolean $viewtypetoggle Determines whether or not the 'gallery' view can be displayed (default: no)
- * @return string Formatted entity list
+ * @return string
*/
-function list_entities_from_annotation_count_by_metadata($entity_type = "", $entity_subtype = "", $name = "", $mdname = '', $mdvalue = '', $limit = 10, $owner_guid = 0, $group_guid = 0, $asc = false, $fullview = true, $viewtypetoggle = false, $pagination = true, $orderdir = 'desc') {
- if ($asc) {
- $asc = "asc";
- } else {
- $asc = "desc";
- }
-
- $offset = (int) get_input("offset",0);
- $count = get_entities_from_annotation_count($entity_type, $entity_subtype, $name, $mdname, $mdvalue, $owner_guid, $limit, $offset, $orderdir, true);
- $entities = get_entities_from_annotation_count($entity_type, $entity_subtype, $name, $mdname, $mdvalue, $owner_guid, $limit, $offset, $orderdir, false);
+function elgg_list_entities_from_annotation_calculation($options) {
+ $defaults = array(
+ 'calculation' => 'sum',
+ 'order_by' => 'annotation_calculation desc'
+ );
+ $options = array_merge($defaults, $options);
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination);
+ return elgg_list_entities($options, 'elgg_get_entities_from_annotation_calculation');
}
/**
- * Delete a given annotation.
+ * Export the annotations for the specified entity
*
- * @param $id int The id
- */
-function delete_annotation($id) {
- global $CONFIG;
-
- $id = (int)$id;
-
- $access = get_access_sql_suffix();
- $annotation = get_annotation($id);
-
- if (trigger_elgg_event('delete', 'annotation', $annotation)) {
- remove_from_river_by_annotation($id);
- return delete_data("DELETE from {$CONFIG->dbprefix}annotations where id=$id and $access");
- }
-
- return FALSE;
-}
-
-/**
- * Clear all the annotations for a given entity, assuming you have access to that metadata.
+ * @param string $hook 'export'
+ * @param string $type 'all'
+ * @param mixed $returnvalue Default return value
+ * @param mixed $params Parameters determining what annotations to export
*
- * @param int $guid
- * @return number of annotations deleted or false if an error
- */
-function clear_annotations($guid, $name = "") {
- global $CONFIG;
-
- $guid = (int)$guid;
-
- if (!empty($name)) {
- $name = get_metastring_id($name);
- if ($name === false) {
- // name doesn't exist so 0 rows were deleted
- return 0;
- }
- }
-
- $entity_guid = (int) $guid;
- if ($entity = get_entity($entity_guid)) {
- if ($entity->canEdit()) {
- $where = array();
-
- if ($name != "") {
- $where[] = " name_id='$name'";
- }
-
- $query = "DELETE from {$CONFIG->dbprefix}annotations where entity_guid=$guid ";
- foreach ($where as $w) {
- $query .= " and $w";
- }
-
- return delete_data($query);
- }
- }
-
- return FALSE;
-}
-
-/**
- * Clear all annotations belonging to a given owner_guid
+ * @elgg_plugin_hook export all
*
- * @param int $owner_guid The owner
- */
-function clear_annotations_by_owner($owner_guid) {
- global $CONFIG;
-
- $owner_guid = (int)$owner_guid;
-
- $annotations = get_data("SELECT id from {$CONFIG->dbprefix}annotations WHERE owner_guid=$owner_guid");
- $deleted = 0;
-
- if (!$annotations) {
- return 0;
- }
-
- foreach ($annotations as $id) {
- // Is this the best way?
- if (delete_annotation($id->id)) {
- $deleted++;
- }
- }
-
- return $deleted;
-}
-
-/**
- * Handler called by trigger_plugin_hook on the "export" event.
+ * @return array
+ * @throws InvalidParameterException
+ * @access private
*/
-function export_annotation_plugin_hook($hook, $entity_type, $returnvalue, $params) {
+function export_annotation_plugin_hook($hook, $type, $returnvalue, $params) {
// Sanity check values
if ((!is_array($params)) && (!isset($params['guid']))) {
throw new InvalidParameterException(elgg_echo('InvalidParameterException:GUIDNotForExport'));
@@ -1106,9 +495,12 @@ function export_annotation_plugin_hook($hook, $entity_type, $returnvalue, $param
}
$guid = (int)$params['guid'];
- $name = $params['name'];
+ $options = array('guid' => $guid, 'limit' => 0);
+ if (isset($params['name'])) {
+ $options['annotation_name'] = $params['name'];
+ }
- $result = get_annotations($guid);
+ $result = elgg_get_annotations($options);
if ($result) {
foreach ($result as $r) {
@@ -1120,14 +512,17 @@ function export_annotation_plugin_hook($hook, $entity_type, $returnvalue, $param
}
/**
- * Get the URL for this item of metadata, by default this links to the export handler in the current view.
+ * Get the URL for this item of metadata, by default this links to the
+ * export handler in the current view.
+ *
+ * @param int $id Annotation id
*
- * @param int $id
+ * @return mixed
*/
function get_annotation_url($id) {
$id = (int)$id;
- if ($extender = get_annotation($id)) {
+ if ($extender = elgg_get_annotation_from_id($id)) {
return get_extender_url($extender);
}
return false;
@@ -1136,28 +531,30 @@ function get_annotation_url($id) {
/**
* Check to see if a user has already created an annotation on an object
*
- * @param int $entity_guid
- * @param string $annotation_type
- * @param int $owner_guid Defaults to logged in user.
+ * @param int $entity_guid Entity guid
+ * @param string $annotation_type Type of annotation
+ * @param int $owner_guid Defaults to logged in user.
*
- * @return true | false
+ * @return bool
+ * @since 1.8.0
*/
function elgg_annotation_exists($entity_guid, $annotation_type, $owner_guid = NULL) {
global $CONFIG;
- if (!$owner_guid && !($owner_guid = get_loggedin_userid())) {
+ if (!$owner_guid && !($owner_guid = elgg_get_logged_in_user_guid())) {
return FALSE;
}
- $entity_guid = (int)$entity_guid;
- $annotation_type = sanitise_string($annotation_type);
+ $entity_guid = sanitize_int($entity_guid);
+ $owner_guid = sanitize_int($owner_guid);
+ $annotation_type = sanitize_string($annotation_type);
- $sql = "select a.id" .
- " FROM {$CONFIG->dbprefix}annotations a, {$CONFIG->dbprefix}metastrings m " .
- " WHERE a.owner_guid={$owner_guid} AND a.entity_guid={$entity_guid} " .
- " AND a.name_id=m.id AND m.string='{$annotation_type}'";
+ $sql = "SELECT a.id FROM {$CONFIG->dbprefix}annotations a" .
+ " JOIN {$CONFIG->dbprefix}metastrings m ON a.name_id = m.id" .
+ " WHERE a.owner_guid = $owner_guid AND a.entity_guid = $entity_guid" .
+ " AND m.string = '$annotation_type'";
- if ($check_annotation = get_data_row($sql)) {
+ if (get_data_row($sql)) {
return TRUE;
}
@@ -1165,14 +562,57 @@ function elgg_annotation_exists($entity_guid, $annotation_type, $owner_guid = NU
}
/**
+ * Return the URL for a comment
+ *
+ * @param ElggAnnotation $comment The comment object
+ * @return string
+ * @access private
+ */
+function elgg_comment_url_handler(ElggAnnotation $comment) {
+ $entity = $comment->getEntity();
+ if ($entity) {
+ return $entity->getURL() . '#item-annotation-' . $comment->id;
+ }
+ return "";
+}
+
+/**
* Register an annotation url handler.
*
- * @param string $function_name The function.
* @param string $extender_name The name, default 'all'.
+ * @param string $function_name The function.
+ *
+ * @return string
*/
-function register_annotation_url_handler($function_name, $extender_name = "all") {
- return register_extender_url_handler($function_name, 'annotation', $extender_name);
+function elgg_register_annotation_url_handler($extender_name = "all", $function_name) {
+ return elgg_register_extender_url_handler('annotation', $extender_name, $function_name);
+}
+
+/**
+ * Register annotation unit tests
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $value
+ * @param array $params
+ * @return array
+ * @access private
+ */
+function annotations_test($hook, $type, $value, $params) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/annotations.php';
+ return $value;
+}
+
+/**
+ * Initialize the annotation library
+ * @access private
+ */
+function elgg_annotations_init() {
+ elgg_register_annotation_url_handler('generic_comment', 'elgg_comment_url_handler');
+
+ elgg_register_plugin_hook_handler("export", "all", "export_annotation_plugin_hook", 2);
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'annotations_test');
}
-/** Register the hook */
-register_plugin_hook("export", "all", "export_annotation_plugin_hook", 2);
+elgg_register_event_handler('init', 'system', 'elgg_annotations_init');
diff --git a/engine/lib/cache.php b/engine/lib/cache.php
index df7b1e525..3116c1a9b 100644
--- a/engine/lib/cache.php
+++ b/engine/lib/cache.php
@@ -3,435 +3,451 @@
* Elgg cache
* Cache file interface for caching data.
*
- * @package Elgg
- * @subpackage API
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Cache
*/
+/* Filepath Cache */
+
/**
- * ElggCache The elgg cache superclass.
- * This defines the interface for a cache (wherever that cache is stored).
+ * Returns an ElggCache object suitable for caching system information
+ *
+ * @todo Can this be done in a cleaner way?
+ * @todo Swap to memcache etc?
*
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage API
+ * @return ElggFileCache
*/
-abstract class ElggCache implements
- // Override for array access
- ArrayAccess {
- /**
- * Variables for the cache object.
- *
- * @var array
- */
- private $variables;
+function elgg_get_system_cache() {
+ global $CONFIG;
/**
- * Set the constructor.
+ * A default filestore cache using the dataroot.
*/
- function __construct() {
- $this->variables = array();
+ static $FILE_PATH_CACHE;
+
+ if (!$FILE_PATH_CACHE) {
+ $FILE_PATH_CACHE = new ElggFileCache($CONFIG->dataroot . 'system_cache/');
}
- /**
- * Set a cache variable.
- *
- * @param string $variable
- * @param string $value
- */
- public function set_variable($variable, $value) {
- if (!is_array($this->variables)) {
- $this->variables = array();
- }
+ return $FILE_PATH_CACHE;
+}
- $this->variables[$variable] = $value;
- }
+/**
+ * Reset the system cache by deleting the caches
+ *
+ * @return void
+ */
+function elgg_reset_system_cache() {
+ $cache = elgg_get_system_cache();
+ $cache->clear();
+}
- /**
- * Get variables for this cache.
- *
- * @param string $variable
- * @return mixed The variable or null;
- */
- public function get_variable($variable) {
- if (isset($this->variables[$variable])) {
- return $this->variables[$variable];
- }
+/**
+ * Saves a system cache.
+ *
+ * @param string $type The type or identifier of the cache
+ * @param string $data The data to be saved
+ * @return bool
+ */
+function elgg_save_system_cache($type, $data) {
+ global $CONFIG;
- return null;
+ if ($CONFIG->system_cache_enabled) {
+ $cache = elgg_get_system_cache();
+ return $cache->save($type, $data);
}
- /**
- * Class member get overloading, returning key using $this->load defaults.
- *
- * @param string $key
- * @return mixed
- */
- function __get($key) {
- return $this->load($key);
- }
+ return false;
+}
- /**
- * Class member set overloading, setting a key using $this->save defaults.
- *
- * @param string $key
- * @param mixed $value
- * @return mixed
- */
- function __set($key, $value) {
- return $this->save($key, $value);
- }
+/**
+ * Retrieve the contents of a system cache.
+ *
+ * @param string $type The type of cache to load
+ * @return string
+ */
+function elgg_load_system_cache($type) {
+ global $CONFIG;
- /**
- * Supporting isset, using $this->load() with default values.
- *
- * @param string $key The name of the attribute or metadata.
- * @return bool
- */
- function __isset($key) {
- return (bool)$this->load($key);
- }
+ if ($CONFIG->system_cache_enabled) {
+ $cache = elgg_get_system_cache();
+ $cached_data = $cache->load($type);
- /**
- * Supporting unsetting of magic attributes.
- *
- * @param string $key The name of the attribute or metadata.
- */
- function __unset($key) {
- return $this->delete($key);
+ if ($cached_data) {
+ return $cached_data;
+ }
}
- /**
- * Save data in a cache.
- *
- * @param string $key
- * @param string $data
- * @return bool
- */
- abstract public function save($key, $data);
+ return NULL;
+}
- /**
- * Load data from the cache using a given key.
- *
- * @param string $key
- * @param int $offset
- * @param int $limit
- * @return mixed The stored data or false.
- */
- abstract public function load($key, $offset = 0, $limit = null);
+/**
+ * Enables the system disk cache.
+ *
+ * Uses the 'system_cache_enabled' datalist with a boolean value.
+ * Resets the system cache.
+ *
+ * @return void
+ */
+function elgg_enable_system_cache() {
+ global $CONFIG;
- /**
- * Invalidate a key
- *
- * @param string $key
- * @return bool
- */
- abstract public function delete($key);
+ datalist_set('system_cache_enabled', 1);
+ $CONFIG->system_cache_enabled = 1;
+ elgg_reset_system_cache();
+}
- /**
- * Clear out all the contents of the cache.
- *
- */
- abstract public function clear();
+/**
+ * Disables the system disk cache.
+ *
+ * Uses the 'system_cache_enabled' datalist with a boolean value.
+ * Resets the system cache.
+ *
+ * @return void
+ */
+function elgg_disable_system_cache() {
+ global $CONFIG;
- /**
- * Add a key only if it doesn't already exist.
- * Implemented simply here, if you extend this class and your caching engine provides a better way then
- * override this accordingly.
- *
- * @param string $key
- * @param string $data
- * @return bool
- */
- public function add($key, $data) {
- if (!isset($this[$key])) {
- return $this->save($key, $data);
- }
+ datalist_set('system_cache_enabled', 0);
+ $CONFIG->system_cache_enabled = 0;
+ elgg_reset_system_cache();
+}
- return false;
- }
+/** @todo deprecate in Elgg 1.9 **/
- // ARRAY ACCESS INTERFACE //////////////////////////////////////////////////////////
- function offsetSet($key, $value) {
- $this->save($key, $value);
- }
+/**
+ * @access private
+ */
+function elgg_get_filepath_cache() {
+ return elgg_get_system_cache();
+}
+/**
+ * @access private
+ */
+function elgg_filepath_cache_reset() {
+ elgg_reset_system_cache();
+}
+/**
+ * @access private
+ */
+function elgg_filepath_cache_save($type, $data) {
+ return elgg_save_system_cache($type, $data);
+}
+/**
+ * @access private
+ */
+function elgg_filepath_cache_load($type) {
+ return elgg_load_system_cache($type);
+}
+/**
+ * @access private
+ */
+function elgg_enable_filepath_cache() {
+ elgg_enable_system_cache();
+}
+/**
+ * @access private
+ */
+function elgg_disable_filepath_cache() {
+ elgg_disable_system_cache();
+}
- function offsetGet($key) {
- return $this->load($key);
- }
+/* Simplecache */
- function offsetUnset($key) {
- if ( isset($this->key) ) {
- unset($this->key);
- }
+/**
+ * Registers a view to simple cache.
+ *
+ * Simple cache is a caching mechanism that saves the output of
+ * views and its extensions into a file. If the view is called
+ * by the {@link simplecache/view.php} file, the Elgg framework will
+ * not be loaded and the contents of the view will returned
+ * from file.
+ *
+ * @warning Simple cached views must take no parameters and return
+ * the same content no matter who is logged in.
+ *
+ * @example
+ * $blog_js = elgg_get_simplecache_url('js', 'blog/save_draft');
+ * elgg_register_simplecache_view('js/blog/save_draft');
+ * elgg_register_js('elgg.blog', $blog_js);
+ * elgg_load_js('elgg.blog');
+ *
+ * @param string $viewname View name
+ *
+ * @return void
+ * @link http://docs.elgg.org/Views/Simplecache
+ * @see elgg_regenerate_simplecache()
+ * @since 1.8.0
+ */
+function elgg_register_simplecache_view($viewname) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->views)) {
+ $CONFIG->views = new stdClass;
}
- function offsetExists($offset) {
- return isset($this->$offset);
+ if (!isset($CONFIG->views->simplecache)) {
+ $CONFIG->views->simplecache = array();
}
+
+ $CONFIG->views->simplecache[] = $viewname;
}
/**
- * Shared memory cache description.
- * Extends ElggCache with functions useful to shared memory style caches (static variables, memcache etc)
+ * Get the URL for the cached file
+ *
+ * @warning You must register the view with elgg_register_simplecache_view()
+ * for caching to work. See elgg_register_simplecache_view() for a full example.
+ *
+ * @param string $type The file type: css or js
+ * @param string $view The view name
+ * @return string
+ * @since 1.8.0
*/
-abstract class ElggSharedMemoryCache extends ElggCache {
- /**
- * Namespace variable used to keep various bits of the cache
- * separate.
- *
- * @var string
- */
- private $namespace;
-
- /**
- * Set the namespace of this cache.
- * This is useful for cache types (like memcache or static variables) where there is one large
- * flat area of memory shared across all instances of the cache.
- *
- * @param string $namespace
- */
- public function setNamespace($namespace = "default") {
- $this->namespace = $namespace;
- }
-
- /**
- * Get the namespace currently defined.
- *
- * @return string
- */
- public function getNamespace() {
- return $this->namespace;
+function elgg_get_simplecache_url($type, $view) {
+ global $CONFIG;
+ $lastcache = (int)$CONFIG->lastcache;
+ $viewtype = elgg_get_viewtype();
+ elgg_register_simplecache_view("$type/$view");// see #5302
+ if (elgg_is_simplecache_enabled()) {
+ $url = elgg_get_site_url() . "cache/$type/$viewtype/$view.$lastcache.$type";
+ } else {
+ $url = elgg_get_site_url() . "$type/$view.$lastcache.$type";
+ $elements = array("view" => $viewtype);
+ $url = elgg_http_add_url_query_elements($url, $elements);
}
+
+ return $url;
}
/**
- * ElggStaticVariableCache
- * Dummy cache which stores values in a static array. Using this makes future replacements to other caching back
- * ends (eg memcache) much easier.
+ * Regenerates the simple cache.
+ *
+ * @warning This does not invalidate the cache, but actively rebuilds it.
+ *
+ * @param string $viewtype Optional viewtype to regenerate. Defaults to all valid viewtypes.
*
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage API
+ * @return void
+ * @see elgg_register_simplecache_view()
+ * @since 1.8.0
*/
-class ElggStaticVariableCache extends ElggSharedMemoryCache {
- /**
- * The cache.
- *
- * @var unknown_type
- */
- private static $__cache;
+function elgg_regenerate_simplecache($viewtype = NULL) {
+ global $CONFIG;
- /**
- * Create the variable cache.
- *
- * This function creates a variable cache in a static variable in memory, optionally with a given namespace (to avoid overlap).
- *
- * @param string $namespace The namespace for this cache to write to - note, namespaces of the same name are shared!
- */
- function __construct($namespace = 'default') {
- $this->setNamespace($namespace);
- $this->clear();
+ if (!isset($CONFIG->views->simplecache) || !is_array($CONFIG->views->simplecache)) {
+ return;
}
- public function save($key, $data) {
- $namespace = $this->getNamespace();
+ $lastcached = time();
- ElggStaticVariableCache::$__cache[$namespace][$key] = $data;
+ // @todo elgg_view() checks if the page set is done (isset($CONFIG->pagesetupdone)) and
+ // triggers an event if it's not. Calling elgg_view() here breaks submenus
+ // (at least) because the page setup hook is called before any
+ // contexts can be correctly set (since this is called before page_handler()).
+ // To avoid this, lie about $CONFIG->pagehandlerdone to force
+ // the trigger correctly when the first view is actually being output.
+ $CONFIG->pagesetupdone = TRUE;
- return true;
+ if (!file_exists($CONFIG->dataroot . 'views_simplecache')) {
+ mkdir($CONFIG->dataroot . 'views_simplecache');
}
- public function load($key, $offset = 0, $limit = null) {
- $namespace = $this->getNamespace();
+ if (isset($viewtype)) {
+ $viewtypes = array($viewtype);
+ } else {
+ $viewtypes = $CONFIG->view_types;
+ }
+
+ $original_viewtype = elgg_get_viewtype();
+
+ // disable error reporting so we don't cache problems
+ $old_debug = elgg_get_config('debug');
+ elgg_set_config('debug', null);
- if (isset(ElggStaticVariableCache::$__cache[$namespace][$key])) {
- return ElggStaticVariableCache::$__cache[$namespace][$key];
+ foreach ($viewtypes as $viewtype) {
+ elgg_set_viewtype($viewtype);
+ foreach ($CONFIG->views->simplecache as $view) {
+ $viewcontents = elgg_view($view);
+ $viewname = md5(elgg_get_viewtype() . $view);
+ if ($handle = fopen($CONFIG->dataroot . 'views_simplecache/' . $viewname, 'w')) {
+ fwrite($handle, $viewcontents);
+ fclose($handle);
+ }
}
- return false;
+ datalist_set("simplecache_lastupdate_$viewtype", $lastcached);
+ datalist_set("simplecache_lastcached_$viewtype", $lastcached);
}
- public function delete($key) {
- $namespace = $this->getNamespace();
+ elgg_set_config('debug', $old_debug);
+ elgg_set_viewtype($original_viewtype);
+
+ // needs to be set for links in html head
+ $CONFIG->lastcache = $lastcached;
- unset(ElggStaticVariableCache::$__cache[$namespace][$key]);
+ unset($CONFIG->pagesetupdone);
+}
+/**
+ * Is simple cache enabled
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_is_simplecache_enabled() {
+ if (elgg_get_config('simplecache_enabled')) {
return true;
}
- public function clear() {
- $namespace = $this->getNamespace();
+ return false;
+}
- if (!isset(ElggStaticVariableCache::$__cache)) {
- ElggStaticVariableCache::$__cache = array();
- }
+/**
+ * Enables the simple cache.
+ *
+ * @access private
+ * @see elgg_register_simplecache_view()
+ * @return void
+ * @since 1.8.0
+ */
+function elgg_enable_simplecache() {
+ global $CONFIG;
- ElggStaticVariableCache::$__cache[$namespace] = array();
- }
+ datalist_set('simplecache_enabled', 1);
+ $CONFIG->simplecache_enabled = 1;
+ elgg_regenerate_simplecache();
}
/**
- * ElggFileCache
- * Store cached data in a file store.
+ * Disables the simple cache.
+ *
+ * @warning Simplecache is also purged when disabled.
*
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage API
+ * @access private
+ * @see elgg_register_simplecache_view()
+ * @return void
+ * @since 1.8.0
*/
-class ElggFileCache extends ElggCache {
- /**
- * Set the Elgg cache.
- *
- * @param string $cache_path The cache path.
- * @param int $max_age Maximum age in seconds, 0 if no limit.
- * @param int $max_size Maximum size of cache in seconds, 0 if no limit.
- */
- function __construct($cache_path, $max_age = 0, $max_size = 0) {
- $this->set_variable("cache_path", $cache_path);
- $this->set_variable("max_age", $max_age);
- $this->set_variable("max_size", $max_size);
-
- if ($cache_path=="") {
- throw new ConfigurationException(elgg_echo('ConfigurationException:NoCachePath'));
+function elgg_disable_simplecache() {
+ global $CONFIG;
+ if ($CONFIG->simplecache_enabled) {
+ datalist_set('simplecache_enabled', 0);
+ $CONFIG->simplecache_enabled = 0;
+
+ // purge simple cache
+ if ($handle = opendir($CONFIG->dataroot . 'views_simplecache')) {
+ while (false !== ($file = readdir($handle))) {
+ if ($file != "." && $file != "..") {
+ unlink($CONFIG->dataroot . 'views_simplecache/' . $file);
+ }
+ }
+ closedir($handle);
}
}
+}
- /**
- * Create and return a handle to a file.
- *
- * @param string $filename
- * @param string $rw
- */
- protected function create_file($filename, $rw = "rb") {
- // Create a filename matrix
- $matrix = "";
- $depth = strlen($filename);
- if ($depth > 5) {
- $depth = 5;
- }
-
- // Create full path
- $path = $this->get_variable("cache_path") . $matrix;
- if (!is_dir($path)) {
- mkdir($path, 0700, true);
- }
-
- // Open the file
- if ((!file_exists($path . $filename)) && ($rw=="rb")) {
- return false;
- }
+/**
+ * Deletes all cached views in the simplecache and sets the lastcache and
+ * lastupdate time to 0 for every valid viewtype.
+ *
+ * @return bool
+ * @since 1.7.4
+ */
+function elgg_invalidate_simplecache() {
+ global $CONFIG;
- return fopen($path . $filename, $rw);
+ if (!isset($CONFIG->views->simplecache) || !is_array($CONFIG->views->simplecache)) {
+ return false;
}
- /**
- * Create a sanitised filename for the file.
- *
- * @param string $filename
- */
- protected function sanitise_filename($filename) {
- // TODO : Writeme
+ $handle = opendir($CONFIG->dataroot . 'views_simplecache');
- return $filename;
+ if (!$handle) {
+ return false;
}
- /**
- * Save a key
- *
- * @param string $key
- * @param string $data
- * @return boolean
- */
- public function save($key, $data) {
- $f = $this->create_file($this->sanitise_filename($key), "wb");
- if ($f) {
- $result = fwrite($f, $data);
- fclose($f);
-
- return $result;
+ // remove files.
+ $return = true;
+ while (false !== ($file = readdir($handle))) {
+ if ($file != "." && $file != "..") {
+ $return &= unlink($CONFIG->dataroot . 'views_simplecache/' . $file);
}
-
- return false;
}
+ closedir($handle);
- /**
- * Load a key
- *
- * @param string $key
- * @param int $offset
- * @param int $limit
- * @return string
- */
- public function load($key, $offset = 0, $limit = null) {
- $f = $this->create_file($this->sanitise_filename($key));
- if ($f) {
- //fseek($f, $offset);
- if (!$limit) {
- $limit = -1;
- }
- $data = stream_get_contents($f, $limit, $offset);
-
- fclose($f);
-
- return $data;
- }
+ // reset cache times
+ $viewtypes = $CONFIG->view_types;
+ if (!is_array($viewtypes)) {
return false;
}
- /**
- * Invalidate a given key.
- *
- * @param string $key
- * @return bool
- */
- public function delete($key) {
- $dir = $this->get_variable("cache_path");
-
- if (file_exists($dir.$key)) {
- return unlink($dir.$key);
- }
- return TRUE;
- }
-
- public function clear() {
- // TODO : writeme
+ foreach ($viewtypes as $viewtype) {
+ $return &= datalist_set("simplecache_lastupdate_$viewtype", 0);
+ $return &= datalist_set("simplecache_lastcached_$viewtype", 0);
}
- public function __destruct() {
- // TODO: Check size and age, clean up accordingly
- $size = 0;
- $dir = $this->get_variable("cache_path");
+ return $return;
+}
- // Short circuit if both size and age are unlimited
- if (($this->get_variable("max_age")==0) && ($this->get_variable("max_size")==0)) {
- return;
- }
+/**
+ * @see elgg_reset_system_cache()
+ * @access private
+ */
+function _elgg_load_cache() {
+ global $CONFIG;
- $exclude = array(".","..");
+ $CONFIG->system_cache_loaded = false;
- $files = scandir($dir);
- if (!$files) {
- throw new IOException(sprintf(elgg_echo('IOException:NotDirectory'), $dir));
- }
+ $CONFIG->views = new stdClass();
+ $data = elgg_load_system_cache('view_locations');
+ if (!is_string($data)) {
+ return;
+ }
+ $CONFIG->views->locations = unserialize($data);
+
+ $data = elgg_load_system_cache('view_types');
+ if (!is_string($data)) {
+ return;
+ }
+ $CONFIG->view_types = unserialize($data);
- // Perform cleanup
- foreach ($files as $f) {
- if (!in_array($f, $exclude)) {
- $stat = stat($dir.$f);
+ $CONFIG->system_cache_loaded = true;
+}
- // Add size
- $size .= $stat['size'];
+/**
+ * @access private
+ */
+function _elgg_cache_init() {
+ global $CONFIG;
+
+ $viewtype = elgg_get_viewtype();
+
+ // Regenerate the simple cache if expired.
+ // Don't do it on upgrade because upgrade does it itself.
+ // @todo - move into function and perhaps run off init system event
+ if (!defined('UPGRADING')) {
+ $lastupdate = datalist_get("simplecache_lastupdate_$viewtype");
+ $lastcached = datalist_get("simplecache_lastcached_$viewtype");
+ if ($lastupdate == 0 || $lastcached < $lastupdate) {
+ elgg_regenerate_simplecache($viewtype);
+ $lastcached = datalist_get("simplecache_lastcached_$viewtype");
+ }
+ $CONFIG->lastcache = $lastcached;
+ }
- // Is this older than my maximum date?
- if (($this->get_variable("max_age")>0) && (time() - $stat['mtime'] > $this->get_variable("max_age"))) {
- unlink($dir.$f);
- }
+ // cache system data if enabled and not loaded
+ if ($CONFIG->system_cache_enabled && !$CONFIG->system_cache_loaded) {
+ elgg_save_system_cache('view_locations', serialize($CONFIG->views->locations));
+ elgg_save_system_cache('view_types', serialize($CONFIG->view_types));
+ }
- // TODO: Size
- }
+ if ($CONFIG->system_cache_enabled && !$CONFIG->i18n_loaded_from_cache) {
+ reload_all_translations();
+ foreach ($CONFIG->translations as $lang => $map) {
+ elgg_save_system_cache("$lang.lang", serialize($map));
}
}
}
+
+elgg_register_event_handler('ready', 'system', '_elgg_cache_init');
diff --git a/engine/lib/calendar.php b/engine/lib/calendar.php
index a9d6dfadf..e6f95934c 100644
--- a/engine/lib/calendar.php
+++ b/engine/lib/calendar.php
@@ -2,45 +2,21 @@
/**
* Elgg calendar / entity / event functions.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
- */
-
-/**
- * Calendar interface for events.
+ * @package Elgg.Core
+ * @subpackage Calendar
*
+ * @todo Implement or remove
*/
-interface Notable {
- /**
- * 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);
-
- /**
- * Return the start timestamp.
- */
- public function getCalendarStartTime();
-
- /**
- * Return the end timestamp.
- */
- public function getCalendarEndTime();
-}
/**
* Return a timestamp for the start of a given day (defaults today).
*
+ * @param int $day Day
+ * @param int $month Month
+ * @param int $year Year
+ *
+ * @return int
+ * @access private
*/
function get_day_start($day = null, $month = null, $year = null) {
return mktime(0, 0, 0, $month, $day, $year);
@@ -49,6 +25,12 @@ function get_day_start($day = null, $month = null, $year = null) {
/**
* Return a timestamp for the end of a given day (defaults today).
*
+ * @param int $day Day
+ * @param int $month Month
+ * @param int $year Year
+ *
+ * @return int
+ * @access private
*/
function get_day_end($day = null, $month = null, $year = null) {
return mktime(23, 59, 59, $month, $day, $year);
@@ -57,19 +39,26 @@ function get_day_end($day = null, $month = null, $year = null) {
/**
* Return the notable entities for a given time period.
*
- * @param int $start_time The start time as a unix timestamp.
- * @param int $end_time The end time as a unix timestamp.
- * @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).
+ * @todo this function also accepts an array(type => subtypes) for 3rd arg. Should we document this?
+ *
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @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 instead of entities. Defaults to false.
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any.
+ * @param mixed $container_guid Container or containers to get entities from (default: any).
+ *
+ * @return array|false
+ * @access private
*/
-function get_notable_entities($start_time, $end_time, $type = "", $subtype = "", $owner_guid = 0, $order_by = "asc", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) {
+function get_notable_entities($start_time, $end_time, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "asc", $limit = 10, $offset = 0, $count = false, $site_guid = 0,
+$container_guid = null) {
global $CONFIG;
if ($subtype === false || $subtype === null || $subtype === 0) {
@@ -91,15 +80,17 @@ function get_notable_entities($start_time, $end_time, $type = "", $subtype = "",
if (is_array($type)) {
$tempwhere = "";
if (sizeof($type)) {
- foreach($type as $typekey => $subtypearray) {
- foreach($subtypearray as $subtypeval) {
+ foreach ($type as $typekey => $subtypearray) {
+ foreach ($subtypearray as $subtypeval) {
$typekey = sanitise_string($typekey);
if (!empty($subtypeval)) {
$subtypeval = (int) get_subtype_id($typekey, $subtypeval);
} else {
$subtypeval = 0;
}
- if (!empty($tempwhere)) $tempwhere .= " or ";
+ if (!empty($tempwhere)) {
+ $tempwhere .= " or ";
+ }
$tempwhere .= "(e.type = '{$typekey}' and e.subtype = {$subtypeval})";
}
}
@@ -115,7 +106,7 @@ function get_notable_entities($start_time, $end_time, $type = "", $subtype = "",
$where[] = "e.type='$type'";
}
- if ($subtype!=="") {
+ if ($subtype !== "") {
$where[] = "e.subtype=$subtype";
}
}
@@ -128,8 +119,8 @@ function get_notable_entities($start_time, $end_time, $type = "", $subtype = "",
} 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 = implode(",",$owner_guid); //
- $where[] = "e.owner_guid in ({$owner_guid})" ; //
+ $owner_guid = implode(",", $owner_guid);
+ $where[] = "e.owner_guid in ({$owner_guid})";
}
if (is_null($container_guid)) {
$container_guid = $owner_array;
@@ -142,8 +133,10 @@ function get_notable_entities($start_time, $end_time, $type = "", $subtype = "",
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) . ")";
+ 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}";
@@ -195,21 +188,26 @@ function get_notable_entities($start_time, $end_time, $type = "", $subtype = "",
/**
* Return the notable entities for a given time period based on an item of metadata.
*
- * @param int $start_time The start time as a unix timestamp.
- * @param int $end_time The end time as a unix timestamp.
- * @param mixed $meta_name
- * @param mixed $meta_value
- * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @param mixed $meta_name Metadata name
+ * @param mixed $meta_value Metadata value
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
* @param string $entity_subtype The subtype of the entity.
- * @param int $limit
- * @param int $offset
- * @param string $order_by Optional ordering.
- * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites.
- * @param true|false $count If set to true, returns the total number of entities rather than a list. (Default: false)
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any.
+ * @param bool $count If true, returns count instead of entities. (Default: false)
*
* @return int|array A list of entities, or a count if $count is set to true
+ * @access private
*/
-function get_notable_entities_from_metadata($start_time, $end_time, $meta_name, $meta_value = "", $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) {
+function get_notable_entities_from_metadata($start_time, $end_time, $meta_name, $meta_value = "",
+$entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "",
+$site_guid = 0, $count = false) {
+
global $CONFIG;
$meta_n = get_metastring_id($meta_name);
@@ -227,7 +225,7 @@ function get_notable_entities_from_metadata($start_time, $end_time, $meta_name,
$order_by = sanitise_string($order_by);
$site_guid = (int) $site_guid;
if ((is_array($owner_guid) && (count($owner_guid)))) {
- foreach($owner_guid as $key => $guid) {
+ foreach ($owner_guid as $key => $guid) {
$owner_guid[$key] = (int) $guid;
}
} else {
@@ -242,7 +240,7 @@ function get_notable_entities_from_metadata($start_time, $end_time, $meta_name,
$where = array();
- if ($entity_type!="") {
+ if ($entity_type != "") {
$where[] = "e.type='$entity_type'";
}
@@ -250,11 +248,11 @@ function get_notable_entities_from_metadata($start_time, $end_time, $meta_name,
$where[] = "e.subtype=$entity_subtype";
}
- if ($meta_name!="") {
+ if ($meta_name != "") {
$where[] = "m.name_id='$meta_n'";
}
- if ($meta_value!="") {
+ if ($meta_value != "") {
$where[] = "m.value_id='$meta_v'";
}
@@ -263,7 +261,7 @@ function get_notable_entities_from_metadata($start_time, $end_time, $meta_name,
}
if (is_array($owner_guid)) {
- $where[] = "e.container_guid in (".implode(",",$owner_guid).")";
+ $where[] = "e.container_guid in (" . implode(",", $owner_guid) . ")";
} else if ($owner_guid > 0) {
$where[] = "e.container_guid = {$owner_guid}";
}
@@ -290,7 +288,9 @@ function get_notable_entities_from_metadata($start_time, $end_time, $meta_name,
$query = "SELECT count(distinct e.guid) as total ";
}
- $query .= "from {$CONFIG->dbprefix}entities e JOIN {$CONFIG->dbprefix}metadata m on e.guid = m.entity_guid $cal_join where";
+ $query .= "from {$CONFIG->dbprefix}entities e"
+ . " JOIN {$CONFIG->dbprefix}metadata m on e.guid = m.entity_guid $cal_join where";
+
foreach ($where as $w) {
$query .= " $w and ";
}
@@ -315,22 +315,29 @@ function get_notable_entities_from_metadata($start_time, $end_time, $meta_name,
/**
* Return the notable entities for a given time period based on their relationship.
*
- * @param int $start_time The start time as a unix timestamp.
- * @param int $end_time The end time as a unix timestamp.
- * @param string $relationship The relationship eg "friends_of"
- * @param int $relationship_guid The guid of the entity to use query
- * @param bool $inverse_relationship Reverse the normal function of the query to instead say "give me all entities for whome $relationship_guid is a $relationship of"
- * @param string $type
- * @param string $subtype
- * @param int $owner_guid
- * @param string $order_by
- * @param int $limit
- * @param int $offset
- * @param boolean $count Set to true if you want to count the number of entities instead (default 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 $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @param string $relationship The relationship eg "friends_of"
+ * @param int $relationship_guid The guid of the entity to use query
+ * @param bool $inverse_relationship Reverse the normal function of the query to say
+ * "give me all entities for whom $relationship_guid is a
+ * $relationship of"
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param int $owner_guid Owner GUID
+ * @param string $order_by Optional Order by
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param boolean $count If true returns a count of entities (default false)
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
+ *
* @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @access private
*/
-function get_noteable_entities_from_relationship($start_time, $end_time, $relationship, $relationship_guid, $inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+function get_noteable_entities_from_relationship($start_time, $end_time, $relationship,
+$relationship_guid, $inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+
global $CONFIG;
$start_time = (int)$start_time;
@@ -356,11 +363,12 @@ function get_noteable_entities_from_relationship($start_time, $end_time, $relati
$where = array();
- if ($relationship!="") {
+ if ($relationship != "") {
$where[] = "r.relationship='$relationship'";
}
if ($relationship_guid) {
- $where[] = ($inverse_relationship ? "r.guid_two='$relationship_guid'" : "r.guid_one='$relationship_guid'");
+ $where[] = $inverse_relationship ?
+ "r.guid_two='$relationship_guid'" : "r.guid_one='$relationship_guid'";
}
if ($type != "") {
$where[] = "e.type='$type'";
@@ -401,7 +409,9 @@ function get_noteable_entities_from_relationship($start_time, $end_time, $relati
} else {
$query = "SELECT distinct e.* ";
}
- $query .= " from {$CONFIG->dbprefix}entity_relationships r JOIN {$CONFIG->dbprefix}entities e on $joinon $cal_join where ";
+ $query .= " from {$CONFIG->dbprefix}entity_relationships r"
+ . " JOIN {$CONFIG->dbprefix}entities e on $joinon $cal_join where ";
+
foreach ($where as $w) {
$query .= " $w and ";
}
@@ -421,66 +431,87 @@ function get_noteable_entities_from_relationship($start_time, $end_time, $relati
/**
* Get all entities for today.
*
- * @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).
+ * @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 If true returns a count of entities (default false)
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
+ * @param mixed $container_guid Container(s) to get entities from (default: any).
+ *
+ * @return array|false
+ * @access private
*/
-function get_todays_entities($type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) {
+function get_todays_entities($type = "", $subtype = "", $owner_guid = 0, $order_by = "",
+$limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) {
+
$day_start = get_day_start();
$day_end = get_day_end();
- return get_notable_entities($day_start, $day_end, $type, $subtype, $owner_guid, $order_by, $limit, $offset, $count, $site_guid, $container_guid);
+ return get_notable_entities($day_start, $day_end, $type, $subtype, $owner_guid, $order_by,
+ $limit, $offset, $count, $site_guid, $container_guid);
}
/**
* Get entities for today from metadata.
*
- * @param mixed $meta_name
- * @param mixed $meta_value
- * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param mixed $meta_name Metadata name
+ * @param mixed $meta_value Metadata value
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
* @param string $entity_subtype The subtype of the entity.
- * @param int $limit
- * @param int $offset
- * @param string $order_by Optional ordering.
- * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites.
- * @param true|false $count If set to true, returns the total number of entities rather than a list. (Default: false)
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any.
+ * @param bool $count If true, returns count instead of entities. (Default: false)
*
* @return int|array A list of entities, or a count if $count is set to true
+ * @access private
*/
-function get_todays_entities_from_metadata($meta_name, $meta_value = "", $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) {
+function get_todays_entities_from_metadata($meta_name, $meta_value = "", $entity_type = "",
+$entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0,
+$count = false) {
+
$day_start = get_day_start();
$day_end = get_day_end();
- return get_notable_entities_from_metadata($day_start, $day_end, $meta_name, $meta_value, $entity_type, $entity_subtype, $owner_guid, $limit, $offset, $order_by, $site_guid, $count);
+ return get_notable_entities_from_metadata($day_start, $day_end, $meta_name, $meta_value,
+ $entity_type, $entity_subtype, $owner_guid, $limit, $offset, $order_by, $site_guid, $count);
}
/**
* Get entities for today from a relationship
*
- * @param string $relationship The relationship eg "friends_of"
- * @param int $relationship_guid The guid of the entity to use query
- * @param bool $inverse_relationship Reverse the normal function of the query to instead say "give me all entities for whome $relationship_guid is a $relationship of"
- * @param string $type
- * @param string $subtype
- * @param int $owner_guid
- * @param string $order_by
- * @param int $limit
- * @param int $offset
- * @param boolean $count Set to true if you want to count the number of entities instead (default false)
- * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites.
+ * @param string $relationship The relationship eg "friends_of"
+ * @param int $relationship_guid The guid of the entity to use query
+ * @param bool $inverse_relationship Reverse the normal function of the query to say
+ * "give me all entities for whom $relationship_guid is a
+ * $relationship of"
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param int $owner_guid Owner GUID
+ * @param string $order_by Optional Order by
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param boolean $count If true returns a count of entities (default false)
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
+ *
* @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @access private
*/
-function get_todays_entities_from_relationship($relationship, $relationship_guid, $inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+function get_todays_entities_from_relationship($relationship, $relationship_guid,
+$inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+
$day_start = get_day_start();
$day_end = get_day_end();
- return get_notable_entities_from_relationship($day_start, $day_end, $relationship, $relationship_guid, $inverse_relationship, $type, $subtype, $owner_guid, $order_by, $limit, $offset, $count, $site_guid);
+ return get_notable_entities_from_relationship($day_start, $day_end, $relationship,
+ $relationship_guid, $inverse_relationship, $type, $subtype, $owner_guid, $order_by,
+ $limit, $offset, $count, $site_guid);
}
/**
@@ -488,23 +519,31 @@ function get_todays_entities_from_relationship($relationship, $relationship_guid
*
* @see elgg_view_entity_list
*
- * @param int $start_time The start time as a unix timestamp.
- * @param int $end_time The end time as a unix timestamp.
- * @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
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @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 return; 10 by default
+ * @param boolean $fullview Whether or not to display the full view (default: true)
+ * @param boolean $listtypetoggle Whether or not to allow gallery view
+ * @param boolean $navigation Display pagination? Default: true
+ *
* @return string A viewable list of entities
+ * @access private
*/
-function list_notable_entities($start_time, $end_time, $type= "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $navigation = true) {
+function list_notable_entities($start_time, $end_time, $type= "", $subtype = "", $owner_guid = 0,
+$limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) {
+
$offset = (int) get_input('offset');
- $count = get_notable_entities($start_time, $end_time, $type, $subtype, $owner_guid, "", $limit, $offset, true);
- $entities = get_notable_entities($start_time, $end_time,$type, $subtype, $owner_guid, "", $limit, $offset);
+ $count = get_notable_entities($start_time, $end_time, $type, $subtype,
+ $owner_guid, "", $limit, $offset, true);
+
+ $entities = get_notable_entities($start_time, $end_time, $type, $subtype,
+ $owner_guid, "", $limit, $offset);
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $navigation);
+ return elgg_view_entity_list($entities, $count, $offset, $limit,
+ $fullview, $listtypetoggle, $navigation);
}
/**
@@ -512,18 +551,23 @@ function list_notable_entities($start_time, $end_time, $type= "", $subtype = "",
*
* @see list_notable_entities
*
- * @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
+ * @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 return; 10 by default
+ * @param boolean $fullview Whether or not to display the full view (default: true)
+ * @param boolean $listtypetoggle Whether or not to allow gallery view
+ * @param boolean $navigation Display pagination? Default: true
+ *
* @return string A viewable list of entities
+ * @access private
*/
-function list_todays_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $navigation = true) {
+function list_todays_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10,
+$fullview = true, $listtypetoggle = false, $navigation = true) {
+
$day_start = get_day_start();
$day_end = get_day_end();
- return list_notable_entities($day_start, $day_end, $type, $subtype, $owner_guid, $limit, $fullview, $viewtypetoggle, $navigation);
-} \ No newline at end of file
+ return list_notable_entities($day_start, $day_end, $type, $subtype, $owner_guid, $limit,
+ $fullview, $listtypetoggle, $navigation);
+}
diff --git a/engine/lib/configuration.php b/engine/lib/configuration.php
index 7976f8d8b..55e5bbd36 100644
--- a/engine/lib/configuration.php
+++ b/engine/lib/configuration.php
@@ -1,45 +1,431 @@
<?php
/**
- * Elgg configuration library
- * Contains functions for managing system configuration
+ * Elgg configuration procedural code.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * Includes functions for manipulating the configuration values stored in the database
+ * Plugin authors should use the {@link elgg_get_config()}, {@link elgg_set_config()},
+ * {@link elgg_save_config()}, and {@unset_config()} functions to access or update
+ * config values.
+ *
+ * Elgg's configuration is split among 2 tables and 1 file:
+ * - dbprefix_config
+ * - dbprefix_datalists
+ * - engine/settings.php (See {@link settings.example.php})
+ *
+ * Upon system boot, all values in dbprefix_config are read into $CONFIG.
+ *
+ * @package Elgg.Core
+ * @subpackage Configuration
+ */
+
+/**
+ * Get the URL for the current (or specified) site
+ *
+ * @param int $site_guid The GUID of the site whose URL we want to grab
+ * @return string
+ * @since 1.8.0
+ */
+function elgg_get_site_url($site_guid = 0) {
+ if ($site_guid == 0) {
+ global $CONFIG;
+ return $CONFIG->wwwroot;
+ }
+
+ $site = get_entity($site_guid);
+
+ if (!$site instanceof ElggSite) {
+ return false;
+ }
+ /* @var ElggSite $site */
+
+ return $site->url;
+}
+
+/**
+ * Get the plugin path for this installation
+ *
+ * @return string
+ * @since 1.8.0
+ */
+function elgg_get_plugins_path() {
+ global $CONFIG;
+ return $CONFIG->pluginspath;
+}
+
+/**
+ * Get the data directory path for this installation
+ *
+ * @return string
+ * @since 1.8.0
+ */
+function elgg_get_data_path() {
+ global $CONFIG;
+ return $CONFIG->dataroot;
+}
+
+/**
+ * Get the root directory path for this installation
+ *
+ * @return string
+ * @since 1.8.0
+ */
+function elgg_get_root_path() {
+ global $CONFIG;
+ return $CONFIG->path;
+}
+
+/**
+ * Get an Elgg configuration value
+ *
+ * @param string $name Name of the configuration value
+ * @param int $site_guid NULL for installation setting, 0 for default site
+ *
+ * @return mixed Configuration value or null if it does not exist
+ * @since 1.8.0
+ */
+function elgg_get_config($name, $site_guid = 0) {
+ global $CONFIG;
+
+ $name = trim($name);
+
+ if (isset($CONFIG->$name)) {
+ return $CONFIG->$name;
+ }
+
+ if ($site_guid === null) {
+ // installation wide setting
+ $value = datalist_get($name);
+ } else {
+ // hit DB only if we're not sure if value exists or not
+ if (!isset($CONFIG->site_config_loaded)) {
+ // site specific setting
+ if ($site_guid == 0) {
+ $site_guid = (int) $CONFIG->site_id;
+ }
+ $value = get_config($name, $site_guid);
+ } else {
+ $value = null;
+ }
+ }
+
+ // @todo document why we don't cache false
+ if ($value === false) {
+ return null;
+ }
+
+ $CONFIG->$name = $value;
+ return $value;
+}
+
+/**
+ * Set an Elgg configuration value
+ *
+ * @warning This does not persist the configuration setting. Use elgg_save_config()
+ *
+ * @param string $name Name of the configuration value
+ * @param mixed $value Value
+ *
+ * @return void
+ * @since 1.8.0
+ */
+function elgg_set_config($name, $value) {
+ global $CONFIG;
+
+ $name = trim($name);
+
+ $CONFIG->$name = $value;
+}
+
+/**
+ * Save a configuration setting
+ *
+ * @param string $name Configuration name (cannot be greater than 255 characters)
+ * @param mixed $value Configuration value. Should be string for installation setting
+ * @param int $site_guid NULL for installation setting, 0 for default site
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_save_config($name, $value, $site_guid = 0) {
+ global $CONFIG;
+
+ $name = trim($name);
+
+ if (strlen($name) > 255) {
+ elgg_log("The name length for configuration variables cannot be greater than 255", "ERROR");
+ return false;
+ }
+
+ elgg_set_config($name, $value);
+
+ if ($site_guid === NULL) {
+ if (is_array($value) || is_object($value)) {
+ return false;
+ }
+ return datalist_set($name, $value);
+ } else {
+ if ($site_guid == 0) {
+ $site_guid = (int) $CONFIG->site_id;
+ }
+ return set_config($name, $value, $site_guid);
+ }
+}
+
+/**
+ * Check that installation has completed and the database is populated.
+ *
+ * @throws InstallationException|DatabaseException
+ * @return void
+ * @access private
*/
+function verify_installation() {
+ global $CONFIG;
+
+ if (isset($CONFIG->installed)) {
+ return;
+ }
+
+ try {
+ $dblink = get_db_link('read');
+ if (!$dblink) {
+ throw new DatabaseException();
+ }
+
+ mysql_query("SELECT value FROM {$CONFIG->dbprefix}datalists WHERE name = 'installed'", $dblink);
+ if (mysql_errno($dblink) > 0) {
+ throw new DatabaseException();
+ }
+
+ $CONFIG->installed = true;
+
+ } catch (DatabaseException $e) {
+ throw new InstallationException(elgg_echo('InstallationException:SiteNotInstalled'));
+ }
+}
/**
- * Unset a config option.
+ * An array of key value pairs from the datalists table.
+ *
+ * Used as a cache in datalist functions.
*
- * @param string $name The name of the field.
- * @param int $site_guid Optionally, the GUID of the site (current site is assumed by default).
- * @return mixed
+ * @global array $DATALIST_CACHE
+ */
+$DATALIST_CACHE = array();
+
+/**
+ * Get the value of a datalist element.
+ *
+ * @internal Datalists are stored in the datalist table.
+ *
+ * @tip Use datalists to store information common to a full installation.
+ *
+ * @param string $name The name of the datalist
+ * @return string|null|false String if value exists, null if doesn't, false on error
+ * @access private
+ */
+function datalist_get($name) {
+ global $CONFIG, $DATALIST_CACHE;
+
+ $name = trim($name);
+
+ // cannot store anything longer than 255 characters in db, so catch here
+ if (elgg_strlen($name) > 255) {
+ elgg_log("The name length for configuration variables cannot be greater than 255", "ERROR");
+ return false;
+ }
+
+ $name = sanitise_string($name);
+ if (isset($DATALIST_CACHE[$name])) {
+ return $DATALIST_CACHE[$name];
+ }
+
+ // If memcache enabled then cache value in memcache
+ $value = null;
+ static $datalist_memcache;
+ if ((!$datalist_memcache) && (is_memcache_available())) {
+ $datalist_memcache = new ElggMemcache('datalist_memcache');
+ }
+ if ($datalist_memcache) {
+ $value = $datalist_memcache->load($name);
+ }
+ if ($value) {
+ return $value;
+ }
+
+ // [Marcus Povey 20090217 : Now retrieving all datalist values on first
+ // load as this saves about 9 queries per page]
+ // This also causes OOM problems when the datalists table is large
+ // @todo make a list of datalists that we want to get in one grab
+ $result = get_data("SELECT * from {$CONFIG->dbprefix}datalists");
+ if ($result) {
+ foreach ($result as $row) {
+ $DATALIST_CACHE[$row->name] = $row->value;
+
+ // Cache it if memcache is available
+ if ($datalist_memcache) {
+ $datalist_memcache->save($row->name, $row->value);
+ }
+ }
+
+ if (isset($DATALIST_CACHE[$name])) {
+ return $DATALIST_CACHE[$name];
+ }
+ }
+
+ return null;
+}
+
+/**
+ * Set the value for a datalist element.
+ *
+ * @param string $name The name of the datalist
+ * @param string $value The new value
+ *
+ * @return bool
+ * @access private
+ */
+function datalist_set($name, $value) {
+ global $CONFIG, $DATALIST_CACHE;
+
+ // cannot store anything longer than 255 characters in db, so catch before we set
+ if (elgg_strlen($name) > 255) {
+ elgg_log("The name length for configuration variables cannot be greater than 255", "ERROR");
+ return false;
+ }
+
+ $sanitised_name = sanitise_string($name);
+ $sanitised_value = sanitise_string($value);
+
+ // If memcache is available then invalidate the cached copy
+ static $datalist_memcache;
+ if ((!$datalist_memcache) && (is_memcache_available())) {
+ $datalist_memcache = new ElggMemcache('datalist_memcache');
+ }
+
+ if ($datalist_memcache) {
+ $datalist_memcache->delete($name);
+ }
+
+ $success = insert_data("INSERT into {$CONFIG->dbprefix}datalists"
+ . " set name = '{$sanitised_name}', value = '{$sanitised_value}'"
+ . " ON DUPLICATE KEY UPDATE value='{$sanitised_value}'");
+
+ if ($success !== FALSE) {
+ $DATALIST_CACHE[$name] = $value;
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Run a function one time per installation.
+ *
+ * If you pass a timestamp as the second argument, it will run the function
+ * only if (i) it has never been run before or (ii) the timestamp is >=
+ * the last time it was run.
+ *
+ * @warning Functions are determined by their name. If you change the name of a function
+ * it will be run again.
+ *
+ * @tip Use $timelastupdatedcheck in your plugins init function to perform automated
+ * upgrades. Schedule a function to run once and pass the timestamp of the new release.
+ * This will cause the run once function to be run on all installations. To perform
+ * additional upgrades, create new functions for each release.
+ *
+ * @warning The function name cannot be longer than 255 characters long due to
+ * the current schema for the datalist table.
+ *
+ * @internal A datalist entry $functioname is created with the value of time().
+ *
+ * @param string $functionname The name of the function you want to run.
+ * @param int $timelastupdatedcheck A UNIX timestamp. If time() is > than this,
+ * this function will be run again.
+ *
+ * @return bool
+ */
+function run_function_once($functionname, $timelastupdatedcheck = 0) {
+ $lastupdated = datalist_get($functionname);
+ if ($lastupdated) {
+ $lastupdated = (int) $lastupdated;
+ } elseif ($lastupdated !== false) {
+ $lastupdated = 0;
+ } else {
+ // unable to check datalist
+ return false;
+ }
+ if (is_callable($functionname) && $lastupdated <= $timelastupdatedcheck) {
+ $functionname();
+ datalist_set($functionname, time());
+ return true;
+ } else {
+ return false;
+ }
+}
+
+/**
+ * Removes a config setting.
+ *
+ * @internal
+ * These settings are stored in the dbprefix_config table and read during system
+ * boot into $CONFIG.
+ *
+ * @param string $name The name of the field.
+ * @param int $site_guid Optionally, the GUID of the site (current site is assumed by default).
+ *
+ * @return int|false The number of affected rows or false on error.
+ *
+ * @see get_config()
+ * @see set_config()
*/
function unset_config($name, $site_guid = 0) {
global $CONFIG;
+ if (isset($CONFIG->$name)) {
+ unset($CONFIG->$name);
+ }
+
$name = sanitise_string($name);
$site_guid = (int) $site_guid;
if ($site_guid == 0) {
$site_guid = (int) $CONFIG->site_id;
}
- return delete_data("delete from {$CONFIG->dbprefix}config where name='$name' and site_guid=$site_guid");
+ $query = "delete from {$CONFIG->dbprefix}config where name='$name' and site_guid=$site_guid";
+ return delete_data($query);
}
/**
- * Sets a configuration value
+ * Add or update a config setting.
*
- * @param string $name The name of the configuration value
- * @param string $value Its value
- * @param int $site_guid Optionally, the GUID of the site (current site is assumed by default)
- * @return 0
+ * If the config name already exists, it will be updated to the new value.
+ *
+ * @internal
+ * These settings are stored in the dbprefix_config table and read during system
+ * boot into $CONFIG.
+ *
+ * @param string $name The name of the configuration value
+ * @param string $value Its value
+ * @param int $site_guid Optionally, the GUID of the site (current site is assumed by default)
+ *
+ * @return bool
* @todo The config table doens't have numeric primary keys so insert_data returns 0.
+ * @todo Use "INSERT ... ON DUPLICATE KEY UPDATE" instead of trying to delete then add.
+ * @see unset_config()
+ * @see get_config()
+ * @access private
*/
function set_config($name, $value, $site_guid = 0) {
global $CONFIG;
+ $name = trim($name);
+
+ // cannot store anything longer than 255 characters in db, so catch before we set
+ if (elgg_strlen($name) > 255) {
+ elgg_log("The name length for configuration variables cannot be greater than 255", "ERROR");
+ return false;
+ }
+
// Unset existing
unset_config($name, $site_guid);
@@ -50,42 +436,90 @@ function set_config($name, $value, $site_guid = 0) {
$CONFIG->$name = $value;
$value = sanitise_string(serialize($value));
- return insert_data("insert into {$CONFIG->dbprefix}config set name = '{$name}', value = '{$value}', site_guid = {$site_guid}");
+ $query = "insert into {$CONFIG->dbprefix}config"
+ . " set name = '{$name}', value = '{$value}', site_guid = {$site_guid}";
+ $result = insert_data($query);
+ return $result !== false;
}
/**
* Gets a configuration value
*
- * @param string $name The name of the config value
- * @param int $site_guid Optionally, the GUID of the site (current site is assumed by default)
- * @return mixed|false Depending on success
+ * @internal
+ * These settings are stored in the dbprefix_config table and read during system
+ * boot into $CONFIG.
+ *
+ * @param string $name The name of the config value
+ * @param int $site_guid Optionally, the GUID of the site (current site is assumed by default)
+ *
+ * @return mixed|null
+ * @see set_config()
+ * @see unset_config()
+ * @access private
*/
function get_config($name, $site_guid = 0) {
global $CONFIG;
+ $name = sanitise_string($name);
+ $site_guid = (int) $site_guid;
+
+ // check for deprecated values.
+ // @todo might be a better spot to define this?
+ $new_name = false;
+ switch($name) {
+ case 'viewpath':
+ $new_name = 'view_path';
+ $dep_version = 1.8;
+ break;
+
+ case 'pluginspath':
+ $new_name = 'plugins_path';
+ $dep_version = 1.8;
+ break;
+
+ case 'sitename':
+ $new_name = 'site_name';
+ $dep_version = 1.8;
+ break;
+ }
+
+ // @todo these haven't really been implemented in Elgg 1.8. Complete in 1.9.
+ // show dep message
+ if ($new_name) {
+ // $msg = "Config value $name has been renamed as $new_name";
+ $name = $new_name;
+ // elgg_deprecated_notice($msg, $dep_version);
+ }
+
+ // decide from where to return the value
if (isset($CONFIG->$name)) {
return $CONFIG->$name;
}
- $name = sanitise_string($name);
- $site_guid = (int) $site_guid;
+
if ($site_guid == 0) {
$site_guid = (int) $CONFIG->site_id;
}
- if ($result = get_data_row("SELECT value FROM {$CONFIG->dbprefix}config
- WHERE name = '{$name}' and site_guid = {$site_guid}")) {
+
+ $result = get_data_row("SELECT value FROM {$CONFIG->dbprefix}config
+ WHERE name = '{$name}' and site_guid = {$site_guid}");
+
+ if ($result) {
$result = $result->value;
$result = unserialize($result->value);
$CONFIG->$name = $result;
return $result;
}
- return false;
+ return null;
}
/**
- * Gets all the configuration details in the config database for a given site.
+ * Loads all configuration values from the dbprefix_config table into $CONFIG.
*
* @param int $site_guid Optionally, the GUID of the site (current site is assumed by default)
+ *
+ * @return bool
+ * @access private
*/
function get_all_config($site_guid = 0) {
global $CONFIG;
@@ -93,10 +527,10 @@ function get_all_config($site_guid = 0) {
$site_guid = (int) $site_guid;
if ($site_guid == 0) {
- $site_guid = (int) $CONFIG->site_id;
+ $site_guid = (int) $CONFIG->site_guid;
}
- if ($result = get_data("SELECT * from {$CONFIG->dbprefix}config where site_guid = {$site_guid}")) {
+ if ($result = get_data("SELECT * FROM {$CONFIG->dbprefix}config WHERE site_guid = $site_guid")) {
foreach ($result as $r) {
$name = $r->name;
$value = $r->value;
@@ -109,104 +543,90 @@ function get_all_config($site_guid = 0) {
}
/**
- * If certain configuration elements don't exist, autodetect sensible defaults
- *
- * @uses $CONFIG The main configuration global
+ * Loads configuration related to this site
*
+ * This loads from the config database table and the site entity
+ * @access private
*/
-function set_default_config() {
+function _elgg_load_site_config() {
global $CONFIG;
- if (empty($CONFIG->path)) {
- $CONFIG->path = str_replace("\\","/",dirname(dirname(dirname(__FILE__)))) . "/";
- }
-
- if (empty($CONFIG->viewpath)) {
- $CONFIG->viewpath = $CONFIG->path . "views/";
+ $CONFIG->site_guid = (int) datalist_get('default_site');
+ $CONFIG->site_id = $CONFIG->site_guid;
+ $CONFIG->site = get_entity($CONFIG->site_guid);
+ if (!$CONFIG->site) {
+ throw new InstallationException(elgg_echo('InstallationException:SiteNotInstalled'));
}
- if (empty($CONFIG->pluginspath)) {
- $CONFIG->pluginspath = $CONFIG->path . "mod/";
- }
-
- if (empty($CONFIG->wwwroot)) {
- /*
- $CONFIG->wwwroot = "http://" . $_SERVER['SERVER_NAME'];
+ $CONFIG->wwwroot = $CONFIG->site->url;
+ $CONFIG->sitename = $CONFIG->site->name;
+ $CONFIG->sitedescription = $CONFIG->site->description;
+ $CONFIG->siteemail = $CONFIG->site->email;
+ $CONFIG->url = $CONFIG->wwwroot;
- $request = $_SERVER['REQUEST_URI'];
+ get_all_config();
+ // gives hint to elgg_get_config function how to approach missing values
+ $CONFIG->site_config_loaded = true;
+}
- if (strripos($request,"/") < (strlen($request) - 1)) {
- // addressing a file directly, not a dir
- $request = substr($request, 0, strripos($request,"/")+1);
- }
+/**
+ * Loads configuration related to Elgg as an application
+ *
+ * This loads from the datalists database table
+ * @access private
+ */
+function _elgg_load_application_config() {
+ global $CONFIG;
- $CONFIG->wwwroot .= $request;
- */
- $pathpart = str_replace("//","/",str_replace($_SERVER['DOCUMENT_ROOT'],"",$CONFIG->path));
- if (substr($pathpart,0,1) != "/") {
- $pathpart = "/" . $pathpart;
+ $install_root = str_replace("\\", "/", dirname(dirname(dirname(__FILE__))));
+ $defaults = array(
+ 'path' => "$install_root/",
+ 'view_path' => "$install_root/views/",
+ 'plugins_path' => "$install_root/mod/",
+ 'language' => 'en',
+
+ // compatibility with old names for plugins not using elgg_get_config()
+ 'viewpath' => "$install_root/views/",
+ 'pluginspath' => "$install_root/mod/",
+ );
+
+ foreach ($defaults as $name => $value) {
+ if (empty($CONFIG->$name)) {
+ $CONFIG->$name = $value;
}
- $CONFIG->wwwroot = "http://" . $_SERVER['HTTP_HOST'] . $pathpart;
}
- if (empty($CONFIG->url)) {
- $CONFIG->url = $CONFIG->wwwroot;
+ $path = datalist_get('path');
+ if (!empty($path)) {
+ $CONFIG->path = $path;
}
-
- if (empty($CONFIG->sitename)) {
- $CONFIG->sitename = "New Elgg site";
+ $dataroot = datalist_get('dataroot');
+ if (!empty($dataroot)) {
+ $CONFIG->dataroot = $dataroot;
}
-
- if (empty($CONFIG->language)) {
- $CONFIG->language = "en";
+ $simplecache_enabled = datalist_get('simplecache_enabled');
+ if ($simplecache_enabled !== false) {
+ $CONFIG->simplecache_enabled = $simplecache_enabled;
+ } else {
+ $CONFIG->simplecache_enabled = 1;
+ }
+ $system_cache_enabled = datalist_get('system_cache_enabled');
+ if ($system_cache_enabled !== false) {
+ $CONFIG->system_cache_enabled = $system_cache_enabled;
+ } else {
+ $CONFIG->system_cache_enabled = 1;
}
-}
-/**
- * Function that provides some config initialisation on system init
- *
- */
-function configuration_init() {
- global $CONFIG;
+ // initialize context here so it is set before the get_input call
+ $CONFIG->context = array();
- if (is_installed() || is_db_installed()) {
- $path = datalist_get('path');
- if (!empty($path)) {
- $CONFIG->path = $path;
- }
- $dataroot = datalist_get('dataroot');
- if (!empty($dataroot)) {
- $CONFIG->dataroot = $dataroot;
- }
- $simplecache_enabled = datalist_get('simplecache_enabled');
- if ($simplecache_enabled !== false) {
- $CONFIG->simplecache_enabled = $simplecache_enabled;
- } else {
- $CONFIG->simplecache_enabled = 1;
- }
- $viewpath_cache_enabled = datalist_get('viewpath_cache_enabled');
- if ($viewpath_cache_enabled !== false) {
- $CONFIG->viewpath_cache_enabled = $viewpath_cache_enabled;
- } else {
- $CONFIG->viewpath_cache_enabled = 1;
- }
- if (isset($CONFIG->site) && ($CONFIG->site instanceof ElggSite)) {
- $CONFIG->wwwroot = $CONFIG->site->url;
- $CONFIG->sitename = $CONFIG->site->name;
- $CONFIG->sitedescription = $CONFIG->site->description;
- $CONFIG->siteemail = $CONFIG->site->email;
- }
- $CONFIG->url = $CONFIG->wwwroot;
+ // needs to be set before system, init for links in html head
+ $viewtype = get_input('view', 'default');
+ $lastcached = datalist_get("simplecache_lastcached_$viewtype");
+ $CONFIG->lastcache = $lastcached;
- // Load default settings from database
- get_all_config();
+ $CONFIG->i18n_loaded_from_cache = false;
- return true;
- }
+ // this must be synced with the enum for the entities table
+ $CONFIG->entity_types = array('group', 'object', 'site', 'user');
}
-
-/**
- * Register config_init
- */
-
-register_elgg_event_handler('boot', 'system', 'configuration_init', 10); \ No newline at end of file
diff --git a/engine/lib/cron.php b/engine/lib/cron.php
index 223b6774f..4f3d05b93 100644
--- a/engine/lib/cron.php
+++ b/engine/lib/cron.php
@@ -4,72 +4,86 @@
*
* @package Elgg
* @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
*/
-/** The cron exception. */
-class CronException extends Exception {}
-
/**
- * Initialisation
+ * Cron initialization
*
+ * @return void
+ * @access private
*/
function cron_init() {
// Register a pagehandler for cron
- register_page_handler('cron','cron_page_handler');
-
+ elgg_register_page_handler('cron', 'cron_page_handler');
+
// register a hook for Walled Garden public pages
- register_plugin_hook('public_pages', 'walled_garden', 'cron_public_pages');
+ elgg_register_plugin_hook_handler('public_pages', 'walled_garden', 'cron_public_pages');
}
/**
- * Cron handler for redirecting pages.
+ * Cron handler
*
- * @param unknown_type $page
+ * @param array $page Pages
+ *
+ * @return bool
+ * @throws CronException
+ * @access private
*/
function cron_page_handler($page) {
- global $CONFIG;
+ if (!isset($page[0])) {
+ forward();
+ }
- if ($page[0]) {
- switch (strtolower($page[0])) {
- case 'minute' :
- case 'fiveminute' :
- case 'fifteenmin' :
- case 'halfhour' :
- case 'hourly' :
- case 'daily' :
- case 'weekly' :
- case 'monthly':
- case 'yearly' :
- case 'reboot' :
- set_input('period', $page[0]);
- break;
- default :
- throw new CronException(sprintf(elgg_echo('CronException:unknownperiod'), $page[0]));
- }
+ $period = strtolower($page[0]);
- // Include cron handler
- include($CONFIG->path . "engine/handlers/cron_handler.php");
- } else {
- forward();
+ $allowed_periods = array(
+ 'minute', 'fiveminute', 'fifteenmin', 'halfhour', 'hourly',
+ 'daily', 'weekly', 'monthly', 'yearly', 'reboot'
+ );
+
+ if (!in_array($period, $allowed_periods)) {
+ throw new CronException(elgg_echo('CronException:unknownperiod', array($period)));
}
+
+ // Get a list of parameters
+ $params = array();
+ $params['time'] = time();
+
+ // Data to return to
+ $old_stdout = "";
+ ob_start();
+
+ $old_stdout = elgg_trigger_plugin_hook('cron', $period, $params, $old_stdout);
+ $std_out = ob_get_clean();
+
+ echo $std_out . $old_stdout;
+ return true;
}
+/**
+ * Register cron's pages as public in case we're in Walled Garden mode
+ *
+ * @param string $hook public_pages
+ * @param string $type system
+ * @param array $return_value Array of pages to allow
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
+ */
function cron_public_pages($hook, $type, $return_value, $params) {
- $return_value[] = 'pg/cron/minute';
- $return_value[] = 'pg/cron/fiveminute';
- $return_value[] = 'pg/cron/fifteenmin';
- $return_value[] = 'pg/cron/halfhour';
- $return_value[] = 'pg/cron/hourly';
- $return_value[] = 'pg/cron/daily';
- $return_value[] = 'pg/cron/weekly';
- $return_value[] = 'pg/cron/monthly';
- $return_value[] = 'pg/cron/yearly';
- $return_value[] = 'pg/cron/reboot';
-
+ $return_value[] = 'cron/minute';
+ $return_value[] = 'cron/fiveminute';
+ $return_value[] = 'cron/fifteenmin';
+ $return_value[] = 'cron/halfhour';
+ $return_value[] = 'cron/hourly';
+ $return_value[] = 'cron/daily';
+ $return_value[] = 'cron/weekly';
+ $return_value[] = 'cron/monthly';
+ $return_value[] = 'cron/yearly';
+ $return_value[] = 'cron/reboot';
+
return $return_value;
}
-// Register a startup event
-register_elgg_event_handler('init','system','cron_init'); \ No newline at end of file
+elgg_register_event_handler('init', 'system', 'cron_init');
diff --git a/engine/lib/database.php b/engine/lib/database.php
index 58685bb82..a7949788d 100644
--- a/engine/lib/database.php
+++ b/engine/lib/database.php
@@ -1,35 +1,94 @@
<?php
/**
- * Elgg database
- * Contains database connection and transfer functionality
+ * Elgg database procedural code.
*
- * @package Elgg
- * @subpackage Core
-
- * @author Curverider Ltd
+ * Includes functions for establishing and retrieving a database link,
+ * reading data, writing data, upgrading DB schemas, and sanitizing input.
+ *
+ * @package Elgg.Core
+ * @subpackage Database
+ */
- * @link http://elgg.org/
+/**
+ * Query cache for all queries.
+ *
+ * Each query and its results are stored in this cache as:
+ * <code>
+ * $DB_QUERY_CACHE[query hash] => array(result1, result2, ... resultN)
+ * </code>
+ * @see elgg_query_runner() for details on the hash.
+ *
+ * @warning Elgg used to set this as an empty array to turn off the cache
+ *
+ * @global ElggLRUCache|null $DB_QUERY_CACHE
+ * @access private
*/
+global $DB_QUERY_CACHE;
+$DB_QUERY_CACHE = null;
-$DB_QUERY_CACHE = array();
+/**
+ * Queries to be executed upon shutdown.
+ *
+ * These queries are saved to an array and executed using
+ * a function registered by register_shutdown_function().
+ *
+ * Queries are saved as an array in the format:
+ * <code>
+ * $DB_DELAYED_QUERIES[] = array(
+ * 'q' => str $query,
+ * 'l' => resource $dblink,
+ * 'h' => str $handler // a callback function
+ * );
+ * </code>
+ *
+ * @global array $DB_DELAYED_QUERIES
+ * @access private
+ */
+global $DB_DELAYED_QUERIES;
$DB_DELAYED_QUERIES = array();
/**
+ * Database connection resources.
+ *
+ * Each database link created with establish_db_link($name) is stored in
+ * $dblink as $dblink[$name] => resource. Use get_db_link($name) to retrieve it.
+ *
+ * @global resource[] $dblink
+ * @access private
+ */
+global $dblink;
+$dblink = array();
+
+/**
+ * Database call count
+ *
+ * Each call to the database increments this counter.
+ *
+ * @global integer $dbcalls
+ * @access private
+ */
+global $dbcalls;
+$dbcalls = 0;
+
+/**
+ * Establish a connection to the database servser
+ *
* Connect to the database server and use the Elgg database for a particular database link
*
- * @param string $dblinkname Default "readwrite"; you can change this to set up additional global database links, eg "read" and "write"
+ * @param string $dblinkname The type of database connection. Used to identify the
+ * resource. eg "read", "write", or "readwrite".
+ *
+ * @return void
+ * @throws DatabaseException
+ * @access private
*/
function establish_db_link($dblinkname = "readwrite") {
// Get configuration, and globalise database link
- global $CONFIG, $dblink, $DB_QUERY_CACHE, $dbcalls;
-
- if (!isset($dblink)) {
- $dblink = array();
- }
+ global $CONFIG, $dblink, $DB_QUERY_CACHE;
if ($dblinkname != "readwrite" && isset($CONFIG->db[$dblinkname])) {
if (is_array($CONFIG->db[$dblinkname])) {
- $index = rand(0,sizeof($CONFIG->db[$dblinkname]));
+ $index = rand(0, sizeof($CONFIG->db[$dblinkname]));
$dbhost = $CONFIG->db[$dblinkname][$index]->dbhost;
$dbuser = $CONFIG->db[$dblinkname][$index]->dbuser;
$dbpass = $CONFIG->db[$dblinkname][$index]->dbpass;
@@ -48,13 +107,14 @@ function establish_db_link($dblinkname = "readwrite") {
}
// Connect to database
- if (!$dblink[$dblinkname] = mysql_connect($CONFIG->dbhost, $CONFIG->dbuser, $CONFIG->dbpass, true)) {
- $msg = sprintf(elgg_echo('DatabaseException:WrongCredentials'),
- $CONFIG->dbuser, $CONFIG->dbhost, "****");
+ if (!$dblink[$dblinkname] = mysql_connect($dbhost, $dbuser, $dbpass, true)) {
+ $msg = elgg_echo('DatabaseException:WrongCredentials',
+ array($dbuser, $dbhost, "****"));
throw new DatabaseException($msg);
}
- if (!mysql_select_db($CONFIG->dbname, $dblink[$dblinkname])) {
- $msg = sprintf(elgg_echo('DatabaseException:NoConnect'), $CONFIG->dbname);
+
+ if (!mysql_select_db($dbname, $dblink[$dblinkname])) {
+ $msg = elgg_echo('DatabaseException:NoConnect', array($dbname));
throw new DatabaseException($msg);
}
@@ -68,21 +128,22 @@ function establish_db_link($dblinkname = "readwrite") {
// Set up cache if global not initialized and query cache not turned off
if ((!$DB_QUERY_CACHE) && (!$db_cache_off)) {
- $DB_QUERY_CACHE = new ElggStaticVariableCache('db_query_cache'); //array();
- //$DB_QUERY_CACHE = select_default_memcache('db_query_cache'); //array();
+ // @todo if we keep this cache in 1.9, expose the size as a config parameter
+ $DB_QUERY_CACHE = new ElggLRUCache(200);
}
}
/**
- * Establish all database connections
+ * Establish database connections
*
* If the configuration has been set up for multiple read/write databases, set those
- * links up separately; otherwise just create the one database link
+ * links up separately; otherwise just create the one database link.
*
+ * @return void
+ * @access private
*/
function setup_db_connections() {
- // Get configuration and globalise database link
- global $CONFIG, $dblink;
+ global $CONFIG;
if (!empty($CONFIG->db->split)) {
establish_db_link('read');
@@ -93,7 +154,10 @@ function setup_db_connections() {
}
/**
- * Shutdown hook to display profiling information about db (debug mode)
+ * Display profiling information about db at NOTICE debug level upon shutdown.
+ *
+ * @return void
+ * @access private
*/
function db_profiling_shutdown_hook() {
global $dbcalls;
@@ -103,44 +167,47 @@ function db_profiling_shutdown_hook() {
}
/**
- * Execute any delayed queries.
+ * Execute any delayed queries upon shutdown.
+ *
+ * @return void
+ * @access private
*/
function db_delayedexecution_shutdown_hook() {
- global $DB_DELAYED_QUERIES, $CONFIG;
+ global $DB_DELAYED_QUERIES;
foreach ($DB_DELAYED_QUERIES as $query_details) {
- // use one of our db functions so it is included in profiling.
- $result = execute_query($query_details['q'], $query_details['l']);
-
try {
+ $link = $query_details['l'];
+
+ if ($link == 'read' || $link == 'write') {
+ $link = get_db_link($link);
+ } elseif (!is_resource($link)) {
+ elgg_log("Link for delayed query not valid resource or db_link type. Query: {$query_details['q']}", 'WARNING');
+ }
+
+ $result = execute_query($query_details['q'], $link);
+
if ((isset($query_details['h'])) && (is_callable($query_details['h']))) {
$query_details['h']($result);
}
- } catch (Exception $e) { // Suppress all errors since these can't be delt with here
+ } catch (Exception $e) {
+ // Suppress all errors since these can't be dealt with here
elgg_log($e, 'WARNING');
}
}
}
/**
- * Alias to setup_db_connections, for use in the event handler
+ * Returns (if required, also creates) a database link resource.
*
- * @param string $event The event type
- * @param string $object_type The object type
- * @param mixed $object Used for nothing in this context
- */
-function init_db($event, $object_type, $object = null) {
- register_shutdown_function('db_delayedexecution_shutdown_hook');
- register_shutdown_function('db_profiling_shutdown_hook');
- // [Marcus Povey 20090213: Db connection moved to first db connection attempt]
- return true;
-}
-
-/**
- * Gets the appropriate db link for the operation mode requested
+ * Database link resources are stored in the {@link $dblink} global. These
+ * resources are created by {@link setup_db_connections()}, which is called if
+ * no links exist.
*
- * @param string $dblinktype The type of link we want - "read", "write" or "readwrite" (the default)
- * @return object Database link
+ * @param string $dblinktype The type of link we want: "read", "write" or "readwrite".
+ *
+ * @return resource Database link
+ * @access private
*/
function get_db_link($dblinktype) {
global $dblink;
@@ -149,40 +216,59 @@ function get_db_link($dblinktype) {
return $dblink[$dblinktype];
} else if (isset($dblink['readwrite'])) {
return $dblink['readwrite'];
- }
- else {
+ } else {
setup_db_connections();
return get_db_link($dblinktype);
}
}
/**
- * Explain a given query, useful for debug.
+ * Execute an EXPLAIN for $query.
+ *
+ * @param string $query The query to explain
+ * @param mixed $link The database link resource to user.
+ *
+ * @return mixed An object of the query's result, or FALSE
+ * @access private
*/
function explain_query($query, $link) {
if ($result = execute_query("explain " . $query, $link)) {
return mysql_fetch_object($result);
}
- return false;
+ return FALSE;
}
/**
* Execute a query.
*
- * @param string $query The query
- * @param link $dblink the DB link
- * @return Returns a the result of mysql_query
+ * $query is executed via {@link mysql_query()}. If there is an SQL error,
+ * a {@link DatabaseException} is thrown.
+ *
+ * @internal
+ * {@link $dbcalls} is incremented and the query is saved into the {@link $DB_QUERY_CACHE}.
+ *
+ * @param string $query The query
+ * @param resource $dblink The DB link
+ *
+ * @return resource result of mysql_query()
+ * @throws DatabaseException
+ * @access private
*/
function execute_query($query, $dblink) {
- global $CONFIG, $dbcalls, $DB_QUERY_CACHE;
+ global $dbcalls;
+
+ if ($query == NULL) {
+ throw new DatabaseException(elgg_echo('DatabaseException:InvalidQuery'));
+ }
+
+ if (!is_resource($dblink)) {
+ throw new DatabaseException(elgg_echo('DatabaseException:InvalidDBLink'));
+ }
$dbcalls++;
$result = mysql_query($query, $dblink);
- if ($DB_QUERY_CACHE) {
- $DB_QUERY_CACHE[$query] = -1; // Set initial cache to -1
- }
if (mysql_errno($dblink)) {
throw new DatabaseException(mysql_error($dblink) . "\n\n QUERY: " . $query);
@@ -192,14 +278,17 @@ function execute_query($query, $dblink) {
}
/**
- * Queue a query for execution after all output has been sent to the user.
+ * Queue a query for execution upon shutdown.
*
* You can specify a handler function if you care about the result. This function will accept
- * the raw result from mysql_query();
+ * the raw result from {@link mysql_query()}.
+ *
+ * @param string $query The query to execute
+ * @param resource|string $dblink The database link to use or the link type (read | write)
+ * @param string $handler A callback function to pass the results array to
*
- * @param string $query The query to execute
- * @param resource $dblink The database link to use
- * @param string $handler The handler
+ * @return true
+ * @access private
*/
function execute_delayed_query($query, $dblink, $handler = "") {
global $DB_DELAYED_QUERIES;
@@ -208,6 +297,10 @@ function execute_delayed_query($query, $dblink, $handler = "") {
$DB_DELAYED_QUERIES = array();
}
+ if (!is_resource($dblink) && $dblink != 'read' && $dblink != 'write') {
+ return false;
+ }
+
// Construct delayed query
$delayed_query = array();
$delayed_query['q'] = $query;
@@ -216,212 +309,243 @@ function execute_delayed_query($query, $dblink, $handler = "") {
$DB_DELAYED_QUERIES[] = $delayed_query;
- return true;
+ return TRUE;
}
/**
* Write wrapper for execute_delayed_query()
*
- * @param string $query The query to execute
+ * @param string $query The query to execute
* @param string $handler The handler if you care about the result.
+ *
+ * @return true
+ * @uses execute_delayed_query()
+ * @uses get_db_link()
+ * @access private
*/
function execute_delayed_write_query($query, $handler = "") {
- return execute_delayed_query($query, get_db_link('write'), $handler);
+ return execute_delayed_query($query, 'write', $handler);
}
/**
* Read wrapper for execute_delayed_query()
*
- * @param string $query The query to execute
+ * @param string $query The query to execute
* @param string $handler The handler if you care about the result.
+ *
+ * @return true
+ * @uses execute_delayed_query()
+ * @uses get_db_link()
+ * @access private
*/
function execute_delayed_read_query($query, $handler = "") {
- return execute_delayed_query($query, get_db_link('read'), $handler);
+ return execute_delayed_query($query, 'read', $handler);
}
/**
- * Use this function to get data from the database
- * @param mixed $query The query being passed.
- * @param string $call Optionally, the name of a function to call back to on each row (which takes $row as a single parameter)
- * @return array An array of database result objects
+ * Retrieve rows from the database.
+ *
+ * Queries are executed with {@link execute_query()} and results
+ * are retrieved with {@link mysql_fetch_object()}. If a callback
+ * function $callback is defined, each row will be passed as the single
+ * argument to $callback. If no callback function is defined, the
+ * entire result set is returned as an array.
+ *
+ * @param mixed $query The query being passed.
+ * @param string $callback Optionally, the name of a function to call back to on each row
+ *
+ * @return array An array of database result objects or callback function results. If the query
+ * returned nothing, an empty array.
+ * @access private
*/
function get_data($query, $callback = "") {
- global $CONFIG, $DB_QUERY_CACHE;
+ return elgg_query_runner($query, $callback, false);
+}
- // Is cached?
- if ($DB_QUERY_CACHE) {
- $cached_query = $DB_QUERY_CACHE[$query];
- }
+/**
+ * Retrieve a single row from the database.
+ *
+ * Similar to {@link get_data()} but returns only the first row
+ * matched. If a callback function $callback is specified, the row will be passed
+ * as the only argument to $callback.
+ *
+ * @param mixed $query The query to execute.
+ * @param string $callback A callback function
+ *
+ * @return mixed A single database result object or the result of the callback function.
+ * @access private
+ */
+function get_data_row($query, $callback = "") {
+ return elgg_query_runner($query, $callback, true);
+}
+
+/**
+ * Handles returning data from a query, running it through a callback function,
+ * and caching the results. This is for R queries (from CRUD).
+ *
+ * @access private
+ *
+ * @param string $query The query to execute
+ * @param string $callback An optional callback function to run on each row
+ * @param bool $single Return only a single result?
+ *
+ * @return array An array of database result objects or callback function results. If the query
+ * returned nothing, an empty array.
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_query_runner($query, $callback = null, $single = false) {
+ global $DB_QUERY_CACHE;
- if ((isset($cached_query)) && ($cached_query)) {
- elgg_log("$query results returned from cache");
+ // Since we want to cache results of running the callback, we need to
+ // need to namespace the query with the callback and single result request.
+ // https://github.com/elgg/elgg/issues/4049
+ $hash = (string)$callback . (int)$single . $query;
- if ($cached_query === -1) {
- // Last time this query returned nothing, so return an empty array
- return array();
+ // Is cached?
+ if ($DB_QUERY_CACHE) {
+ if (isset($DB_QUERY_CACHE[$hash])) {
+ elgg_log("DB query $query results returned from cache (hash: $hash)", 'NOTICE');
+ return $DB_QUERY_CACHE[$hash];
}
-
- return $cached_query;
}
$dblink = get_db_link('read');
- $resultarray = array();
+ $return = array();
if ($result = execute_query("$query", $dblink)) {
+
+ // test for callback once instead of on each iteration.
+ // @todo check profiling to see if this needs to be broken out into
+ // explicit cases instead of checking in the iteration.
+ $is_callable = is_callable($callback);
while ($row = mysql_fetch_object($result)) {
- if (!empty($callback) && is_callable($callback)) {
+ if ($is_callable) {
$row = $callback($row);
}
- if ($row) {
- $resultarray[] = $row;
+
+ if ($single) {
+ $return = $row;
+ break;
+ } else {
+ $return[] = $row;
}
}
}
- if (empty($resultarray)) {
- elgg_log("DB query \"$query\" returned no results.");
- return false;
+ if (empty($return)) {
+ elgg_log("DB query $query returned no results.", 'NOTICE');
}
// Cache result
if ($DB_QUERY_CACHE) {
- $DB_QUERY_CACHE[$query] = $resultarray;
- elgg_log("$query results cached");
- }
-
- return $resultarray;
-}
-
-/**
- * Use this function to get a single data row from the database
- * @param mixed $query The query to run.
- * @return object A single database result object
- */
-
-function get_data_row($query, $callback = "") {
- global $CONFIG, $DB_QUERY_CACHE;
-
- // Is cached
- if ($DB_QUERY_CACHE) {
- $cached_query = $DB_QUERY_CACHE[$query];
- }
-
- if ((isset($cached_query)) && ($cached_query)) {
- elgg_log("$query results returned from cache");
-
- if ($cached_query === -1) {
- // Last time this query returned nothing, so return false
- //@todo fix me this should return array().
- return false;
- }
-
- return $cached_query;
- }
-
- $dblink = get_db_link('read');
-
- if ($result = execute_query("$query", $dblink)) {
- $row = mysql_fetch_object($result);
-
- // Cache result (even if query returned no data)
- if ($DB_QUERY_CACHE) {
- $DB_QUERY_CACHE[$query] = $row;
- elgg_log("$query results cached");
- }
-
- if (!empty($callback) && is_callable($callback)) {
- $row = $callback($row);
- }
-
- if ($row) {
- return $row;
- }
+ $DB_QUERY_CACHE[$hash] = $return;
+ elgg_log("DB query $query results cached (hash: $hash)", 'NOTICE');
}
- elgg_log("$query returned no results.");
- return FALSE;
+ return $return;
}
/**
- * Use this function to insert database data; returns id or false
+ * Insert a row into the database.
+ *
+ * @note Altering the DB invalidates all queries in {@link $DB_QUERY_CACHE}.
+ *
+ * @param mixed $query The query to execute.
*
- * @param mixed $query The query to run.
- * @return int $id the database id of the inserted row.
+ * @return int|false The database id of the inserted row if a AUTO_INCREMENT field is
+ * defined, 0 if not, and false on failure.
+ * @access private
*/
function insert_data($query) {
- global $CONFIG, $DB_QUERY_CACHE;
+ elgg_log("DB query $query", 'NOTICE');
+
$dblink = get_db_link('write');
- // Invalidate query cache
- if ($DB_QUERY_CACHE) {
- $DB_QUERY_CACHE->clear();
- }
-
- elgg_log("Query cache invalidated");
+ _elgg_invalidate_query_cache();
if (execute_query("$query", $dblink)) {
return mysql_insert_id($dblink);
}
- return false;
+ return FALSE;
}
/**
- * Update database data
+ * Update the database.
+ *
+ * @note Altering the DB invalidates all queries in {@link $DB_QUERY_CACHE}.
+ *
+ * @param string $query The query to run.
*
- * @param mixed $query The query to run.
- * @return Bool on success
+ * @return bool
+ * @access private
*/
function update_data($query) {
- global $CONFIG, $DB_QUERY_CACHE;
+
+ elgg_log("DB query $query", 'NOTICE');
$dblink = get_db_link('write');
- // Invalidate query cache
- if ($DB_QUERY_CACHE) {
- $DB_QUERY_CACHE->clear();
- elgg_log("Query cache invalidated");
- }
+ _elgg_invalidate_query_cache();
if (execute_query("$query", $dblink)) {
- // @todo why is this comment out?
- //return mysql_affected_rows();
- return true;
+ return TRUE;
}
- return false;
+ return FALSE;
}
/**
- * Use this function to delete data
+ * Remove data from the database.
*
- * @param mixed $query The SQL query to run
- * @return int|false Either the number of affected rows, or false on failure
+ * @note Altering the DB invalidates all queries in {@link $DB_QUERY_CACHE}.
+ *
+ * @param string $query The SQL query to run
+ *
+ * @return int|false The number of affected rows or false on failure
+ * @access private
*/
function delete_data($query) {
- global $CONFIG, $DB_QUERY_CACHE;
+
+ elgg_log("DB query $query", 'NOTICE');
$dblink = get_db_link('write');
- // Invalidate query cache
- if ($DB_QUERY_CACHE) {
- $DB_QUERY_CACHE->clear();
- elgg_log("Query cache invalidated");
- }
+ _elgg_invalidate_query_cache();
if (execute_query("$query", $dblink)) {
return mysql_affected_rows($dblink);
}
- return false;
+ return FALSE;
}
+/**
+ * Invalidate the query cache
+ *
+ * @access private
+ */
+function _elgg_invalidate_query_cache() {
+ global $DB_QUERY_CACHE;
+ if ($DB_QUERY_CACHE instanceof ElggLRUCache) {
+ $DB_QUERY_CACHE->clear();
+ elgg_log("Query cache invalidated", 'NOTICE');
+ } elseif ($DB_QUERY_CACHE) {
+ // In case someone sets the cache to an array and primes it with data
+ $DB_QUERY_CACHE = array();
+ elgg_log("Query cache invalidated", 'NOTICE');
+ }
+}
/**
- * Get the tables currently installed in the Elgg database
+ * Return tables matching the database prefix {@link $CONFIG->dbprefix}% in the currently
+ * selected database.
*
- * @return array List of tables
+ * @return array|false List of tables or false on failure
+ * @static array $tables Tables found matching the database prefix
+ * @access private
*/
function get_db_tables() {
global $CONFIG;
@@ -435,29 +559,36 @@ function get_db_tables() {
$result = get_data("show tables like '" . $CONFIG->dbprefix . "%'");
} catch (DatabaseException $d) {
// Likely we can't handle an exception here, so just return false.
- return false;
+ return FALSE;
}
$tables = array();
if (is_array($result) && !empty($result)) {
- foreach($result as $row) {
+ foreach ($result as $row) {
$row = (array) $row;
- if (is_array($row) && !empty($row))
- foreach($row as $element) {
+ if (is_array($row) && !empty($row)) {
+ foreach ($row as $element) {
$tables[] = $element;
}
+ }
}
} else {
- return false;
+ return FALSE;
}
return $tables;
}
/**
- * Run an optimize query on a mysql tables. Useful for executing after major data changes.
+ * Optimise a table.
+ *
+ * Executes an OPTIMIZE TABLE query on $table. Useful after large DB changes.
*
+ * @param string $table The name of the table to optimise
+ *
+ * @return bool
+ * @access private
*/
function optimize_table($table) {
$table = sanitise_string($table);
@@ -467,18 +598,35 @@ function optimize_table($table) {
/**
* Get the last database error for a particular database link
*
- * @param database link $dblink
+ * @param resource $dblink The DB link
+ *
* @return string Database error message
+ * @access private
*/
function get_db_error($dblink) {
return mysql_error($dblink);
}
/**
- * Runs a full database script from disk
+ * Runs a full database script from disk.
+ *
+ * The file specified should be a standard SQL file as created by
+ * mysqldump or similar. Statements must be terminated with ;
+ * and a newline character (\n or \r\n) with only one statement per line.
+ *
+ * The special string 'prefix_' is replaced with the database prefix
+ * as defined in {@link $CONFIG->dbprefix}.
+ *
+ * @warning Errors do not halt execution of the script. If a line
+ * generates an error, the error message is saved and the
+ * next line is executed. After the file is run, any errors
+ * are displayed as a {@link DatabaseException}
*
- * @uses $CONFIG
* @param string $scriptlocation The full path to the script
+ *
+ * @return void
+ * @throws DatabaseException
+ * @access private
*/
function run_sql_script($scriptlocation) {
if ($script = file_get_contents($scriptlocation)) {
@@ -486,14 +634,18 @@ function run_sql_script($scriptlocation) {
$errors = array();
+ // Remove MySQL -- style comments
$script = preg_replace('/\-\-.*\n/', '', $script);
- $sql_statements = preg_split('/;[\n\r]+/', $script);
- foreach($sql_statements as $statement) {
+
+ // Statements must end with ; and a newline
+ $sql_statements = preg_split('/;[\n\r]+/', $script);
+
+ foreach ($sql_statements as $statement) {
$statement = trim($statement);
- $statement = str_replace("prefix_",$CONFIG->dbprefix,$statement);
+ $statement = str_replace("prefix_", $CONFIG->dbprefix, $statement);
if (!empty($statement)) {
try {
- $result = update_data($statement);
+ update_data($statement);
} catch (DatabaseException $e) {
$errors[] = $e->getMessage();
}
@@ -501,99 +653,38 @@ function run_sql_script($scriptlocation) {
}
if (!empty($errors)) {
$errortxt = "";
- foreach($errors as $error)
+ foreach ($errors as $error) {
$errortxt .= " {$error};";
- throw new DatabaseException(elgg_echo('DatabaseException:DBSetupIssues') . $errortxt);
- }
- } else {
- throw new DatabaseException(sprintf(elgg_echo('DatabaseException:ScriptNotFound'), $scriptlocation));
- }
-}
-
-/**
- * Upgrade the database schema in an ordered sequence.
- *
- * Makes use of schema upgrade files
- *
- * This is a about as core as it comes, so don't start running this from your plugins!
- *
- * @param int $version The version you are upgrading from (usually given in the Elgg version format of YYYYMMDDXX - see version.php for example)
- * @param string $fromdir Optional directory to load upgrades from (default: engine/schema/upgrades/)
- * @param bool $quiet If true, will suppress all error messages. Don't use this.
- * @return bool
- */
-function db_upgrade($version, $fromdir = "", $quiet = FALSE) {
- global $CONFIG;
-
- // Elgg and its database must be installed to upgrade it!
- if (!is_db_installed() || !is_installed()) {
- return false;
- }
-
- $version = (int) $version;
-
- if (!$fromdir) {
- $fromdir = $CONFIG->path . 'engine/schema/upgrades/';
- }
-
- if ($handle = opendir($fromdir)) {
- $sqlupgrades = array();
-
- while ($sqlfile = readdir($handle)) {
- if (!is_dir($fromdir . $sqlfile)) {
- if (preg_match('/^([0-9]{10})\.(sql)$/', $sqlfile, $matches)) {
- $sql_version = (int) $matches[1];
- if ($sql_version > $version) {
- $sqlupgrades[] = $sqlfile;
- }
- }
}
- }
-
- asort($sqlupgrades);
- if (sizeof($sqlupgrades) > 0) {
- foreach($sqlupgrades as $sqlfile) {
-
- // hide all errors.
- if ($quiet) {
- try {
- run_sql_script($fromdir . $sqlfile);
- } catch (DatabaseException $e) {
- error_log($e->getmessage());
- }
- } else {
- run_sql_script($fromdir . $sqlfile);
- }
- }
+ $msg = elgg_echo('DatabaseException:DBSetupIssues') . $errortxt;
+ throw new DatabaseException($msg);
}
+ } else {
+ $msg = elgg_echo('DatabaseException:ScriptNotFound', array($scriptlocation));
+ throw new DatabaseException($msg);
}
-
- return TRUE;
}
/**
- * This function, called by validate_platform(), will check whether the installed version of
- * MySQL meets the minimum required.
+ * Format a query string for logging
*
- * TODO: If multiple dbs are supported check which db is supported and use the appropriate code to validate
- * the appropriate version.
- *
- * @return bool
+ * @param string $query Query string
+ * @return string
+ * @access private
*/
-function db_check_version() {
- $version = mysql_get_server_info();
- $points = explode('.', $version);
-
- if ($points[0] < 5) {
- return false;
- }
-
- return true;
+function elgg_format_query($query) {
+ // remove newlines and extra spaces so logs are easier to read
+ return preg_replace('/\s\s+/', ' ', $query);
}
/**
* Sanitise a string for database use, but with the option of escaping extra characters.
+ *
+ * @param string $string The string to sanitise
+ * @param string $extra_escapeable Extra characters to escape with '\\'
+ *
+ * @return string The escaped string
*/
function sanitise_string_special($string, $extra_escapeable = '') {
$string = sanitise_string($string);
@@ -606,9 +697,10 @@ function sanitise_string_special($string, $extra_escapeable = '') {
}
/**
- * Sanitise a string for database use
+ * Sanitise a string for database use.
*
* @param string $string The string to sanitise
+ *
* @return string Sanitised string
*/
function sanitise_string($string) {
@@ -621,34 +713,52 @@ function sanitise_string($string) {
* Wrapper function for alternate English spelling
*
* @param string $string The string to sanitise
+ *
* @return string Sanitised string
- * @uses sanitise_string
*/
function sanitize_string($string) {
return sanitise_string($string);
}
/**
- * Sanitises an integer for database use
+ * Sanitises an integer for database use.
*
- * @param int $int
- * @return int Sanitised integer
+ * @param int $int Value to be sanitized
+ * @param bool $signed Whether negative values should be allowed (true)
+ * @return int
*/
-function sanitise_int($int) {
+function sanitise_int($int, $signed = true) {
+ $int = (int) $int;
+
+ if ($signed === false) {
+ if ($int < 0) {
+ $int = 0;
+ }
+ }
+
return (int) $int;
}
/**
- * Wrapper function for alternate English spelling
+ * Sanitizes an integer for database use.
+ * Wrapper function for alternate English spelling (@see sanitise_int)
*
- * @param int $int
- * @return int Sanitised integer
- * @uses sanitise_string
+ * @param int $int Value to be sanitized
+ * @param bool $signed Whether negative values should be allowed (true)
+ * @return int
*/
-function sanitize_int($int) {
- return (int) $int;
+function sanitize_int($int, $signed = true) {
+ return sanitise_int($int, $signed);
}
-// Stuff for initialisation
+/**
+ * Registers shutdown functions for database profiling and delayed queries.
+ *
+ * @access private
+ */
+function init_db() {
+ register_shutdown_function('db_delayedexecution_shutdown_hook');
+ register_shutdown_function('db_profiling_shutdown_hook');
+}
-register_elgg_event_handler('boot','system','init_db',0); \ No newline at end of file
+elgg_register_event_handler('init', 'system', 'init_db');
diff --git a/engine/lib/deprecated-1.7.php b/engine/lib/deprecated-1.7.php
new file mode 100644
index 000000000..ee95b5611
--- /dev/null
+++ b/engine/lib/deprecated-1.7.php
@@ -0,0 +1,1164 @@
+<?php
+/**
+ * Get entities with the specified access collection id.
+ *
+ * @deprecated 1.7. Use elgg_get_entities_from_access_id()
+ *
+ * @param int $collection_id ID of collection
+ * @param string $entity_type Type of entities
+ * @param string $entity_subtype Subtype of entities
+ * @param int $owner_guid Guid of owner
+ * @param int $limit Limit of number of entities to return
+ * @param int $offset Skip this many entities
+ * @param string $order_by Column to order by
+ * @param int $site_guid The site guid
+ * @param bool $count Return a count or entities
+ *
+ * @return array
+ */
+function get_entities_from_access_id($collection_id, $entity_type = "", $entity_subtype = "",
+ $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) {
+ // log deprecated warning
+ elgg_deprecated_notice('get_entities_from_access_id() was deprecated by elgg_get_entities()', 1.7);
+
+ if (!$collection_id) {
+ return FALSE;
+ }
+
+ // build the options using given parameters
+ $options = array();
+ $options['limit'] = $limit;
+ $options['offset'] = $offset;
+ $options['count'] = $count;
+
+ if ($entity_type) {
+ $options['type'] = sanitise_string($entity_type);
+ }
+
+ if ($entity_subtype) {
+ $options['subtype'] = $entity_subtype;
+ }
+
+ if ($site_guid) {
+ $options['site_guid'] = $site_guid;
+ }
+
+ if ($order_by) {
+ $options['order_by'] = sanitise_string("e.time_created, $order_by");
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ if ($site_guid) {
+ $options['site_guid'] = $site_guid;
+ }
+
+ $options['access_id'] = $collection_id;
+
+ return elgg_get_entities_from_access_id($options);
+}
+
+/**
+ * @deprecated 1.7
+ */
+function get_entities_from_access_collection($collection_id, $entity_type = "", $entity_subtype = "",
+ $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) {
+
+ elgg_deprecated_notice('get_entities_from_access_collection() was deprecated by elgg_get_entities()', 1.7);
+
+ return get_entities_from_access_id($collection_id, $entity_type, $entity_subtype,
+ $owner_guid, $limit, $offset, $order_by, $site_guid, $count);
+}
+
+/**
+ * Get entities from annotations
+ *
+ * No longer used.
+ *
+ * @deprecated 1.7 Use elgg_get_entities_from_annotations()
+ *
+ * @param mixed $entity_type Type of entity
+ * @param mixed $entity_subtype Subtype of entity
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param int $owner_guid Guid of owner of annotation
+ * @param int $group_guid Guid of group
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by SQL order by string
+ * @param bool $count Count or return entities
+ * @param int $timelower Lower time limit
+ * @param int $timeupper Upper time limit
+ *
+ * @return unknown_type
+ */
+function get_entities_from_annotations($entity_type = "", $entity_subtype = "", $name = "",
+$value = "", $owner_guid = 0, $group_guid = 0, $limit = 10, $offset = 0, $order_by = "asc",
+$count = false, $timelower = 0, $timeupper = 0) {
+ $msg = 'get_entities_from_annotations() is deprecated by elgg_get_entities_from_annotations().';
+ elgg_deprecated_notice($msg, 1.7);
+
+ $options = array();
+
+ if ($entity_type) {
+ $options['types'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtypes'] = $entity_subtype;
+ }
+
+ $options['annotation_names'] = $name;
+
+ if ($value) {
+ $options['annotation_values'] = $value;
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['annotation_owner_guids'] = $owner_guid;
+ } else {
+ $options['annotation_owner_guid'] = $owner_guid;
+ }
+ }
+
+ if ($group_guid) {
+ $options['container_guid'] = $group_guid;
+ }
+
+ if ($limit) {
+ $options['limit'] = $limit;
+ }
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($order_by) {
+ $options['order_by'] = "maxtime $order_by";
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ if ($timelower) {
+ $options['annotation_created_time_lower'] = $timelower;
+ }
+
+ if ($timeupper) {
+ $options['annotation_created_time_upper'] = $timeupper;
+ }
+
+ return elgg_get_entities_from_annotations($options);
+}
+
+/**
+ * Lists entities
+ *
+ * @see elgg_view_entity_list
+ *
+ * @param string $entity_type Type of entity.
+ * @param string $entity_subtype Subtype of entity.
+ * @param string $name Name of annotation.
+ * @param string $value Value of annotation.
+ * @param int $limit Maximum number of results to return.
+ * @param int $owner_guid Owner.
+ * @param int $group_guid Group container. Currently only supported if entity_type is object
+ * @param boolean $asc Whether to list in ascending or descending order (default: desc)
+ * @param boolean $fullview Whether to display the entities in full
+ * @param boolean $listtypetoggle Can 'gallery' view can be displayed (default: no)
+ *
+ * @deprecated 1.7 Use elgg_list_entities_from_annotations()
+ * @return string Formatted entity list
+ */
+function list_entities_from_annotations($entity_type = "", $entity_subtype = "", $name = "",
+$value = "", $limit = 10, $owner_guid = 0, $group_guid = 0, $asc = false, $fullview = true,
+$listtypetoggle = false) {
+
+ $msg = 'list_entities_from_annotations is deprecated by elgg_list_entities_from_annotations';
+ elgg_deprecated_notice($msg, 1.8);
+
+ $options = array();
+
+ if ($entity_type) {
+ $options['types'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtypes'] = $entity_subtype;
+ }
+
+ if ($name) {
+ $options['annotation_names'] = $name;
+ }
+
+ if ($value) {
+ $options['annotation_values'] = $value;
+ }
+
+ if ($limit) {
+ $options['limit'] = $limit;
+ }
+
+ if ($owner_guid) {
+ $options['annotation_owner_guid'] = $owner_guid;
+ }
+
+ if ($group_guid) {
+ $options['container_guid'] = $group_guid;
+ }
+
+ if ($asc) {
+ $options['order_by'] = 'maxtime desc';
+ }
+
+ if ($offset = sanitise_int(get_input('offset', null))) {
+ $options['offset'] = $offset;
+ }
+
+ $options['full_view'] = $fullview;
+ $options['list_type_toggle'] = $listtypetoggle;
+ $options['pagination'] = $pagination;
+
+ return elgg_list_entities_from_annotations($options);
+}
+
+/**
+ * Returns all php files in a directory.
+ *
+ * @deprecated 1.7 Use elgg_get_file_list() instead
+ *
+ * @param string $directory Directory to look in
+ * @param array $exceptions Array of extensions (with .!) to ignore
+ * @param array $list A list files to include in the return
+ *
+ * @return array
+ */
+function get_library_files($directory, $exceptions = array(), $list = array()) {
+ elgg_deprecated_notice('get_library_files() deprecated by elgg_get_file_list()', 1.7);
+ return elgg_get_file_list($directory, $exceptions, $list, array('.php'));
+}
+
+/**
+ * Add action tokens to URL.
+ *
+ * @param string $url URL
+ *
+ * @return string
+ *
+ * @deprecated 1.7 final
+ */
+function elgg_validate_action_url($url) {
+ elgg_deprecated_notice('elgg_validate_action_url() deprecated by elgg_add_action_tokens_to_url().',
+ 1.7);
+
+ return elgg_add_action_tokens_to_url($url);
+}
+
+/**
+ * Does nothing.
+ *
+ * @deprecated 1.7
+ * @return 0
+ */
+function test_ip() {
+ elgg_deprecated_notice('test_ip() was removed because of licensing issues.', 1.7);
+
+ return 0;
+}
+
+/**
+ * Does nothing.
+ *
+ * @return bool
+ * @deprecated 1.7
+ */
+function is_ip_in_array() {
+ elgg_deprecated_notice('is_ip_in_array() was removed because of licensing issues.', 1.7);
+
+ return false;
+}
+
+/**
+ * Returns entities.
+ *
+ * @deprecated 1.7. Use elgg_get_entities().
+ *
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param int $owner_guid Owner GUID
+ * @param string $order_by Order by clause
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param bool $count Return a count or an array of entities
+ * @param int $site_guid Site GUID
+ * @param int $container_guid Container GUID
+ * @param int $timelower Lower time limit
+ * @param int $timeupper Upper time limit
+ *
+ * @return array
+ */
+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) {
+
+ elgg_deprecated_notice('get_entities() was deprecated by elgg_get_entities().', 1.7);
+
+ // rewrite owner_guid to container_guid to emulate old functionality
+ if ($owner_guid != "") {
+ if (is_null($container_guid)) {
+ $container_guid = $owner_guid;
+ $owner_guid = NULL;
+ }
+ }
+
+ $options = array();
+ if ($type) {
+ if (is_array($type)) {
+ $options['types'] = $type;
+ } else {
+ $options['type'] = $type;
+ }
+ }
+
+ if ($subtype) {
+ if (is_array($subtype)) {
+ $options['subtypes'] = $subtype;
+ } else {
+ $options['subtype'] = $subtype;
+ }
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ if ($order_by) {
+ $options['order_by'] = $order_by;
+ }
+
+ // need to pass 0 for all option
+ $options['limit'] = $limit;
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ if ($site_guid) {
+ $options['site_guids'] = $site_guid;
+ }
+
+ if ($container_guid) {
+ $options['container_guids'] = $container_guid;
+ }
+
+ if ($timeupper) {
+ $options['created_time_upper'] = $timeupper;
+ }
+
+ if ($timelower) {
+ $options['created_time_lower'] = $timelower;
+ }
+
+ $r = elgg_get_entities($options);
+ return $r;
+}
+
+/**
+ * Delete multiple entities that match a given query.
+ * This function iterates through and calls delete_entity on
+ * each one, this is somewhat inefficient but lets
+ * the 'delete' event be called for each entity.
+ *
+ * @deprecated 1.7. This is a dangerous function as it defaults to deleting everything.
+ *
+ * @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
+ *
+ * @return false
+ */
+function delete_entities($type = "", $subtype = "", $owner_guid = 0) {
+ elgg_deprecated_notice('delete_entities() was deprecated because no one should use it.', 1.7);
+ return false;
+}
+
+/**
+ * Lists entities.
+ *
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param bool $fullview Show entity full views
+ * @param bool $listtypetoggle Show list type toggle
+ * @param bool $allowedtypes A string of the allowed types
+ *
+ * @return string
+ * @deprecated 1.7. Use elgg_list_registered_entities().
+ */
+function list_registered_entities($owner_guid = 0, $limit = 10, $fullview = true,
+$listtypetoggle = false, $allowedtypes = true) {
+
+ elgg_deprecated_notice('list_registered_entities() was deprecated by elgg_list_registered_entities().', 1.7);
+
+ $options = array();
+
+ // don't want to send anything if not being used.
+ if ($owner_guid) {
+ $options['owner_guid'] = $owner_guid;
+ }
+
+ if ($limit) {
+ $options['limit'] = $limit;
+ }
+
+ if ($allowedtypes) {
+ $options['allowed_types'] = $allowedtypes;
+ }
+
+ // need to send because might be BOOL
+ $options['full_view'] = $fullview;
+ $options['list_type_toggle'] = $listtypetoggle;
+
+ $options['offset'] = get_input('offset', 0);
+
+ return elgg_list_registered_entities($options);
+}
+
+/**
+ * Lists entities
+ *
+ * @deprecated 1.7. Use elgg_list_entities().
+ *
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param bool $fullview Display entity full views?
+ * @param bool $listtypetoggle Allow switching to gallery mode?
+ * @param bool $pagination Show pagination?
+ *
+ * @return string
+ */
+function list_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true,
+$listtypetoggle = false, $pagination = true) {
+
+ elgg_deprecated_notice('list_entities() was deprecated by elgg_list_entities()!', 1.7);
+
+ $options = array();
+
+ // rewrite owner_guid to container_guid to emulate old functionality
+ if ($owner_guid) {
+ $options['container_guids'] = $owner_guid;
+ }
+
+ if ($type) {
+ $options['types'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtypes'] = $subtype;
+ }
+
+ if ($limit) {
+ $options['limit'] = $limit;
+ }
+
+ if ($offset = sanitise_int(get_input('offset', null))) {
+ $options['offset'] = $offset;
+ }
+
+ $options['full_view'] = $fullview;
+ $options['list_type_toggle'] = $listtypetoggle;
+ $options['pagination'] = $pagination;
+
+ return elgg_list_entities($options);
+}
+
+/**
+ * Searches for a group based on a complete or partial name or description
+ *
+ * @param string $criteria The partial or full name or description
+ * @param int $limit Limit of the search.
+ * @param int $offset Offset.
+ * @param string $order_by The order.
+ * @param boolean $count Whether to return the count of results or just the results.
+ *
+ * @return mixed
+ * @deprecated 1.7
+ */
+function search_for_group($criteria, $limit = 10, $offset = 0, $order_by = "", $count = false) {
+ elgg_deprecated_notice('search_for_group() was deprecated by new search plugin.', 1.7);
+ global $CONFIG;
+
+ $criteria = sanitise_string($criteria);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ $order_by = sanitise_string($order_by);
+
+ $access = get_access_sql_suffix("e");
+
+ if ($order_by == "") {
+ $order_by = "e.time_created desc";
+ }
+
+ if ($count) {
+ $query = "SELECT count(e.guid) as total ";
+ } else {
+ $query = "SELECT e.* ";
+ }
+ $query .= "from {$CONFIG->dbprefix}entities e"
+ . " JOIN {$CONFIG->dbprefix}groups_entity g on e.guid=g.guid where ";
+
+ $query .= "(g.name like \"%{$criteria}%\" or g.description like \"%{$criteria}%\")";
+ $query .= " and $access";
+
+ if (!$count) {
+ $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($count = get_data_row($query)) {
+ return $count->total;
+ }
+ }
+ return false;
+}
+
+/**
+ * Returns a formatted list of groups suitable for injecting into search.
+ *
+ * @deprecated 1.7
+ *
+ * @param string $hook Hook name
+ * @param string $user User
+ * @param mixed $returnvalue Previous hook's return value
+ * @param string $tag Tag to search on
+ *
+ * @return string
+ */
+function search_list_groups_by_name($hook, $user, $returnvalue, $tag) {
+ elgg_deprecated_notice('search_list_groups_by_name() was deprecated by new search plugin', 1.7);
+ // Change this to set the number of groups that display on the search page
+ $threshold = 4;
+
+ $object = get_input('object');
+
+ if (!get_input('offset') && (empty($object) || $object == 'group')) {
+ if ($groups = search_for_group($tag, $threshold)) {
+ $countgroups = search_for_group($tag, 0, 0, "", true);
+
+ $return = elgg_view('group/search/startblurb', array('count' => $countgroups, 'tag' => $tag));
+ foreach ($groups as $group) {
+ $return .= elgg_view_entity($group);
+ }
+ $vars = array('count' => $countgroups, 'threshold' => $threshold, 'tag' => $tag);
+ $return .= elgg_view('group/search/finishblurb', $vars);
+ return $return;
+ }
+ }
+}
+
+/**
+ * Displays a list of group objects that have been searched for.
+ *
+ * @see elgg_view_entity_list
+ *
+ * @param string $tag Search criteria
+ * @param int $limit The number of entities to display on a page
+ *
+ * @return string The list in a form suitable to display
+ * @deprecated 1.7
+ */
+function list_group_search($tag, $limit = 10) {
+ elgg_deprecated_notice('list_group_search() was deprecated by new search plugin.', 1.7);
+ $offset = (int) get_input('offset');
+ $limit = (int) $limit;
+ $count = (int) search_for_group($tag, 10, 0, '', true);
+ $entities = search_for_group($tag, $limit, $offset);
+
+ return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, false);
+
+}
+
+/**
+ * Return a list of entities based on the given search criteria.
+ *
+ * @deprecated 1.7 use elgg_get_entities_from_metadata().
+ *
+ * @param mixed $meta_name Metadat name
+ * @param mixed $meta_value Metadata value
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site GUID. 0 for current, -1 for any.
+ * @param bool $count Return a count instead of entities
+ * @param bool $case_sensitive Metadata names case sensitivity
+ *
+ * @return int|array A list of entities, or a count if $count is set to true
+ */
+function get_entities_from_metadata($meta_name, $meta_value = "", $entity_type = "",
+$entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "",
+$site_guid = 0, $count = FALSE, $case_sensitive = TRUE) {
+
+ elgg_deprecated_notice('get_entities_from_metadata() was deprecated by elgg_get_entities_from_metadata()!', 1.7);
+
+ $options = array();
+
+ $options['metadata_names'] = $meta_name;
+
+ if ($meta_value) {
+ $options['metadata_values'] = $meta_value;
+ }
+
+ if ($entity_type) {
+ $options['types'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtypes'] = $entity_subtype;
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ if ($limit) {
+ $options['limit'] = $limit;
+ }
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($order_by) {
+ $options['order_by'];
+ }
+
+ if ($site_guid) {
+ $options['site_guid'];
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ // need to be able to pass false
+ $options['metadata_case_sensitive'] = $case_sensitive;
+
+ return elgg_get_entities_from_metadata($options);
+}
+
+/**
+ * Return entities from metadata
+ *
+ * @deprecated 1.7. Use elgg_get_entities_from_metadata().
+ *
+ * @param mixed $meta_array Metadata name
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site GUID. 0 for current, -1 for any.
+ * @param bool $count Return a count instead of entities
+ * @param bool $meta_array_operator Operator for metadata values
+ *
+ * @return int|array A list of entities, or a count if $count is set to true
+ */
+function get_entities_from_metadata_multi($meta_array, $entity_type = "", $entity_subtype = "",
+$owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0,
+$count = false, $meta_array_operator = 'and') {
+
+ elgg_deprecated_notice('get_entities_from_metadata_multi() was deprecated by elgg_get_entities_from_metadata()!', 1.7);
+
+ if (!is_array($meta_array) || sizeof($meta_array) == 0) {
+ return false;
+ }
+
+ $options = array();
+
+ $options['metadata_name_value_pairs'] = $meta_array;
+
+ if ($entity_type) {
+ $options['types'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtypes'] = $entity_subtype;
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ if ($limit) {
+ $options['limit'] = $limit;
+ }
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($order_by) {
+ $options['order_by'];
+ }
+
+ if ($site_guid) {
+ $options['site_guid'];
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ $options['metadata_name_value_pairs_operator'] = $meta_array_operator;
+
+ return elgg_get_entities_from_metadata($options);
+}
+
+/**
+ * Returns a menu item for use in the children section of add_menu()
+ * This is not currently used in the Elgg core.
+ *
+ * @param string $menu_name The name of the menu item
+ * @param string $menu_url Its URL
+ *
+ * @return stdClass|false Depending on success
+ * @deprecated 1.7
+ */
+function menu_item($menu_name, $menu_url) {
+ elgg_deprecated_notice('menu_item() is deprecated by add_submenu_item', 1.7);
+ return make_register_object($menu_name, $menu_url);
+}
+
+/**
+ * Searches for an object based on a complete or partial title
+ * or description using full text searching.
+ *
+ * IMPORTANT NOTE: With MySQL's default setup:
+ * 1) $criteria must be 4 or more characters long
+ * 2) If $criteria matches greater than 50% of results NO RESULTS ARE RETURNED!
+ *
+ * @param string $criteria The partial or full name or username.
+ * @param int $limit Limit of the search.
+ * @param int $offset Offset.
+ * @param string $order_by The order.
+ * @param boolean $count Whether to return the count of results or just the results.
+ *
+ * @return int|false
+ * @deprecated 1.7
+ */
+function search_for_object($criteria, $limit = 10, $offset = 0, $order_by = "", $count = false) {
+ elgg_deprecated_notice('search_for_object() was deprecated by new search plugin.', 1.7);
+ global $CONFIG;
+
+ $criteria = sanitise_string($criteria);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ $order_by = sanitise_string($order_by);
+ $container_guid = (int)$container_guid;
+
+ $access = get_access_sql_suffix("e");
+
+ if ($order_by == "") {
+ $order_by = "e.time_created desc";
+ }
+
+ if ($count) {
+ $query = "SELECT count(e.guid) as total ";
+ } else {
+ $query = "SELECT e.* ";
+ }
+ $query .= "from {$CONFIG->dbprefix}entities e
+ join {$CONFIG->dbprefix}objects_entity o on e.guid=o.guid
+ where match(o.title,o.description) against ('$criteria') and $access";
+
+ if (!$count) {
+ $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($count = get_data_row($query)) {
+ return $count->total;
+ }
+ }
+ return false;
+}
+
+/**
+ * Returns a formatted list of objects suitable for injecting into search.
+ *
+ * @deprecated 1.7
+ *
+ * @param sting $hook Hook
+ * @param string $user user
+ * @param mixed $returnvalue Previous return value
+ * @param mixed $tag Search term
+ *
+ * @return array
+ */
+function search_list_objects_by_name($hook, $user, $returnvalue, $tag) {
+ elgg_deprecated_notice('search_list_objects_by_name was deprecated by new search plugin.', 1.7);
+
+ // Change this to set the number of users that display on the search page
+ $threshold = 4;
+
+ $object = get_input('object');
+
+ if (!get_input('offset') && (empty($object) || $object == 'user')) {
+ if ($users = search_for_user($tag, $threshold)) {
+ $countusers = search_for_user($tag, 0, 0, "", true);
+
+ $return = elgg_view('user/search/startblurb', array('count' => $countusers, 'tag' => $tag));
+ foreach ($users as $user) {
+ $return .= elgg_view_entity($user);
+ }
+ $return .= elgg_view('user/search/finishblurb',
+ array('count' => $countusers, 'threshold' => $threshold, 'tag' => $tag));
+
+ return $return;
+
+ }
+ }
+}
+
+/**
+ * Return entities from relationships
+ *
+ * @deprecated 1.7 Use elgg_get_entities_from_relationship()
+ *
+ * @param string $relationship The relationship type
+ * @param int $relationship_guid The GUID of the relationship owner
+ * @param bool $inverse_relationship Invert relationship?
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param int $owner_guid Entity owner GUID
+ * @param string $order_by Order by clause
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param bool $count Return a count instead of entities?
+ * @param int $site_guid Site GUID
+ *
+ * @return mixed
+ */
+function get_entities_from_relationship($relationship, $relationship_guid,
+$inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+
+ elgg_deprecated_notice('get_entities_from_relationship() was deprecated by elgg_get_entities_from_relationship()!', 1.7);
+
+ $options = array();
+
+ $options['relationship'] = $relationship;
+ $options['relationship_guid'] = $relationship_guid;
+ $options['inverse_relationship'] = $inverse_relationship;
+
+ if ($type) {
+ $options['types'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtypes'] = $subtype;
+ }
+
+ if ($owner_guid) {
+ $options['owner_guid'] = $owner_guid;
+ }
+
+ $options['limit'] = $limit;
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($order_by) {
+ $options['order_by'];
+ }
+
+ if ($site_guid) {
+ $options['site_guid'];
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ return elgg_get_entities_from_relationship($options);
+}
+
+/**
+ * Searches for a site based on a complete or partial name
+ * or description or url using full text searching.
+ *
+ * IMPORTANT NOTE: With MySQL's default setup:
+ * 1) $criteria must be 4 or more characters long
+ * 2) If $criteria matches greater than 50% of results NO RESULTS ARE RETURNED!
+ *
+ * @param string $criteria The partial or full name or username.
+ * @param int $limit Limit of the search.
+ * @param int $offset Offset.
+ * @param string $order_by The order.
+ * @param boolean $count Whether to return the count of results or just the results.
+ *
+ * @return mixed
+ * @deprecated 1.7
+ */
+function search_for_site($criteria, $limit = 10, $offset = 0, $order_by = "", $count = false) {
+ elgg_deprecated_notice('search_for_site() was deprecated by new search plugin.', 1.7);
+ global $CONFIG;
+
+ $criteria = sanitise_string($criteria);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ $order_by = sanitise_string($order_by);
+
+ $access = get_access_sql_suffix("e");
+
+ if ($order_by == "") {
+ $order_by = "e.time_created desc";
+ }
+
+ if ($count) {
+ $query = "SELECT count(e.guid) as total ";
+ } else {
+ $query = "SELECT e.* ";
+ }
+ $query .= "from {$CONFIG->dbprefix}entities e
+ join {$CONFIG->dbprefix}sites_entity s on e.guid=s.guid
+ where match(s.name, s.description, s.url) against ('$criteria') and $access";
+
+ if (!$count) {
+ $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($count = get_data_row($query)) {
+ return $count->total;
+ }
+ }
+ return false;
+}
+
+/**
+ * Searches for a user based on a complete or partial name or username.
+ *
+ * @param string $criteria The partial or full name or username.
+ * @param int $limit Limit of the search.
+ * @param int $offset Offset.
+ * @param string $order_by The order.
+ * @param boolean $count Whether to return the count of results or just the results.
+ *
+ * @return mixed
+ * @deprecated 1.7
+ */
+function search_for_user($criteria, $limit = 10, $offset = 0, $order_by = "", $count = false) {
+ elgg_deprecated_notice('search_for_user() was deprecated by new search.', 1.7);
+ global $CONFIG;
+
+ $criteria = sanitise_string($criteria);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ $order_by = sanitise_string($order_by);
+
+ $access = get_access_sql_suffix("e");
+
+ if ($order_by == "") {
+ $order_by = "e.time_created desc";
+ }
+
+ if ($count) {
+ $query = "SELECT count(e.guid) as total ";
+ } else {
+ $query = "SELECT e.* ";
+ }
+ $query .= "from {$CONFIG->dbprefix}entities e
+ join {$CONFIG->dbprefix}users_entity u on e.guid=u.guid where ";
+
+ $query .= "(u.name like \"%{$criteria}%\" or u.username like \"%{$criteria}%\")";
+ $query .= " and $access";
+
+ if (!$count) {
+ $query .= " order by $order_by limit $offset, $limit";
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($count = get_data_row($query)) {
+ return $count->total;
+ }
+ }
+ return false;
+}
+
+/**
+ * Displays a list of user objects that have been searched for.
+ *
+ * @see elgg_view_entity_list
+ *
+ * @param string $tag Search criteria
+ * @param int $limit The number of entities to display on a page
+ *
+ * @return string The list in a form suitable to display
+ *
+ * @deprecated 1.7
+ */
+function list_user_search($tag, $limit = 10) {
+ elgg_deprecated_notice('list_user_search() deprecated by new search', 1.7);
+ $offset = (int) get_input('offset');
+ $limit = (int) $limit;
+ $count = (int) search_for_user($tag, 10, 0, '', true);
+ $entities = search_for_user($tag, $limit, $offset);
+
+ return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, false);
+}
+
+/**
+ * Returns a formatted list of users suitable for injecting into search.
+ *
+ * @deprecated 1.7
+ *
+ * @param string $hook Hook name
+ * @param string $user User?
+ * @param mixed $returnvalue Previous hook's return value
+ * @param mixed $tag Tag to search against
+ *
+ * @return void
+ */
+function search_list_users_by_name($hook, $user, $returnvalue, $tag) {
+ elgg_deprecated_notice('search_list_users_by_name() was deprecated by new search', 1.7);
+ // Change this to set the number of users that display on the search page
+ $threshold = 4;
+
+ $object = get_input('object');
+
+ if (!get_input('offset') && (empty($object) || $object == 'user')) {
+ if ($users = search_for_user($tag, $threshold)) {
+ $countusers = search_for_user($tag, 0, 0, "", true);
+
+ $return = elgg_view('user/search/startblurb', array('count' => $countusers, 'tag' => $tag));
+ foreach ($users as $user) {
+ $return .= elgg_view_entity($user);
+ }
+
+ $vars = array('count' => $countusers, 'threshold' => $threshold, 'tag' => $tag);
+ $return .= elgg_view('user/search/finishblurb', $vars);
+ return $return;
+
+ }
+ }
+}
+
+/**
+ * Extend a view
+ *
+ * @deprecated 1.7. Use elgg_extend_view().
+ *
+ * @param string $view The view to extend.
+ * @param string $view_name This view is added to $view
+ * @param int $priority The priority, from 0 to 1000,
+ * to add at (lowest numbers displayed first)
+ * @param string $viewtype Not used
+ *
+ * @return void
+ */
+function extend_view($view, $view_name, $priority = 501, $viewtype = '') {
+ elgg_deprecated_notice('extend_view() was deprecated by elgg_extend_view()!', 1.7);
+ elgg_extend_view($view, $view_name, $priority, $viewtype);
+}
+
+/**
+ * Get views in a dir
+ *
+ * @deprecated 1.7. Use elgg_get_views().
+ *
+ * @param string $dir Dir
+ * @param string $base Base view
+ *
+ * @return array
+ */
+function get_views($dir, $base) {
+ elgg_deprecated_notice('get_views() was deprecated by elgg_get_views()!', 1.7);
+ elgg_get_views($dir, $base);
+}
+
+/**
+ * Constructs and returns a register object.
+ *
+ * @param string $register_name The name of the register
+ * @param mixed $register_value The value of the register
+ * @param array $children_array Optionally, an array of children
+ *
+ * @return false|stdClass Depending on success
+ * @deprecated 1.7 Use {@link add_submenu_item()}
+ */
+function make_register_object($register_name, $register_value, $children_array = array()) {
+ elgg_deprecated_notice('make_register_object() is deprecated by add_submenu_item()', 1.7);
+ if (empty($register_name) || empty($register_value)) {
+ return false;
+ }
+
+ $register = new stdClass;
+ $register->name = $register_name;
+ $register->value = $register_value;
+ $register->children = $children_array;
+
+ return $register;
+}
+
+/**
+ * THIS FUNCTION IS DEPRECATED.
+ *
+ * Delete a object's extra data.
+ *
+ * @todo - this should be removed - was deprecated in 1.5 or earlier
+ *
+ * @param int $guid GUID
+ *
+ * @return 1
+ * @deprecated 1.7
+ */
+function delete_object_entity($guid) {
+ system_message(elgg_echo('deprecatedfunction', array('delete_user_entity')));
+
+ return 1; // Always return that we have deleted one row in order to not break existing code.
+}
+
+/**
+ * THIS FUNCTION IS DEPRECATED.
+ *
+ * Delete a user's extra data.
+ *
+ * @todo remove
+ *
+ * @param int $guid User GUID
+ *
+ * @return 1
+ * @deprecated 1.7
+ */
+function delete_user_entity($guid) {
+ system_message(elgg_echo('deprecatedfunction', array('delete_user_entity')));
+
+ return 1; // Always return that we have deleted one row in order to not break existing code.
+} \ No newline at end of file
diff --git a/engine/lib/deprecated-1.8.php b/engine/lib/deprecated-1.8.php
new file mode 100644
index 000000000..91068d047
--- /dev/null
+++ b/engine/lib/deprecated-1.8.php
@@ -0,0 +1,4820 @@
+<?php
+/**
+ * ***************************************************************************
+ * NOTE: If this is ever removed from Elgg, sites lose the ability to upgrade
+ * from 1.7.x and earlier to the latest version of Elgg without upgrading to
+ * 1.8 first.
+ * ***************************************************************************
+ *
+ * Upgrade the database schema in an ordered sequence.
+ *
+ * Executes all upgrade files in elgg/engine/schema/upgrades/ in sequential order.
+ * Upgrade files must be in the standard Elgg release format of YYYYMMDDII.sql
+ * where II is an incrementor starting from 01.
+ *
+ * Files that are < $version will be ignored.
+ *
+ * @warning Plugin authors should not call this function directly.
+ *
+ * @param int $version The version you are upgrading from in the format YYYYMMDDII.
+ * @param string $fromdir Optional directory to load upgrades from. default: engine/schema/upgrades/
+ * @param bool $quiet If true, suppress all error messages. Only use for the upgrade from <=1.6.
+ *
+ * @return int The number of upgrades run.
+ * @see upgrade.php
+ * @see version.php
+ * @deprecated 1.8 Use PHP upgrades for sql changes.
+ */
+function db_upgrade($version, $fromdir = "", $quiet = FALSE) {
+ global $CONFIG;
+
+ elgg_deprecated_notice('db_upgrade() is deprecated by using PHP upgrades.', 1.8);
+
+ $version = (int) $version;
+
+ if (!$fromdir) {
+ $fromdir = $CONFIG->path . 'engine/schema/upgrades/';
+ }
+
+ $i = 0;
+
+ if ($handle = opendir($fromdir)) {
+ $sqlupgrades = array();
+
+ while ($sqlfile = readdir($handle)) {
+ if (!is_dir($fromdir . $sqlfile)) {
+ if (preg_match('/^([0-9]{10})\.(sql)$/', $sqlfile, $matches)) {
+ $sql_version = (int) $matches[1];
+ if ($sql_version > $version) {
+ $sqlupgrades[] = $sqlfile;
+ }
+ }
+ }
+ }
+
+ asort($sqlupgrades);
+
+ if (sizeof($sqlupgrades) > 0) {
+ foreach ($sqlupgrades as $sqlfile) {
+
+ // hide all errors.
+ if ($quiet) {
+ try {
+ run_sql_script($fromdir . $sqlfile);
+ } catch (DatabaseException $e) {
+ error_log($e->getmessage());
+ }
+ } else {
+ run_sql_script($fromdir . $sqlfile);
+ }
+ $i++;
+ }
+ }
+ }
+
+ return $i;
+}
+
+/**
+ * Lists entities from an access collection
+ *
+ * @deprecated 1.8 Use elgg_list_entities_from_access_id()
+ *
+ * @return str
+ */
+function list_entities_from_access_id($access_id, $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = true, $pagination = true) {
+
+ elgg_deprecated_notice("All list_entities* functions were deprecated in 1.8. Use elgg_list_entities* instead.", 1.8);
+
+ echo elgg_list_entities_from_access_id(array('access_id' => $access_id,
+ 'type' => $entity_type, 'subtype' => $entity_subtype, 'owner_guids' => $owner_guid,
+ 'limit' => $limit, 'full_view' => $fullview, 'list_type_toggle' => $listtypetoggle,
+ 'pagination' => $pagination,));
+}
+
+/**
+ * Registers a particular action in memory
+ *
+ * @deprecated 1.8 Use {@link elgg_register_action()} instead
+ *
+ * @param string $action The name of the action (eg "register", "account/settings/save")
+ * @param boolean $public Can this action be accessed by people not logged into the system?
+ * @param string $filename Optionally, the filename where this action is located
+ * @param boolean $admin_only Whether this action is only available to admin users.
+ */
+function register_action($action, $public = false, $filename = "", $admin_only = false) {
+ elgg_deprecated_notice("register_action() was deprecated by elgg_register_action()", 1.8);
+
+ if ($admin_only) {
+ $access = 'admin';
+ } elseif ($public) {
+ $access = 'public';
+ } else {
+ $access = 'logged_in';
+ }
+
+ return elgg_register_action($action, $filename, $access);
+}
+
+/**
+ * Register an admin page with the admin panel.
+ * This function extends the view "admin/main" with the provided view.
+ * This view should provide a description and either a control or a link to.
+ *
+ * @deprecated 1.8 Extend admin views manually
+ *
+ * Usage:
+ * - To add a control to the main admin panel then extend admin/main
+ * - To add a control to a new page create a page which renders a view admin/subpage
+ * (where subpage is your new page -
+ * nb. some pages already exist that you can extend), extend the main view to point to it,
+ * and add controls to your new view.
+ *
+ * At the moment this is essentially a wrapper around elgg_extend_view().
+ *
+ * @param string $new_admin_view The view associated with the control you're adding
+ * @param string $view The view to extend, by default this is 'admin/main'.
+ * @param int $priority Optional priority to govern the appearance in the list.
+ *
+ * @return void
+ */
+function extend_elgg_admin_page($new_admin_view, $view = 'admin/main', $priority = 500) {
+ elgg_deprecated_notice('extend_elgg_admin_page() does nothing. Extend admin views manually.', 1.8);
+}
+
+/**
+ * Get entities ordered by a mathematical calculation
+ *
+ * @deprecated 1.8 Use elgg_get_entities_from_annotation_calculation()
+ *
+ * @param string $sum What sort of calculation to perform
+ * @param string $entity_type Type of Entity
+ * @param string $entity_subtype Subtype of Entity
+ * @param string $name Name of annotation
+ * @param string $mdname Metadata name
+ * @param string $mdvalue Metadata value
+ * @param int $owner_guid GUID of owner of annotation
+ * @param int $limit Limit of results
+ * @param int $offset Offset of results
+ * @param string $orderdir Order of results
+ * @param bool $count Return count or entities
+ *
+ * @return mixed
+ */
+function get_entities_from_annotations_calculate_x($sum = "sum", $entity_type = "", $entity_subtype = "", $name = "", $mdname = '', $mdvalue = '', $owner_guid = 0, $limit = 10, $offset = 0, $orderdir = 'desc', $count = false) {
+
+ $msg = 'get_entities_from_annotations_calculate_x() is deprecated by elgg_get_entities_from_annotation_calculation().';
+
+ elgg_deprecated_notice($msg, 1.8);
+
+ $options = array();
+
+ $options['calculation'] = $sum;
+
+ if ($entity_type) {
+ $options['types'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtypes'] = $entity_subtype;
+ }
+
+ $options['annotation_names'] = $name;
+
+ if ($mdname) {
+ $options['metadata_names'] = $mdname;
+ }
+
+ if ($mdvalue) {
+ $options['metadata_values'] = $mdvalue;
+ }
+
+ // original function rewrote this to container guid.
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['container_guids'] = $owner_guid;
+ } else {
+ $options['container_guid'] = $owner_guid;
+ }
+ }
+
+ $options['limit'] = $limit;
+ $options['offset'] = $offset;
+
+ $options['order_by'] = "annotation_calculation $orderdir";
+
+ $options['count'] = $count;
+
+ return elgg_get_entities_from_annotation_calculation($options);
+}
+
+/**
+ * Returns entities ordered by the sum of an annotation
+ *
+ * @warning This is function uses sum instead of count. THIS IS SLOW. See #3366.
+ * This should be used when you have annotations with different values and you
+ * want a list of entities ordered by the sum of all of those values.
+ * If you want a list of entities ordered by the number of annotations on each entity,
+ * use __get_entities_from_annotations_calculate_x() and pass 'count' as the first param.
+ *
+ * @deprecated 1.8 Use elgg_get_entities_from_annotation_calculation()
+ *
+ * @param string $entity_type Type of Entity
+ * @param string $entity_subtype Subtype of Entity
+ * @param string $name Name of annotation
+ * @param string $mdname Metadata name
+ * @param string $mdvalue Metadata value
+ * @param int $owner_guid GUID of owner of annotation
+ * @param int $limit Limit of results
+ * @param int $offset Offset of results
+ * @param string $orderdir Order of results
+ * @param bool $count Return count or entities
+ *
+ * @return unknown
+ */
+function get_entities_from_annotation_count($entity_type = "", $entity_subtype = "", $name = "", $mdname = '', $mdvalue = '', $owner_guid = 0, $limit = 10, $offset = 0, $orderdir = 'desc', $count = false) {
+
+ $msg = 'get_entities_from_annotation_count() is deprecated by elgg_get_entities_from_annotation_calculation().';
+
+ elgg_deprecated_notice($msg, 1.8);
+
+ $options = array();
+
+ $options['calculation'] = 'sum';
+
+ if ($entity_type) {
+ $options['types'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtypes'] = $entity_subtype;
+ }
+
+ $options['annotation_names'] = $name;
+
+ if ($mdname) {
+ $options['metadata_names'] = $mdname;
+ }
+
+ if ($mdvalue) {
+ $options['metadata_values'] = $mdvalue;
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ $options['limit'] = $limit;
+ $options['offset'] = $offset;
+
+ $options['order_by'] = "annotation_calculation $orderdir";
+
+ $options['count'] = $count;
+
+ return elgg_get_entities_from_annotation_calculation($options);
+}
+
+/**
+ * Lists entities by the totals of a particular kind of annotation
+ *
+ * @deprecated 1.8 Use elgg_list_entities_from_annotation_calculation()
+ *
+ * @param string $entity_type Type of entity.
+ * @param string $entity_subtype Subtype of entity.
+ * @param string $name Name of annotation.
+ * @param int $limit Maximum number of results to return.
+ * @param int $owner_guid Owner.
+ * @param int $group_guid Group container. Currently only supported if entity_type is object
+ * @param boolean $asc Whether to list in ascending or descending order (default: desc)
+ * @param boolean $fullview Whether to display the entities in full
+ * @param boolean $listtypetoggle Can the 'gallery' view can be displayed (default: no)
+ * @param boolean $pagination Add pagination
+ * @param string $orderdir Order desc or asc
+ *
+ * @return string Formatted entity list
+ */
+function list_entities_from_annotation_count($entity_type = "", $entity_subtype = "", $name = "", $limit = 10, $owner_guid = 0, $group_guid = 0, $asc = false, $fullview = true, $listtypetoggle = false, $pagination = true, $orderdir = 'desc') {
+
+ $msg = 'list_entities_from_annotation_count() is deprecated by elgg_list_entities_from_annotation_calculation().';
+
+ elgg_deprecated_notice($msg, 1.8);
+
+ $options = array();
+
+ $options['calculation'] = 'sum';
+
+ if ($entity_type) {
+ $options['types'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtypes'] = $entity_subtype;
+ }
+
+ $options['annotation_names'] = $name;
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ $options['full_view'] = $fullview;
+
+ $options['list_type_toggle'] = $listtypetoggle;
+
+ $options['pagination'] = $pagination;
+
+ $options['limit'] = $limit;
+
+ $options['order_by'] = "annotation_calculation $orderdir";
+
+ return elgg_get_entities_from_annotation_calculation($options);
+}
+
+/**
+ * Adds an entry in $CONFIG[$register_name][$subregister_name].
+ *
+ * @deprecated 1.8 Use the new menu system.
+ *
+ * This is only used for the site-wide menu. See {@link add_menu()}.
+ *
+ * @param string $register_name The name of the top-level register
+ * @param string $subregister_name The name of the subregister
+ * @param mixed $subregister_value The value of the subregister
+ * @param array $children_array Optionally, an array of children
+ *
+ * @return true|false Depending on success
+ */
+function add_to_register($register_name, $subregister_name, $subregister_value, $children_array = array()) {
+ elgg_deprecated_notice("add_to_register() has been deprecated", 1.8);
+ global $CONFIG;
+
+ if (empty($register_name) || empty($subregister_name)) {
+ return false;
+ }
+
+ if (!isset($CONFIG->registers)) {
+ $CONFIG->registers = array();
+ }
+
+ if (!isset($CONFIG->registers[$register_name])) {
+ $CONFIG->registers[$register_name] = array();
+ }
+
+ $subregister = new stdClass;
+ $subregister->name = $subregister_name;
+ $subregister->value = $subregister_value;
+
+ if (is_array($children_array)) {
+ $subregister->children = $children_array;
+ }
+
+ $CONFIG->registers[$register_name][$subregister_name] = $subregister;
+ return true;
+}
+
+/**
+ * Removes a register entry from $CONFIG[register_name][subregister_name]
+ *
+ * @deprecated 1.8 Use the new menu system.
+ *
+ * This is used to by {@link remove_menu()} to remove site-wide menu items.
+ *
+ * @param string $register_name The name of the top-level register
+ * @param string $subregister_name The name of the subregister
+ *
+ * @return true|false Depending on success
+ * @since 1.7.0
+ */
+function remove_from_register($register_name, $subregister_name) {
+ elgg_deprecated_notice("remove_from_register() has been deprecated", 1.8);
+ global $CONFIG;
+
+ if (empty($register_name) || empty($subregister_name)) {
+ return false;
+ }
+
+ if (!isset($CONFIG->registers)) {
+ return false;
+ }
+
+ if (!isset($CONFIG->registers[$register_name])) {
+ return false;
+ }
+
+ if (isset($CONFIG->registers[$register_name][$subregister_name])) {
+ unset($CONFIG->registers[$register_name][$subregister_name]);
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * If it exists, returns a particular register as an array
+ *
+ * @deprecated 1.8 Use the new menu system
+ *
+ * @param string $register_name The name of the register
+ *
+ * @return array|false Depending on success
+ */
+function get_register($register_name) {
+ elgg_deprecated_notice("get_register() has been deprecated", 1.8);
+ global $CONFIG;
+
+ if ($register_name == 'menu') {
+ // backward compatible code for site menu
+ $menu = $CONFIG->menus['site'];
+ $builder = new ElggMenuBuilder($menu);
+ $menu_items = $builder->getMenu('text');
+ $menu_items = $menu_items['default'];
+
+ $menu = array();
+ foreach ($menu_items as $item) {
+ $subregister = new stdClass;
+ $subregister->name = $item->getText();
+ $subregister->value = $item->getHref();
+ $menu[$subregister->name] = $subregister;
+ }
+ return $menu;
+ }
+
+ if (isset($CONFIG->registers[$register_name])) {
+ return $CONFIG->registers[$register_name];
+ }
+
+ return false;
+}
+
+/**
+ * Deprecated events core function. Code divided between elgg_register_event_handler()
+ * and trigger_elgg_event().
+ *
+ * @deprecated 1.8 Use explicit register/trigger event functions
+ *
+ * @param string $event The type of event (eg 'init', 'update', 'delete')
+ * @param string $object_type The type of object (eg 'system', 'blog', 'user')
+ * @param string $function The name of the function that will handle the event
+ * @param int $priority Priority to call handler. Lower numbers called first (default 500)
+ * @param boolean $call Set to true to call the event rather than add to it (default false)
+ * @param mixed $object Optionally, the object the event is being performed on (eg a user)
+ *
+ * @return true|false Depending on success
+ */
+function events($event = "", $object_type = "", $function = "", $priority = 500, $call = false, $object = null) {
+
+ elgg_deprecated_notice('events() has been deprecated.', 1.8);
+
+ // leaving this here just in case someone was directly calling this internal function
+ if (!$call) {
+ return elgg_register_event_handler($event, $object_type, $function, $priority);
+ } else {
+ return trigger_elgg_event($event, $object_type, $object);
+ }
+}
+
+/**
+ * Alias function for events, that registers a function to a particular kind of event
+ *
+ * @deprecated 1.8 Use elgg_register_event_handler() instead
+ *
+ * @param string $event The event type
+ * @param string $object_type The object type
+ * @param string $function The function name
+ * @return true|false Depending on success
+ */
+function register_elgg_event_handler($event, $object_type, $callback, $priority = 500) {
+ elgg_deprecated_notice("register_elgg_event_handler() was deprecated by elgg_register_event_handler()", 1.8);
+ return elgg_register_event_handler($event, $object_type, $callback, $priority);
+}
+
+/**
+ * Unregisters a function to a particular kind of event
+ *
+ * @deprecated 1.8 Use elgg_unregister_event_handler instead
+ *
+ * @param string $event The event type
+ * @param string $object_type The object type
+ * @param string $function The function name
+ * @since 1.7.0
+ */
+function unregister_elgg_event_handler($event, $object_type, $callback) {
+ elgg_deprecated_notice('unregister_elgg_event_handler => elgg_unregister_event_handler', 1.8);
+ elgg_unregister_event_handler($event, $object_type, $callback);
+}
+
+/**
+ * Alias function for events, that triggers a particular kind of event
+ *
+ * @deprecated 1.8 Use elgg_trigger_event() instead
+ *
+ * @param string $event The event type
+ * @param string $object_type The object type
+ * @param string $function The function name
+ * @return true|false Depending on success
+ */
+function trigger_elgg_event($event, $object_type, $object = null) {
+ elgg_deprecated_notice('trigger_elgg_event() was deprecated by elgg_trigger_event()', 1.8);
+ return elgg_trigger_event($event, $object_type, $object);
+}
+
+/**
+ * Register a function to a plugin hook for a particular entity type, with a given priority.
+ *
+ * @deprecated 1.8 Use elgg_register_plugin_hook_handler() instead
+ *
+ * eg if you want the function "export_user" to be called when the hook "export" for "user" entities
+ * is run, use:
+ *
+ * register_plugin_hook("export", "user", "export_user");
+ *
+ * "all" is a valid value for both $hook and $entity_type. "none" is a valid value for $entity_type.
+ *
+ * The export_user function would then be defined as:
+ *
+ * function export_user($hook, $entity_type, $returnvalue, $params);
+ *
+ * Where $returnvalue is the return value returned by the last function returned by the hook, and
+ * $params is an array containing a set of parameters (or nothing).
+ *
+ * @param string $hook The name of the hook
+ * @param string $entity_type The name of the type of entity (eg "user", "object" etc)
+ * @param string $function The name of a valid function to be run
+ * @param string $priority The priority - 0 is first, 1000 last, default is 500
+ * @return true|false Depending on success
+ */
+function register_plugin_hook($hook, $type, $callback, $priority = 500) {
+ elgg_deprecated_notice("register_plugin_hook() was deprecated by elgg_register_plugin_hook_handler()", 1.8);
+ return elgg_register_plugin_hook_handler($hook, $type, $callback, $priority);
+}
+
+/**
+ * Unregister a function to a plugin hook for a particular entity type
+ *
+ * @deprecated 1.8 Use elgg_unregister_plugin_hook_handler() instead
+ *
+ * @param string $hook The name of the hook
+ * @param string $entity_type The name of the type of entity (eg "user", "object" etc)
+ * @param string $function The name of a valid function to be run
+ * @since 1.7.0
+ */
+function unregister_plugin_hook($hook, $entity_type, $callback) {
+ elgg_deprecated_notice("unregister_plugin_hook() was deprecated by elgg_unregister_plugin_hook_handler()", 1.8);
+ elgg_unregister_plugin_hook_handler($hook, $entity_type, $callback);
+}
+
+/**
+ * Triggers a plugin hook, with various parameters as an array. For example, to provide
+ * a 'foo' hook that concerns an entity of type 'bar', with a parameter called 'param1'
+ * with value 'value1', that by default returns true, you'd call:
+ *
+ * @deprecated 1.8 Use elgg_trigger_plugin_hook() instead
+ *
+ * trigger_plugin_hook('foo', 'bar', array('param1' => 'value1'), true);
+ *
+ * @see register_plugin_hook
+ * @param string $hook The name of the hook to trigger
+ * @param string $entity_type The name of the entity type to trigger it for (or "all", or "none")
+ * @param array $params Any parameters. It's good practice to name the keys, i.e. by using array('name' => 'value', 'name2' => 'value2')
+ * @param mixed $returnvalue An initial return value
+ * @return mixed|null The cumulative return value for the plugin hook functions
+ */
+function trigger_plugin_hook($hook, $type, $params = null, $returnvalue = null) {
+ elgg_deprecated_notice("trigger_plugin_hook() was deprecated by elgg_trigger_plugin_hook()", 1.8);
+ return elgg_trigger_plugin_hook($hook, $type, $params, $returnvalue);
+}
+
+/**
+ * Checks if code is being called from a certain function.
+ *
+ * To use, call this function with the function name (and optional
+ * file location) that it has to be called from, it will either
+ * return true or false.
+ *
+ * e.g.
+ *
+ * function my_secure_function()
+ * {
+ * if (!call_gatekeeper("my_call_function"))
+ * return false;
+ *
+ * ... do secure stuff ...
+ * }
+ *
+ * function my_call_function()
+ * {
+ * // will work
+ * my_secure_function();
+ * }
+ *
+ * function bad_function()
+ * {
+ * // Will not work
+ * my_secure_function();
+ * }
+ *
+ * @param mixed $function The function that this function must have in its call stack,
+ * to test against a method pass an array containing a class and
+ * method name.
+ * @param string $file Optional file that the function must reside in.
+ *
+ * @return bool
+ *
+ * @deprecated 1.8 A neat but pointless function
+ */
+function call_gatekeeper($function, $file = "") {
+ elgg_deprecated_notice("call_gatekeeper() is neat but pointless", 1.8);
+ // Sanity check
+ if (!$function) {
+ return false;
+ }
+
+ // Check against call stack to see if this is being called from the correct location
+ $callstack = debug_backtrace();
+ $stack_element = false;
+
+ foreach ($callstack as $call) {
+ if (is_array($function)) {
+ if ((strcmp($call['class'], $function[0]) == 0) && (strcmp($call['function'], $function[1]) == 0)) {
+ $stack_element = $call;
+ }
+ } else {
+ if (strcmp($call['function'], $function) == 0) {
+ $stack_element = $call;
+ }
+ }
+ }
+
+ if (!$stack_element) {
+ return false;
+ }
+
+ // If file then check that this it is being called from this function
+ if ($file) {
+ $mirror = null;
+
+ if (is_array($function)) {
+ $mirror = new ReflectionMethod($function[0], $function[1]);
+ } else {
+ $mirror = new ReflectionFunction($function);
+ }
+
+ if ((!$mirror) || (strcmp($file, $mirror->getFileName()) != 0)) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * This function checks to see if it is being called at somepoint by a function defined somewhere
+ * on a given path (optionally including subdirectories).
+ *
+ * This function is similar to call_gatekeeper() but returns true if it is being called
+ * by a method or function which has been defined on a given path or by a specified file.
+ *
+ * @param string $path The full path and filename that this function must have
+ * in its call stack If a partial path is given and
+ * $include_subdirs is true, then the function will return
+ * true if called by any function in or below the specified path.
+ * @param bool $include_subdirs Are subdirectories of the path ok, or must you specify an
+ * absolute path and filename.
+ * @param bool $strict_mode If true then the calling method or function must be directly
+ * called by something on $path, if false the whole call stack is
+ * searched.
+ *
+ * @return void
+ *
+ * @deprecated 1.8 A neat but pointless function
+ */
+function callpath_gatekeeper($path, $include_subdirs = true, $strict_mode = false) {
+ elgg_deprecated_notice("callpath_gatekeeper() is neat but pointless", 1.8);
+
+ global $CONFIG;
+
+ $path = sanitise_string($path);
+
+ if ($path) {
+ $callstack = debug_backtrace();
+
+ foreach ($callstack as $call) {
+ $call['file'] = str_replace("\\", "/", $call['file']);
+
+ if ($include_subdirs) {
+ if (strpos($call['file'], $path) === 0) {
+
+ if ($strict_mode) {
+ $callstack[1]['file'] = str_replace("\\", "/", $callstack[1]['file']);
+ if ($callstack[1] === $call) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ } else {
+ if (strcmp($path, $call['file']) == 0) {
+ if ($strict_mode) {
+ if ($callstack[1] === $call) {
+ return true;
+ }
+ } else {
+ return true;
+ }
+ }
+ }
+
+ }
+ return false;
+ }
+
+ if (isset($CONFIG->debug)) {
+ system_message("Gatekeeper'd function called from {$callstack[1]['file']}:" . "{$callstack[1]['line']}\n\nStack trace:\n\n" . print_r($callstack, true));
+ }
+
+ return false;
+}
+
+/**
+ * Returns SQL where clause for owner and containers.
+ *
+ * @deprecated 1.8 Use elgg_get_guid_based_where_sql();
+ *
+ * @param string $table Entity table prefix as defined in SELECT...FROM entities $table
+ * @param NULL|array $owner_guids Owner GUIDs
+ *
+ * @return FALSE|str
+ * @since 1.7.0
+ * @access private
+ */
+function elgg_get_entity_owner_where_sql($table, $owner_guids) {
+ elgg_deprecated_notice('elgg_get_entity_owner_where_sql() is deprecated by elgg_get_guid_based_where_sql().', 1.8);
+
+ return elgg_get_guid_based_where_sql("{$table}.owner_guid", $owner_guids);
+}
+
+/**
+ * Returns SQL where clause for containers.
+ *
+ * @deprecated 1.8 Use elgg_get_guid_based_where_sql();
+ *
+ * @param string $table Entity table prefix as defined in
+ * SELECT...FROM entities $table
+ * @param NULL|array $container_guids Array of container guids
+ *
+ * @return FALSE|string
+ * @since 1.7.0
+ * @access private
+ */
+function elgg_get_entity_container_where_sql($table, $container_guids) {
+ elgg_deprecated_notice('elgg_get_entity_container_where_sql() is deprecated by elgg_get_guid_based_where_sql().', 1.8);
+
+ return elgg_get_guid_based_where_sql("{$table}.container_guid", $container_guids);
+}
+
+/**
+ * Returns SQL where clause for site entities
+ *
+ * @deprecated 1.8 Use elgg_get_guid_based_where_sql()
+ *
+ * @param string $table Entity table prefix as defined in SELECT...FROM entities $table
+ * @param NULL|array $site_guids Array of site guids
+ *
+ * @return FALSE|string
+ * @since 1.7.0
+ * @access private
+ */
+function elgg_get_entity_site_where_sql($table, $site_guids) {
+ elgg_deprecated_notice('elgg_get_entity_site_where_sql() is deprecated by elgg_get_guid_based_where_sql().', 1.8);
+
+ return elgg_get_guid_based_where_sql("{$table}.site_guid", $site_guids);
+}
+
+/**
+ * Return an array of objects in a given container.
+ *
+ * @see get_entities()
+ *
+ * @param int $group_guid The container (defaults to current page owner)
+ * @param string $subtype The subtype
+ * @param int $owner_guid Owner
+ * @param int $site_guid The site
+ * @param string $order_by Order
+ * @param int $limit Limit on number of elements to return, by default 10.
+ * @param int $offset Where to start, by default 0.
+ * @param bool $count Whether to return the entities or a count of them.
+ *
+ * @return array|false
+ * @deprecated 1.8 Use elgg_get_entities() instead
+ */
+function get_objects_in_group($group_guid, $subtype = "", $owner_guid = 0, $site_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = FALSE) {
+ elgg_deprecated_notice("get_objects_in_group was deprected in 1.8. Use elgg_get_entities() instead", 1.8);
+
+ 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;
+ }
+
+ $container_guid = (int)$group_guid;
+ if ($container_guid == 0) {
+ $container_guid = elgg_get_page_owner_guid();
+ }
+
+ $where = array();
+
+ $where[] = "e.type='object'";
+
+ if (!empty($subtype)) {
+ if (!$subtype = get_subtype_id('object', $subtype)) {
+ return FALSE;
+ }
+ $where[] = "e.subtype=$subtype";
+ }
+ if ($owner_guid != "") {
+ if (!is_array($owner_guid)) {
+ $owner_guid = (int)$owner_guid;
+ $where[] = "e.container_guid = '$owner_guid'";
+ } else if (sizeof($owner_guid) > 0) {
+ // Cast every element to the owner_guid array to int
+ $owner_guid = array_map("sanitise_int", $owner_guid);
+ $owner_guid = implode(",", $owner_guid);
+ $where[] = "e.container_guid in ({$owner_guid})";
+ }
+ }
+ if ($site_guid > 0) {
+ $where[] = "e.site_guid = {$site_guid}";
+ }
+
+ if ($container_guid > 0) {
+ $where[] = "e.container_guid = {$container_guid}";
+ }
+
+ if (!$count) {
+ $query = "SELECT * from {$CONFIG->dbprefix}entities e" . " join {$CONFIG->dbprefix}objects_entity o on e.guid=o.guid where ";
+ } else {
+ $query = "SELECT count(e.guid) as total from {$CONFIG->dbprefix}entities e" . " join {$CONFIG->dbprefix}objects_entity o on e.guid=o.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";
+
+ // 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;
+ }
+}
+
+/**
+ * Lists entities that belong to a group.
+ *
+ * @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 bool $fullview Whether or not to display the full view (default: true)
+ * @param bool $listtypetoggle Whether or not to allow gallery view (default: true)
+ * @param bool $pagination Whether to display pagination (default: true)
+ *
+ * @return string List of parsed entities
+ *
+ * @see elgg_list_entities()
+ * @deprecated 1.8 Use elgg_list_entities() instead
+ */
+function list_entities_groups($subtype = "", $owner_guid = 0, $container_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = true, $pagination = true) {
+ elgg_deprecated_notice("list_entities_groups was deprecated in 1.8. Use elgg_list_entities() instead.", 1.8);
+ $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, $listtypetoggle, $pagination);
+}
+
+/**
+ * Get all the entities from metadata from a group.
+ *
+ * @param int $group_guid The ID of the group.
+ * @param mixed $meta_name Metadata name
+ * @param mixed $meta_value Metadata value
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $owner_guid Owner guid
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site GUID. 0 for current, -1 for any
+ * @param bool $count Return count instead of entities
+ *
+ * @return array|false
+ * @deprecated 1.8 Use elgg_get_entities_from_metadata()
+ */
+function get_entities_from_metadata_groups($group_guid, $meta_name, $meta_value = "", $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) {
+ elgg_deprecated_notice("get_entities_from_metadata_groups was deprecated in 1.8.", 1.8);
+ global $CONFIG;
+
+ $meta_n = get_metastring_id($meta_name);
+ $meta_v = get_metastring_id($meta_value);
+
+ $entity_type = sanitise_string($entity_type);
+ $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ if ($order_by == "") {
+ $order_by = "e.time_created desc";
+ }
+ $order_by = sanitise_string($order_by);
+ $site_guid = (int)$site_guid;
+ if (is_array($owner_guid)) {
+ foreach ($owner_guid as $key => $guid) {
+ $owner_guid[$key] = (int)$guid;
+ }
+ } else {
+ $owner_guid = (int)$owner_guid;
+ }
+ if ($site_guid == 0) {
+ $site_guid = $CONFIG->site_guid;
+ }
+
+ $container_guid = (int)$group_guid;
+ if ($container_guid == 0) {
+ $container_guid = elgg_get_page_owner_guid();
+ }
+
+ $where = array();
+
+ if ($entity_type != "") {
+ $where[] = "e.type='$entity_type'";
+ }
+ if ($entity_subtype) {
+ $where[] = "e.subtype=$entity_subtype";
+ }
+ if ($meta_name != "") {
+ $where[] = "m.name_id='$meta_n'";
+ }
+ if ($meta_value != "") {
+ $where[] = "m.value_id='$meta_v'";
+ }
+ if ($site_guid > 0) {
+ $where[] = "e.site_guid = {$site_guid}";
+ }
+ if ($container_guid > 0) {
+ $where[] = "e.container_guid = {$container_guid}";
+ }
+
+ if (is_array($owner_guid)) {
+ $where[] = "e.container_guid in (" . implode(",", $owner_guid) . ")";
+ } else if ($owner_guid > 0) {
+ $where[] = "e.container_guid = {$owner_guid}";
+ }
+
+ if (!$count) {
+ $query = "SELECT distinct e.* ";
+ } else {
+ $query = "SELECT count(e.guid) as total ";
+ }
+
+ $query .= "from {$CONFIG->dbprefix}entities e" . " JOIN {$CONFIG->dbprefix}metadata m on e.guid = m.entity_guid " . " JOIN {$CONFIG->dbprefix}objects_entity o on e.guid = o.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 limit $offset, $limit"; // Add order and limit
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($row = get_data_row($query)) {
+ return $row->total;
+ }
+ }
+ return false;
+}
+
+/**
+ * As get_entities_from_metadata_groups() but with multiple entities.
+ *
+ * @param int $group_guid The ID of the group.
+ * @param array $meta_array Array of 'name' => 'value' pairs
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site GUID. 0 for current, -1 for any
+ * @param bool $count Return count of entities instead of entities
+ *
+ * @return int|array List of ElggEntities, or the total number if count is set to false
+ * @deprecated 1.8 Use elgg_get_entities_from_metadata()
+ */
+function get_entities_from_metadata_groups_multi($group_guid, $meta_array, $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) {
+ elgg_deprecated_notice("get_entities_from_metadata_groups_multi was deprecated in 1.8.", 1.8);
+
+ global $CONFIG;
+
+ if (!is_array($meta_array) || sizeof($meta_array) == 0) {
+ return false;
+ }
+
+ $where = array();
+
+ $mindex = 1;
+ $join = "";
+ foreach ($meta_array as $meta_name => $meta_value) {
+ $meta_n = get_metastring_id($meta_name);
+ $meta_v = get_metastring_id($meta_value);
+ $join .= " JOIN {$CONFIG->dbprefix}metadata m{$mindex} on e.guid = m{$mindex}.entity_guid" . " JOIN {$CONFIG->dbprefix}objects_entity o on e.guid = o.guid ";
+
+ if ($meta_name != "") {
+ $where[] = "m{$mindex}.name_id='$meta_n'";
+ }
+
+ if ($meta_value != "") {
+ $where[] = "m{$mindex}.value_id='$meta_v'";
+ }
+
+ $mindex++;
+ }
+
+ $entity_type = sanitise_string($entity_type);
+ $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ if ($order_by == "") {
+ $order_by = "e.time_created desc";
+ }
+ $order_by = sanitise_string($order_by);
+ $owner_guid = (int)$owner_guid;
+
+ $site_guid = (int)$site_guid;
+ if ($site_guid == 0) {
+ $site_guid = $CONFIG->site_guid;
+ }
+
+ //$access = get_access_list();
+
+ if ($entity_type != "") {
+ $where[] = "e.type = '{$entity_type}'";
+ }
+
+ if ($entity_subtype) {
+ $where[] = "e.subtype = {$entity_subtype}";
+ }
+
+ if ($site_guid > 0) {
+ $where[] = "e.site_guid = {$site_guid}";
+ }
+
+ if ($owner_guid > 0) {
+ $where[] = "e.owner_guid = {$owner_guid}";
+ }
+
+ if ($container_guid > 0) {
+ $where[] = "e.container_guid = {$container_guid}";
+ }
+
+ if ($count) {
+ $query = "SELECT count(e.guid) as total ";
+ } else {
+ $query = "SELECT distinct e.* ";
+ }
+
+ $query .= " from {$CONFIG->dbprefix}entities e {$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 limit $offset, $limit"; // Add order and limit
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($count = get_data_row($query)) {
+ return $count->total;
+ }
+ }
+ return false;
+}
+
+/**
+ * List items within a given geographic area.
+ *
+ * @param real $lat Latitude
+ * @param real $long Longitude
+ * @param real $radius The radius
+ * @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 bool $fullview Whether or not to display the full view (default: true)
+ * @param bool $listtypetoggle Whether or not to allow gallery view
+ * @param bool $navigation Display pagination? Default: true
+ *
+ * @return string A viewable list of entities
+ * @deprecated 1.8 Use elgg_get_entities_from_location()
+ */
+function list_entities_in_area($lat, $long, $radius, $type = "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) {
+ elgg_deprecated_notice('list_entities_in_area() was deprecated. Use elgg_list_entities_from_location()', 1.8);
+
+ $options = array();
+
+ $options['latitude'] = $lat;
+ $options['longitude'] = $long;
+ $options['distance'] = $radius;
+
+ if ($type) {
+ $options['types'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtypes'] = $subtype;
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ $options['limit'] = $limit;
+
+ $options['full_view'] = $fullview;
+ $options['list_type_toggle'] = $listtypetoggle;
+ $options['pagination'] = $pagination;
+
+ return elgg_list_entities_from_location($options);
+}
+
+/**
+ * List entities in a given location
+ *
+ * @param string $location Location
+ * @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 bool $fullview Whether or not to display the full view (default: true)
+ * @param bool $listtypetoggle Whether or not to allow gallery view
+ * @param bool $navigation Display pagination? Default: true
+ *
+ * @return string A viewable list of entities
+ * @deprecated 1.8 Use elgg_list_entities_from_location()
+ */
+function list_entities_location($location, $type = "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) {
+ elgg_deprecated_notice('list_entities_location() was deprecated. Use elgg_list_entities_from_metadata()', 1.8);
+
+ return list_entities_from_metadata('location', $location, $type, $subtype, $owner_guid, $limit, $fullview, $listtypetoggle, $navigation);
+}
+
+/**
+ * Return entities within a given geographic area.
+ *
+ * @param float $lat Latitude
+ * @param float $long Longitude
+ * @param float $radius The radius
+ * @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 Count entities
+ * @param int $site_guid Site GUID. 0 for current, -1 for any
+ * @param int|array $container_guid Container GUID
+ *
+ * @return array A list of entities.
+ * @deprecated 1.8 Use elgg_get_entities_from_location()
+ */
+function get_entities_in_area($lat, $long, $radius, $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = NULL) {
+ elgg_deprecated_notice('get_entities_in_area() was deprecated by elgg_get_entities_from_location()!', 1.8);
+
+ $options = array();
+
+ $options['latitude'] = $lat;
+ $options['longitude'] = $long;
+ $options['distance'] = $radius;
+
+ // set container_guid to owner_guid to emulate old functionality
+ if ($owner_guid != "") {
+ if (is_null($container_guid)) {
+ $container_guid = $owner_guid;
+ }
+ }
+
+ if ($type) {
+ $options['types'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtypes'] = $subtype;
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ if ($container_guid) {
+ if (is_array($container_guid)) {
+ $options['container_guids'] = $container_guid;
+ } else {
+ $options['container_guid'] = $container_guid;
+ }
+ }
+
+ $options['limit'] = $limit;
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($order_by) {
+ $options['order_by'];
+ }
+
+ if ($site_guid) {
+ $options['site_guid'];
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ return elgg_get_entities_from_location($options);
+}
+
+/**
+ * Return a list of entities suitable for display based on the given search criteria.
+ *
+ * @see elgg_view_entity_list
+ *
+ * @deprecated 1.8 Use elgg_list_entities_from_metadata
+ *
+ * @param mixed $meta_name Metadata name to search on
+ * @param mixed $meta_value The value to match, optionally
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Number of entities to display per page
+ * @param bool $fullview WDisplay the full view (default: true)
+ * @param bool $listtypetoggle Allow users to toggle to the gallery view. Default: true
+ * @param bool $pagination Display pagination? Default: true
+ * @param bool $case_sensitive Case sensitive metadata names?
+ *
+ * @return string
+ *
+ * @return string A list of entities suitable for display
+ */
+function list_entities_from_metadata($meta_name, $meta_value = "", $entity_type = ELGG_ENTITIES_ANY_VALUE, $entity_subtype = ELGG_ENTITIES_ANY_VALUE, $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = true, $pagination = true, $case_sensitive = true) {
+
+ elgg_deprecated_notice('list_entities_from_metadata() was deprecated by elgg_list_entities_from_metadata()!', 1.8);
+
+ $offset = (int)get_input('offset');
+ $limit = (int)$limit;
+ $options = array(
+ 'metadata_name' => $meta_name,
+ 'metadata_value' => $meta_value,
+ 'type' => $entity_type,
+ 'subtype' => $entity_subtype,
+ 'limit' => $limit,
+ 'offset' => $offset,
+ 'count' => TRUE,
+ 'metadata_case_sensitive' => $case_sensitive
+ );
+
+ // previous function allowed falsy $owner_guid for anything
+ if ($owner_guid) {
+ $options['owner_guid'] = $owner_guid;
+ }
+
+ $count = elgg_get_entities_from_metadata($options);
+
+ $options['count'] = FALSE;
+ $entities = elgg_get_entities_from_metadata($options);
+
+ return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $listtypetoggle, $pagination);
+}
+
+/**
+ * Returns a viewable list of entities based on the given search criteria.
+ *
+ * @see elgg_view_entity_list
+ *
+ * @param array $meta_array Array of 'name' => 'value' pairs
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param bool $fullview WDisplay the full view (default: true)
+ * @param bool $listtypetoggle Allow users to toggle to the gallery view. Default: true
+ * @param bool $pagination Display pagination? Default: true
+ *
+ * @return string List of ElggEntities suitable for display
+ *
+ * @deprecated 1.8 Use elgg_list_entities_from_metadata() instead
+ */
+function list_entities_from_metadata_multi($meta_array, $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $listtypetoggle = true, $pagination = true) {
+ elgg_deprecated_notice(elgg_echo('deprecated:function', array(
+ 'list_entities_from_metadata_multi', 'elgg_get_entities_from_metadata')), 1.8);
+
+ $offset = (int)get_input('offset');
+ $limit = (int)$limit;
+ $count = get_entities_from_metadata_multi($meta_array, $entity_type, $entity_subtype, $owner_guid, $limit, $offset, "", $site_guid, true);
+ $entities = get_entities_from_metadata_multi($meta_array, $entity_type, $entity_subtype, $owner_guid, $limit, $offset, "", $site_guid, false);
+
+ return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $listtypetoggle, $pagination);
+}
+
+/**
+ * Deprecated by elgg_register_menu_item(). Set $menu_name to 'page'.
+ *
+ * @see elgg_register_menu_item()
+ * @deprecated 1.8 Use the new menu system
+ *
+ * @param string $label The label
+ * @param string $link The link
+ * @param string $group The group to store item in
+ * @param boolean $onclick Add a confirmation when clicked?
+ * @param boolean $selected Is menu item selected
+ *
+ * @return bool
+ */
+function add_submenu_item($label, $link, $group = 'default', $onclick = false, $selected = NULL) {
+ elgg_deprecated_notice('add_submenu_item was deprecated by elgg_register_menu_item', 1.8);
+
+ // submenu items were added in the page setup hook usually by checking
+ // the context. We'll pass in the current context here, which will
+ // emulate that effect.
+ // if context == 'main' (default) it probably means they always wanted
+ // the menu item to show up everywhere.
+ $context = elgg_get_context();
+
+ if ($context == 'main') {
+ $context = 'all';
+ }
+
+ $item = array('name' => $label, 'text' => $label, 'href' => $link, 'context' => $context,
+ 'section' => $group,);
+
+ if ($selected) {
+ $item['selected'] = true;
+ }
+
+ if ($onclick) {
+ $js = "onclick=\"javascript:return confirm('" . elgg_echo('deleteconfirm') . "')\"";
+ $item['vars'] = array('js' => $js);
+ }
+
+ return elgg_register_menu_item('page', $item);
+}
+
+/**
+ * Remove an item from submenu by label
+ *
+ * @deprecated 1.8 Use the new menu system
+ * @see elgg_unregister_menu_item()
+ *
+ * @param string $label The item label
+ * @param string $group The submenu group (default "a")
+ * @return bool whether the item was removed or not
+ * @since 1.7.8
+ */
+function remove_submenu_item($label, $group = 'a') {
+ elgg_deprecated_notice('remove_submenu_item was deprecated by elgg_unregister_menu_item', 1.8);
+
+ return elgg_unregister_menu_item('page', $label);
+}
+
+/**
+ * Use elgg_view_menu(). Set $menu_name to 'owner_block'.
+ *
+ * @see elgg_view_menu()
+ * @deprecated 1.8 Use the new menu system. elgg_view_menu()
+ *
+ * @return string
+ */
+function get_submenu() {
+ elgg_deprecated_notice("get_submenu() has been deprecated by elgg_view_menu()", 1.8);
+ return elgg_view_menu('owner_block', array('entity' => $owner,
+ 'class' => 'elgg-menu-owner-block',));
+}
+
+/**
+ * Adds an item to the site-wide menu.
+ *
+ * You can obtain the menu array by calling {@link get_register('menu')}
+ *
+ * @param string $menu_name The name of the menu item
+ * @param string $menu_url The URL of the page
+ * @param array $menu_children Optionally, an array of submenu items (not used)
+ * @param string $context (not used)
+ *
+ * @return true|false Depending on success
+ * @deprecated 1.8 use elgg_register_menu_item() for the menu 'site'
+ */
+function add_menu($menu_name, $menu_url, $menu_children = array(), $context = "") {
+ elgg_deprecated_notice('add_menu() deprecated by elgg_register_menu_item()', 1.8);
+
+ return elgg_register_menu_item('site', array('name' => $menu_name, 'text' => $menu_name,
+ 'href' => $menu_url,));
+}
+
+/**
+ * Removes an item from the menu register
+ *
+ * @param string $menu_name The name of the menu item
+ *
+ * @return true|false Depending on success
+ * @deprecated 1.8 Use the new menu system
+ */
+function remove_menu($menu_name) {
+ elgg_deprecated_notice("remove_menu() deprecated by elgg_unregister_menu_item()", 1.8);
+ return elgg_unregister_menu_item('site', $menu_name);
+}
+
+/**
+ * When given a title, returns a version suitable for inclusion in a URL
+ *
+ * @param string $title The title
+ *
+ * @return string The optimised title
+ * @deprecated 1.8 Use elgg_get_friendly_title()
+ */
+function friendly_title($title) {
+ elgg_deprecated_notice('friendly_title was deprecated by elgg_get_friendly_title', 1.8);
+ return elgg_get_friendly_title($title);
+}
+
+/**
+ * Displays a UNIX timestamp in a friendly way (eg "less than a minute ago")
+ *
+ * @param int $time A UNIX epoch timestamp
+ *
+ * @return string The friendly time
+ * @deprecated 1.8 Use elgg_view_friendly_time()
+ */
+function friendly_time($time) {
+ elgg_deprecated_notice('friendly_time was deprecated by elgg_view_friendly_time', 1.8);
+ return elgg_view_friendly_time($time);
+}
+
+/**
+ * Filters a string into an array of significant words
+ *
+ * @deprecated 1.8 Don't use this.
+ *
+ * @param string $string A string
+ *
+ * @return array
+ */
+function filter_string($string) {
+ elgg_deprecated_notice('filter_string() was deprecated!', 1.8);
+
+ // Convert it to lower and trim
+ $string = strtolower($string);
+ $string = trim($string);
+
+ // Remove links and email addresses
+ // match protocol://address/path/file.extension?some=variable&another=asf%
+ $string = preg_replace("/\s([a-zA-Z]+:\/\/[a-z][a-z0-9\_\.\-]*[a-z]{2,6}" . "[a-zA-Z0-9\/\*\-\?\&\%\=]*)([\s|\.|\,])/iu", " ", $string);
+
+ // match www.something.domain/path/file.extension?some=variable&another=asf%
+ $string = preg_replace("/\s(www\.[a-z][a-z0-9\_\.\-]*[a-z]{2,6}" . "[a-zA-Z0-9\/\*\-\?\&\%\=]*)([\s|\.|\,])/iu", " ", $string);
+
+ // match name@address
+ $string = preg_replace("/\s([a-zA-Z][a-zA-Z0-9\_\.\-]*[a-zA-Z]" . "*\@[a-zA-Z][a-zA-Z0-9\_\.\-]*[a-zA-Z]{2,6})([\s|\.|\,])/iu", " ", $string);
+
+ // Sanitise the string; remove unwanted characters
+ $string = preg_replace('/\W/ui', ' ', $string);
+
+ // Explode it into an array
+ $terms = explode(' ', $string);
+
+ // Remove any blacklist terms
+ //$terms = array_filter($terms, 'remove_blacklist');
+
+ return $terms;
+}
+
+/**
+ * Returns true if the word in $input is considered significant
+ *
+ * @deprecated 1.8 Don't use this.
+ *
+ * @param string $input A word
+ *
+ * @return true|false
+ */
+function remove_blacklist($input) {
+ elgg_deprecated_notice('remove_blacklist() was deprecated!', 1.8);
+
+ global $CONFIG;
+
+ if (!is_array($CONFIG->wordblacklist)) {
+ return $input;
+ }
+
+ if (strlen($input) < 3 || in_array($input, $CONFIG->wordblacklist)) {
+ return false;
+ }
+
+ return true;
+}
+
+/**
+ * Gets the guid of the entity that owns the current page.
+ *
+ * @deprecated 1.8 Use elgg_get_page_owner_guid()
+ *
+ * @return int The current page owner guid (0 if none).
+ */
+function page_owner() {
+ elgg_deprecated_notice('page_owner() was deprecated by elgg_get_page_owner_guid().', 1.8);
+ return elgg_get_page_owner_guid();
+}
+
+/**
+ * Gets the owner entity for the current page.
+ *
+ * @deprecated 1.8 Use elgg_get_page_owner_entity()
+ * @return ElggEntity|false The current page owner or false if none.
+ */
+function page_owner_entity() {
+ elgg_deprecated_notice('page_owner_entity() was deprecated by elgg_get_page_owner_entity().', 1.8);
+ return elgg_get_page_owner_entity();
+}
+
+/**
+ * Registers a page owner handler function
+ *
+ * @param string $functionname The callback function
+ *
+ * @deprecated 1.8 Use the 'page_owner', 'system' plugin hook
+ * @return void
+ */
+function add_page_owner_handler($functionname) {
+ elgg_deprecated_notice("add_page_owner_handler() was deprecated by the plugin hook 'page_owner', 'system'.", 1.8);
+}
+
+/**
+ * Set a page owner entity
+ *
+ * @param int $entitytoset The GUID of the entity
+ *
+ * @deprecated 1.8 Use elgg_set_page_owner_guid()
+ * @return void
+ */
+function set_page_owner($entitytoset = -1) {
+ elgg_deprecated_notice('set_page_owner() was deprecated by elgg_set_page_owner_guid().', 1.8);
+ elgg_set_page_owner_guid($entitytoset);
+}
+
+/**
+ * Sets the functional context of a page
+ *
+ * @deprecated 1.8 Use elgg_set_context()
+ *
+ * @param string $context The context of the page
+ *
+ * @return mixed Either the context string, or false on failure
+ */
+function set_context($context) {
+ elgg_deprecated_notice('set_context() was deprecated by elgg_set_context().', 1.8);
+ elgg_set_context($context);
+ if (empty($context)) {
+ return false;
+ }
+ return $context;
+}
+
+/**
+ * Returns the functional context of a page
+ *
+ * @deprecated 1.8 Use elgg_get_context()
+ *
+ * @return string The context, or 'main' if no context has been provided
+ */
+function get_context() {
+ elgg_deprecated_notice('get_context() was deprecated by elgg_get_context().', 1.8);
+ return elgg_get_context();
+
+ // @todo - used to set context based on calling script
+ // $context = get_plugin_name(true)
+}
+
+/**
+ * Returns a list of plugins to load, in the order that they should be loaded.
+ *
+ * @deprecated 1.8 Use elgg_get_plugin_ids_in_dir() or elgg_get_plugins()
+ *
+ * @return array List of plugins
+ */
+function get_plugin_list() {
+ elgg_deprecated_notice('get_plugin_list() is deprecated by elgg_get_plugin_ids_in_dir() or elgg_get_plugins()', 1.8);
+
+ $plugins = elgg_get_plugins('any');
+
+ $list = array();
+ if ($plugins) {
+ foreach ($plugins as $i => $plugin) {
+ // in <=1.7 this returned indexed by multiples of 10.
+ // uh...sure...why not.
+ $index = ($i + 1) * 10;
+ $list[$index] = $plugin->getID();
+ }
+ }
+
+ return $list;
+}
+
+/**
+ * Regenerates the list of known plugins and saves it to the current site
+ *
+ * Important: You should regenerate simplecache and the viewpath cache after executing this function
+ * otherwise you may experience view display artifacts. Do this with the following code:
+ *
+ * elgg_regenerate_simplecache();
+ * elgg_reset_system_cache();
+ *
+ * @deprecated 1.8 Use elgg_generate_plugin_entities() and elgg_set_plugin_priorities()
+ *
+ * @param array $pluginorder Optionally, a list of existing plugins and their orders
+ *
+ * @return array The new list of plugins and their orders
+ */
+function regenerate_plugin_list($pluginorder = FALSE) {
+ $msg = 'regenerate_plugin_list() is (sorta) deprecated by elgg_generate_plugin_entities() and'
+ . ' elgg_set_plugin_priorities().';
+ elgg_deprecated_notice($msg, 1.8);
+
+ // they're probably trying to set it?
+ if ($pluginorder) {
+ if (elgg_generate_plugin_entities()) {
+ // sort the plugins by the index numerically since we used
+ // weird indexes in the old system.
+ ksort($pluginorder, SORT_NUMERIC);
+ return elgg_set_plugin_priorities($pluginorder);
+ }
+ return false;
+ } else {
+ // they're probably trying to regenerate from disk?
+ return elgg_generate_plugin_entities();
+ }
+}
+
+/**
+ * Get the name of the most recent plugin to be called in the
+ * call stack (or the plugin that owns the current page, if any).
+ *
+ * i.e., if the last plugin was in /mod/foobar/, get_plugin_name would return foo_bar.
+ *
+ * @deprecated 1.8 Use elgg_get_calling_plugin_id()
+ *
+ * @param boolean $mainfilename If set to true, this will instead determine the
+ * context from the main script filename called by
+ * the browser. Default = false.
+ *
+ * @return string|false Plugin name, or false if no plugin name was called
+ */
+function get_plugin_name($mainfilename = false) {
+ elgg_deprecated_notice('get_plugin_name() is deprecated by elgg_get_calling_plugin_id()', 1.8);
+
+ return elgg_get_calling_plugin_id($mainfilename);
+}
+
+/**
+ * Load and parse a plugin manifest from a plugin XML file.
+ *
+ * @example plugins/manifest.xml Example 1.8-style manifest file.
+ *
+ * @deprecated 1.8 Use ElggPlugin->getManifest()
+ *
+ * @param string $plugin Plugin name.
+ * @return array of values
+ */
+function load_plugin_manifest($plugin) {
+ elgg_deprecated_notice('load_plugin_manifest() is deprecated by ElggPlugin->getManifest()', 1.8);
+
+ $xml_file = elgg_get_plugins_path() . "$plugin/manifest.xml";
+
+ try {
+ $manifest = new ElggPluginManifest($xml_file, $plugin);
+ } catch(Exception $e) {
+ return false;
+ }
+
+ return $manifest->getManifest();
+}
+
+/**
+ * This function checks a plugin manifest 'elgg_version' value against the current install
+ * returning TRUE if the elgg_version is >= the current install's version.
+ *
+ * @deprecated 1.8 Use ElggPlugin->canActivate()
+ *
+ * @param string $manifest_elgg_version_string The build version (eg 2009010201).
+ * @return bool
+ */
+function check_plugin_compatibility($manifest_elgg_version_string) {
+ elgg_deprecated_notice('check_plugin_compatibility() is deprecated by ElggPlugin->canActivate()', 1.8);
+
+ $version = get_version();
+
+ if (strpos($manifest_elgg_version_string, '.') === false) {
+ // Using version
+ $req_version = (int)$manifest_elgg_version_string;
+
+ return ($version >= $req_version);
+ }
+
+ return false;
+}
+
+/**
+ * Shorthand function for finding the plugin settings.
+ *
+ * @deprecated 1.8 Use elgg_get_calling_plugin_entity() or elgg_get_plugin_from_id()
+ *
+ * @param string $plugin_id Optional plugin id, if not specified
+ * then it is detected from where you are calling.
+ *
+ * @return mixed
+ */
+function find_plugin_settings($plugin_id = null) {
+ elgg_deprecated_notice('find_plugin_setting() is deprecated by elgg_get_calling_plugin_entity() or elgg_get_plugin_from_id()', 1.8);
+ if ($plugin_id) {
+ return elgg_get_plugin_from_id($plugin_id);
+ } else {
+ return elgg_get_calling_plugin_entity();
+ }
+}
+
+/**
+ * Return an array of installed plugins.
+ *
+ * @deprecated 1.8 use elgg_get_plugins()
+ *
+ * @param string $status any|enabled|disabled
+ * @return array
+ */
+function get_installed_plugins($status = 'all') {
+ global $CONFIG;
+
+ elgg_deprecated_notice('get_installed_plugins() was deprecated by elgg_get_plugins()', 1.8);
+
+ $plugins = elgg_get_plugins($status);
+
+ if (!$plugins) {
+ return array();
+ }
+
+ $installed_plugins = array();
+
+ foreach ($plugins as $plugin) {
+ if (!$plugin->isValid()) {
+ continue;
+ }
+
+ $include = true;
+
+ if ($status == 'enabled' && !$plugin->isActive()) {
+ $include = false;
+ } elseif ($status == 'disabled' && $plugin->isActive()) {
+ $include = true;
+ }
+
+ if ($include) {
+ $installed_plugins[$plugin->getID()] = array(
+ 'active' => $plugin->isActive(),
+ 'manifest' => $plugin->getManifest()->getManifest()
+ );
+ }
+ }
+
+ return $installed_plugins;
+}
+
+/**
+ * Enable a plugin for a site (default current site)
+ *
+ * Important: You should regenerate simplecache and the viewpath cache after executing this function
+ * otherwise you may experience view display artifacts. Do this with the following code:
+ *
+ * elgg_regenerate_simplecache();
+ * elgg_reset_system_cache();
+ *
+ * @deprecated 1.8 Use ElggPlugin->activate()
+ *
+ * @param string $plugin The plugin name.
+ * @param int $site_guid The site id, if not specified then this is detected.
+ *
+ * @return array
+ * @throws InvalidClassException
+ */
+function enable_plugin($plugin, $site_guid = null) {
+ elgg_deprecated_notice('enable_plugin() was deprecated by ElggPlugin->activate()', 1.8);
+
+ $plugin = sanitise_string($plugin);
+
+ $site_guid = (int) $site_guid;
+ if (!$site_guid) {
+ $site = get_config('site');
+ $site_guid = $site->guid;
+ }
+
+ try {
+ $plugin = new ElggPlugin($plugin);
+ } catch(Exception $e) {
+ return false;
+ }
+
+ if (!$plugin->canActivate($site_guid)) {
+ return false;
+ }
+
+ return $plugin->activate($site_guid);
+}
+
+/**
+ * Disable a plugin for a site (default current site)
+ *
+ * Important: You should regenerate simplecache and the viewpath cache after executing this function
+ * otherwise you may experience view display artifacts. Do this with the following code:
+ *
+ * elgg_regenerate_simplecache();
+ * elgg_reset_system_cache();
+ *
+ * @deprecated 1.8 Use ElggPlugin->deactivate()
+ *
+ * @param string $plugin The plugin name.
+ * @param int $site_guid The site id, if not specified then this is detected.
+ *
+ * @return bool
+ * @throws InvalidClassException
+ */
+function disable_plugin($plugin, $site_guid = 0) {
+ elgg_deprecated_notice('disable_plugin() was deprecated by ElggPlugin->deactivate()', 1.8);
+
+ $plugin = sanitise_string($plugin);
+
+ $site_guid = (int) $site_guid;
+ if (!$site_guid) {
+ $site = get_config('site');
+ $site_guid = $site->guid;
+ }
+
+ try {
+ $plugin = new ElggPlugin($plugin);
+ } catch(Exception $e) {
+ return false;
+ }
+
+ return $plugin->deactivate($site_guid);
+}
+
+/**
+ * Return whether a plugin is enabled or not.
+ *
+ * @deprecated 1.8 Use elgg_is_active_plugin()
+ *
+ * @param string $plugin The plugin name.
+ * @param int $site_guid The site id, if not specified then this is detected.
+ *
+ * @return bool
+ */
+function is_plugin_enabled($plugin, $site_guid = 0) {
+ elgg_deprecated_notice('is_plugin_enabled() was deprecated by elgg_is_active_plugin()', 1.8);
+ return elgg_is_active_plugin($plugin, $site_guid);
+}
+
+/**
+ * Get entities based on their private data.
+ *
+ * @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 Return a count of entities
+ * @param int $site_guid The site to get entities for. 0 for current, -1 for any
+ * @param mixed $container_guid The container(s) GUIDs
+ *
+ * @return array A list of entities.
+ * @deprecated 1.8 Use elgg_get_entities_from_private_settings()
+ */
+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) {
+ elgg_deprecated_notice('get_entities_from_private_setting() was deprecated by elgg_get_entities_from_private_setting()!', 1.8);
+
+ $options = array();
+
+ $options['private_setting_name'] = $name;
+ $options['private_setting_value'] = $value;
+
+ // set container_guid to owner_guid to emulate old functionality
+ if ($owner_guid != "") {
+ if (is_null($container_guid)) {
+ $container_guid = $owner_guid;
+ }
+ }
+
+ if ($type) {
+ $options['types'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtypes'] = $subtype;
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ if ($container_guid) {
+ if (is_array($container_guid)) {
+ $options['container_guids'] = $container_guid;
+ } else {
+ $options['container_guid'] = $container_guid;
+ }
+ }
+
+ $options['limit'] = $limit;
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($order_by) {
+ $options['order_by'];
+ }
+
+ if ($site_guid) {
+ $options['site_guid'];
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ return elgg_get_entities_from_private_settings($options);
+}
+
+/**
+ * Get entities based on their private data by multiple keys.
+ *
+ * @param string $name The name of the setting
+ * @param mixed $type Entity type
+ * @param string $subtype Entity subtype
+ * @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 bool $count Count entities
+ * @param int $site_guid Site GUID. 0 for current, -1 for any.
+ * @param mixed $container_guid Container GUID
+ *
+ * @return array A list of entities.
+ * @deprecated 1.8 Use elgg_get_entities_from_private_settings()
+ */
+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) {
+
+ elgg_deprecated_notice('get_entities_from_private_setting_multi() was deprecated by elgg_get_entities_from_private_settings()!', 1.8);
+
+ $options = array();
+
+ $pairs = array();
+ foreach ($name as $setting_name => $setting_value) {
+ $pairs[] = array('name' => $setting_name, 'value' => $setting_value);
+ }
+ $options['private_setting_name_value_pairs'] = $pairs;
+
+ // set container_guid to owner_guid to emulate old functionality
+ if ($owner_guid != "") {
+ if (is_null($container_guid)) {
+ $container_guid = $owner_guid;
+ }
+ }
+
+ if ($type) {
+ $options['types'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtypes'] = $subtype;
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ if ($container_guid) {
+ if (is_array($container_guid)) {
+ $options['container_guids'] = $container_guid;
+ } else {
+ $options['container_guid'] = $container_guid;
+ }
+ }
+
+ $options['limit'] = $limit;
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($order_by) {
+ $options['order_by'];
+ }
+
+ if ($site_guid) {
+ $options['site_guid'];
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ return elgg_get_entities_from_private_settings($options);
+}
+
+/**
+ * Returns a viewable list of entities by relationship
+ *
+ * @see elgg_view_entity_list
+ *
+ * @deprecated 1.8 Use elgg_list_entities_from_relationship()
+ *
+ * @param string $relationship The relationship eg "friends_of"
+ * @param int $relationship_guid The guid of the entity to use query
+ * @param bool $inverse_relationship Reverse the normal function of the query to instead say "give me all entities for whome $relationship_guid is a $relationship of"
+ * @param string $type The type of entity (eg 'object')
+ * @param string $subtype The entity subtype
+ * @param int $owner_guid The owner (default: all)
+ * @param int $limit The number of entities to display on a page
+ * @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 Whether to display pagination (default: true)
+ * @param bool $order_by SQL order by clause
+ * @return string The viewable list of entities
+ */
+function list_entities_from_relationship($relationship, $relationship_guid,
+$inverse_relationship = false, $type = ELGG_ENTITIES_ANY_VALUE,
+$subtype = ELGG_ENTITIES_ANY_VALUE, $owner_guid = 0, $limit = 10,
+$fullview = true, $listtypetoggle = false, $pagination = true, $order_by = '') {
+
+ elgg_deprecated_notice("list_entities_from_relationship was deprecated by elgg_list_entities_from_relationship()!", 1.8);
+ return elgg_list_entities_from_relationship(array(
+ 'relationship' => $relationship,
+ 'relationship_guid' => $relationship_guid,
+ 'inverse_relationship' => $inverse_relationship,
+ 'type' => $type,
+ 'subtype' => $subtype,
+ 'owner_guid' => $owner_guid,
+ 'order_by' => $order_by,
+ 'limit' => $limit,
+ 'full_view' => $fullview,
+ 'list_type_toggle' => $listtypetoggle,
+ 'pagination' => $pagination,
+ ));
+}
+
+/**
+ * Gets the number of entities by a the number of entities related to them in a particular way.
+ * This is a good way to get out the users with the most friends, or the groups with the
+ * most members.
+ *
+ * @deprecated 1.8 Use elgg_get_entities_from_relationship_count()
+ *
+ * @param string $relationship The relationship eg "friends_of"
+ * @param bool $inverse_relationship Inverse relationship owners
+ * @param string $type The type of entity (default: all)
+ * @param string $subtype The entity subtype (default: all)
+ * @param int $owner_guid The owner of the entities (default: none)
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param bool $count Return a count instead of entities
+ * @param int $site_guid Site GUID
+ *
+ * @return array|int|false An array of entities, or the number of entities, or false on failure
+ */
+function get_entities_by_relationship_count($relationship, $inverse_relationship = true, $type = "",
+$subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+ elgg_deprecated_notice('get_entities_by_relationship_count() is deprecated by elgg_get_entities_from_relationship_count()', 1.8);
+
+ $options = array();
+
+ $options['relationship'] = $relationship;
+
+ // this used to default to true, which is wrong.
+ // flip it for the new function
+ $options['inverse_relationship'] = !$inverse_relationship;
+
+ if ($type) {
+ $options['types'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtypes'] = $subtype;
+ }
+
+ if ($owner_guid) {
+ $options['owner_guid'] = $owner_guid;
+ }
+
+ $options['limit'] = $limit;
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($site_guid) {
+ $options['site_guid'];
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ return elgg_get_entities_from_relationship_count($options);
+}
+
+/**
+ * Displays a human-readable list of entities
+ *
+ * @deprecated 1.8 Use elgg_list_entities_from_relationship_count()
+ *
+ * @param string $relationship The relationship eg "friends_of"
+ * @param bool $inverse_relationship Inverse relationship owners
+ * @param string $type The type of entity (eg 'object')
+ * @param string $subtype The entity subtype
+ * @param int $owner_guid The owner (default: all)
+ * @param int $limit The number of entities to display on a page
+ * @param bool $fullview Whether or not to display the full view (default: true)
+ * @param bool $listtypetoggle Whether or not to allow gallery view
+ * @param bool $pagination Whether to display pagination (default: true)
+ *
+ * @return string The viewable list of entities
+ */
+function list_entities_by_relationship_count($relationship, $inverse_relationship = true,
+$type = "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true,
+$listtypetoggle = false, $pagination = true) {
+
+ elgg_deprecated_notice('list_entities_by_relationship_count() was deprecated by elgg_list_entities_from_relationship_count()', 1.8);
+
+ $options = array();
+
+ $options['relationship'] = $relationship;
+
+ // this used to default to true, which is wrong.
+ // flip it for the new function
+ $options['inverse_relationship'] = !$inverse_relationship;
+
+ if ($type) {
+ $options['types'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtypes'] = $subtype;
+ }
+
+ if ($owner_guid) {
+ $options['owner_guid'] = $owner_guid;
+ }
+
+ $options['limit'] = $limit;
+
+ $options['full_view'] = $fullview;
+
+ return elgg_list_entities_from_relationship_count($options);
+}
+
+/**
+ * Gets the number of entities by a the number of entities related to
+ * them in a particular way also constrained by metadata.
+ *
+ * @deprecated 1.8 Use elgg_get_entities_from_relationship()
+ *
+ * @param string $relationship The relationship eg "friends_of"
+ * @param int $relationship_guid The guid of the entity to use query
+ * @param bool $inverse_relationship Inverse relationship owner
+ * @param String $meta_name The metadata name
+ * @param String $meta_value The metadata value
+ * @param string $type The type of entity (default: all)
+ * @param string $subtype The entity subtype (default: all)
+ * @param int $owner_guid The owner of the entities (default: none)
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param bool $count Return a count instead of entities
+ * @param int $site_guid Site GUID
+ *
+ * @return array|int|false An array of entities, or the number of entities, or false on failure
+ */
+function get_entities_from_relationships_and_meta($relationship, $relationship_guid,
+$inverse_relationship = false, $meta_name = "", $meta_value = "", $type = "",
+$subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+
+ elgg_deprecated_notice('get_entities_from_relationship_and_meta() was deprecated by elgg_get_entities_from_relationship()!', 1.7);
+
+ $options = array();
+
+ $options['relationship'] = $relationship;
+ $options['relationship_guid'] = $relationship_guid;
+ $options['inverse_relationship'] = $inverse_relationship;
+
+ if ($meta_value) {
+ $options['values'] = $meta_value;
+ }
+
+ if ($entity_type) {
+ $options['types'] = $entity_type;
+ }
+
+ if ($type) {
+ $options['types'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtypes'] = $subtype;
+ }
+
+ if ($owner_guid) {
+ $options['owner_guid'] = $owner_guid;
+ }
+
+ if ($limit) {
+ $options['limit'] = $limit;
+ }
+
+ if ($offset) {
+ $options['offset'] = $offset;
+ }
+
+ if ($order_by) {
+ $options['order_by'];
+ }
+
+ if ($site_guid) {
+ $options['site_guid'];
+ }
+
+ if ($count) {
+ $options['count'] = $count;
+ }
+
+ return elgg_get_entities_from_relationship($options);
+}
+
+
+/**
+ * Retrieves items from the river. All parameters are optional.
+ *
+ * @param int|array $subject_guid Acting entity to restrict to. Default: all
+ * @param int|array $object_guid Entity being acted on to restrict to. Default: all
+ * @param string $subject_relationship If set to a relationship type, this will use
+ * $subject_guid as the starting point and set the
+ * subjects to be all users this
+ * entity has this relationship with (eg 'friend').
+ * Default: blank
+ * @param string $type The type of entity to restrict to. Default: all
+ * @param string $subtype The subtype of entity to restrict to. Default: all
+ * @param string $action_type The type of river action to restrict to. Default: all
+ * @param int $limit The number of items to retrieve. Default: 20
+ * @param int $offset The page offset. Default: 0
+ * @param int $posted_min The minimum time period to look at. Default: none
+ * @param int $posted_max The maximum time period to look at. Default: none
+ *
+ * @return array|false Depending on success
+ * @deprecated 1.8 Use elgg_get_river()
+ */
+function get_river_items($subject_guid = 0, $object_guid = 0, $subject_relationship = '',
+$type = '', $subtype = '', $action_type = '', $limit = 20, $offset = 0, $posted_min = 0,
+$posted_max = 0) {
+ elgg_deprecated_notice("get_river_items deprecated by elgg_get_river", 1.8);
+
+ $options = array();
+
+ if ($subject_guid) {
+ $options['subject_guid'] = $subject_guid;
+ }
+
+ if ($object_guid) {
+ $options['object_guid'] = $object_guid;
+ }
+
+ if ($subject_relationship) {
+ $options['relationship'] = $subject_relationship;
+ unset($options['subject_guid']);
+ $options['relationship_guid'] = $subject_guid;
+ }
+
+ if ($type) {
+ $options['type'] = $type;
+ }
+
+ if ($subtype) {
+ $options['subtype'] = $subtype;
+ }
+
+ if ($action_type) {
+ $options['action_type'] = $action_type;
+ }
+
+ $options['limit'] = $limit;
+ $options['offset'] = $offset;
+
+ if ($posted_min) {
+ $options['posted_time_lower'] = $posted_min;
+ }
+
+ if ($posted_max) {
+ $options['posted_time_upper'] = $posted_max;
+ }
+
+ return elgg_get_river($options);
+}
+
+/**
+ * Returns a human-readable version of the river.
+ *
+ * @param int|array $subject_guid Acting entity to restrict to. Default: all
+ * @param int|array $object_guid Entity being acted on to restrict to. Default: all
+ * @param string $subject_relationship If set to a relationship type, this will use
+ * $subject_guid as the starting point and set
+ * the subjects to be all users this entity has this
+ * relationship with (eg 'friend'). Default: blank
+ * @param string $type The type of entity to restrict to. Default: all
+ * @param string $subtype The subtype of entity to restrict to. Default: all
+ * @param string $action_type The type of river action to restrict to. Default: all
+ * @param int $limit The number of items to retrieve. Default: 20
+ * @param int $posted_min The minimum time period to look at. Default: none
+ * @param int $posted_max The maximum time period to look at. Default: none
+ * @param bool $pagination Show pagination?
+ *
+ * @return string Human-readable river.
+ * @deprecated 1.8 Use elgg_list_river()
+ */
+function elgg_view_river_items($subject_guid = 0, $object_guid = 0, $subject_relationship = '',
+$type = '', $subtype = '', $action_type = '', $limit = 20, $posted_min = 0,
+$posted_max = 0, $pagination = true) {
+ elgg_deprecated_notice("elgg_view_river_items deprecated for elgg_list_river", 1.8);
+
+ $river_items = get_river_items($subject_guid, $object_guid, $subject_relationship,
+ $type, $subtype, $action_type, $limit + 1, $posted_min, $posted_max);
+
+ // Get input from outside world and sanitise it
+ $offset = (int) get_input('offset', 0);
+
+ // view them
+ $params = array(
+ 'items' => $river_items,
+ 'count' => count($river_items),
+ 'offset' => $offset,
+ 'limit' => $limit,
+ 'pagination' => $pagination,
+ 'list-class' => 'elgg-list-river',
+ );
+
+ return elgg_view('page/components/list', $params);
+}
+
+/**
+ * Construct and execute the query required for the activity stream.
+ *
+ * @deprecated 1.8 This is outdated and uses the systemlog table instead of the river table.
+ * Don't use it.
+ */
+function get_activity_stream_data($limit = 10, $offset = 0, $type = "", $subtype = "",
+$owner_guid = "", $owner_relationship = "") {
+ elgg_deprecated_notice("get_activity_stream_data was deprecated", 1.8);
+
+ global $CONFIG;
+
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+
+ if ($type) {
+ if (!is_array($type)) {
+ $type = array(sanitise_string($type));
+ } else {
+ foreach ($type as $k => $v) {
+ $type[$k] = sanitise_string($v);
+ }
+ }
+ }
+
+ if ($subtype) {
+ if (!is_array($subtype)) {
+ $subtype = array(sanitise_string($subtype));
+ } else {
+ foreach ($subtype as $k => $v) {
+ $subtype[$k] = sanitise_string($v);
+ }
+ }
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ foreach ($owner_guid as $k => $v) {
+ $owner_guid[$k] = (int)$v;
+ }
+ } else {
+ $owner_guid = array((int)$owner_guid);
+ }
+ }
+
+ $owner_relationship = sanitise_string($owner_relationship);
+
+ // Get a list of possible views
+ $activity_events = array();
+ $activity_views = array_merge(elgg_view_tree('activity', 'default'),
+ elgg_view_tree('river', 'default'));
+
+ $done = array();
+
+ foreach ($activity_views as $view) {
+ $fragments = explode('/', $view);
+ $tmp = explode('/', $view, 2);
+ $tmp = $tmp[1];
+
+ if ((isset($fragments[0])) && (($fragments[0] == 'river') || ($fragments[0] == 'activity'))
+ && (!in_array($tmp, $done))) {
+
+ if (isset($fragments[1])) {
+ $f = array();
+ for ($n = 1; $n < count($fragments); $n++) {
+ $val = sanitise_string($fragments[$n]);
+ switch($n) {
+ case 1: $key = 'type'; break;
+ case 2: $key = 'subtype'; break;
+ case 3: $key = 'event'; break;
+ }
+ $f[$key] = $val;
+ }
+
+ // Filter result based on parameters
+ $add = true;
+ if ($type) {
+ if (!in_array($f['type'], $type)) {
+ $add = false;
+ }
+ }
+ if (($add) && ($subtype)) {
+ if (!in_array($f['subtype'], $subtype)) {
+ $add = false;
+ }
+ }
+ if (($add) && ($event)) {
+ if (!in_array($f['event'], $event)) {
+ $add = false;
+ }
+ }
+
+ if ($add) {
+ $activity_events[] = $f;
+ }
+ }
+
+ $done[] = $tmp;
+ }
+ }
+
+ $n = 0;
+ foreach ($activity_events as $details) {
+ // Get what we're talking about
+ if ($details['subtype'] == 'default') {
+ $details['subtype'] = '';
+ }
+
+ if (($details['type']) && ($details['event'])) {
+ if ($n > 0) {
+ $obj_query .= " or ";
+ }
+
+ $access = "";
+ if ($details['type'] != 'relationship') {
+ $access = " and " . get_access_sql_suffix('sl');
+ }
+
+ $obj_query .= "( sl.object_type='{$details['type']}'
+ AND sl.object_subtype='{$details['subtype']}'
+ AND sl.event='{$details['event']}' $access )";
+
+ $n++;
+ }
+ }
+
+ // User
+ if ((count($owner_guid)) && ($owner_guid[0] != 0)) {
+ $user = " and sl.performed_by_guid in (" . implode(',', $owner_guid) . ")";
+
+ if ($owner_relationship) {
+ $friendsarray = "";
+ if ($friends = elgg_get_entities_from_relationship(array(
+ 'relationship' => $owner_relationship,
+ 'relationship_guid' => $owner_guid[0],
+ 'inverse_relationship' => FALSE,
+ 'type' => 'user',
+ 'subtype' => $subtype,
+ 'limit' => false))
+ ) {
+
+ $friendsarray = array();
+ foreach ($friends as $friend) {
+ $friendsarray[] = $friend->getGUID();
+ }
+
+ $user = " and sl.performed_by_guid in (" . implode(',', $friendsarray) . ")";
+ }
+ }
+ }
+
+ $query = "SELECT sl.* FROM {$CONFIG->dbprefix}system_log sl
+ WHERE 1 $user AND ($obj_query)
+ ORDER BY sl.time_created desc limit $offset, $limit";
+ return get_data($query);
+}
+
+/**
+ * Perform standard authentication with a given username and password.
+ * Returns an ElggUser object for use with login.
+ *
+ * @see login
+ *
+ * @param string $username The username, optionally (for standard logins)
+ * @param string $password The password, optionally (for standard logins)
+ *
+ * @return ElggUser|false The authenticated user object, or false on failure.
+ *
+ * @deprecated 1.8 Use elgg_authenticate
+ */
+function authenticate($username, $password) {
+ elgg_deprecated_notice('authenticate() has been deprecated for elgg_authenticate()', 1.8);
+ $pam = new ElggPAM('user');
+ $credentials = array('username' => $username, 'password' => $password);
+ $result = $pam->authenticate($credentials);
+ if ($result) {
+ return get_user_by_username($username);
+ }
+ return false;
+}
+
+
+/**
+ * Get the members of a site.
+ *
+ * @param int $site_guid Site GUID
+ * @param int $limit User GUID
+ * @param int $offset Offset
+ *
+ * @return mixed
+ * @deprecated 1.8 Use ElggSite::getMembers()
+ */
+function get_site_members($site_guid, $limit = 10, $offset = 0) {
+ elgg_deprecated_notice("get_site_members() deprecated.
+ Use ElggSite::getMembers()", 1.8);
+
+ $site = get_entity($site_guid);
+ if ($site) {
+ return $site->getMembers($limit, $offset);
+ }
+
+ return false;
+}
+
+/**
+ * Display a list of site members
+ *
+ * @param int $site_guid The GUID of the site
+ * @param int $limit The number of members to display on a page
+ * @param bool $fullview Whether or not to display the full view (default: true)
+ *
+ * @return string A displayable list of members
+ * @deprecated 1.8 Use ElggSite::listMembers()
+ */
+function list_site_members($site_guid, $limit = 10, $fullview = true) {
+ elgg_deprecated_notice("list_site_members() deprecated.
+ Use ElggSite::listMembers()", 1.8);
+
+ $options = array(
+ 'limit' => $limit,
+ 'full_view' => $full_view,
+ );
+
+ $site = get_entity($site_guid);
+ if ($site) {
+ return $site->listMembers($options);
+ }
+
+ return '';
+}
+
+
+/**
+ * Add a collection to a site.
+ *
+ * @param int $site_guid Site GUID
+ * @param int $collection_guid Collection GUID
+ *
+ * @return mixed
+ * @deprecated 1.8 Don't use this.
+ */
+function add_site_collection($site_guid, $collection_guid) {
+ elgg_deprecated_notice("add_site_collection has been deprecated", 1.8);
+ global $CONFIG;
+
+ $site_guid = (int)$site_guid;
+ $collection_guid = (int)$collection_guid;
+
+ return add_entity_relationship($collection_guid, "member_of_site", $site_guid);
+}
+
+/**
+ * Remove a collection from a site.
+ *
+ * @param int $site_guid Site GUID
+ * @param int $collection_guid Collection GUID
+ *
+ * @return mixed
+ * @deprecated 1.8 Don't use this.
+ */
+function remove_site_collection($site_guid, $collection_guid) {
+ elgg_deprecated_notice("remove_site_collection has been deprecated", 1.8);
+ $site_guid = (int)$site_guid;
+ $collection_guid = (int)$collection_guid;
+
+ return remove_entity_relationship($collection_guid, "member_of_site", $site_guid);
+}
+
+/**
+ * Get the collections belonging to a site.
+ *
+ * @param int $site_guid Site GUID
+ * @param string $subtype Subtype
+ * @param int $limit Limit
+ * @param int $offset Offset
+ *
+ * @return mixed
+ * @deprecated 1.8 Don't use this.
+ */
+function get_site_collections($site_guid, $subtype = "", $limit = 10, $offset = 0) {
+ elgg_deprecated_notice("get_site_collections has been deprecated", 1.8);
+ $site_guid = (int)$site_guid;
+ $subtype = sanitise_string($subtype);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+
+ // collection isn't a valid type. This won't work.
+ return elgg_get_entities_from_relationship(array(
+ 'relationship' => 'member_of_site',
+ 'relationship_guid' => $site_guid,
+ 'inverse_relationship' => TRUE,
+ 'type' => 'collection',
+ 'subtype' => $subtype,
+ 'limit' => $limit,
+ 'offset' => $offset
+ ));
+}
+
+/**
+ * Get an array of tags with weights for use with the output/tagcloud view.
+ *
+ * @deprecated 1.8 Use elgg_get_tags().
+ *
+ * @param int $threshold Get the threshold of minimum number of each tags to
+ * bother with (ie only show tags where there are more
+ * than $threshold occurances)
+ * @param int $limit Number of tags to return
+ * @param string $metadata_name Optionally, the name of the field you want to grab for
+ * @param string $entity_type Optionally, the entity type ('object' etc)
+ * @param string $entity_subtype The entity subtype, optionally
+ * @param int $owner_guid The GUID of the tags owner, optionally
+ * @param int $site_guid Optionally, the site to restrict to (default is the current site)
+ * @param int $start_ts Optionally specify a start timestamp for tags used to
+ * generate cloud.
+ * @param int $end_ts Optionally specify an end timestamp for tags used to generate cloud
+ *
+ * @return array|false Array of objects with ->tag and ->total values, or false on failure
+ */
+function get_tags($threshold = 1, $limit = 10, $metadata_name = "", $entity_type = "object",
+$entity_subtype = "", $owner_guid = "", $site_guid = -1, $start_ts = "", $end_ts = "") {
+
+ elgg_deprecated_notice('get_tags() has been replaced by elgg_get_tags()', 1.8);
+
+ if (is_array($metadata_name)) {
+ return false;
+ }
+
+ $options = array();
+ if ($metadata_name === '') {
+ $options['tag_names'] = array();
+ } else {
+ $options['tag_names'] = array($metadata_name);
+ }
+
+ $options['threshold'] = $threshold;
+ $options['limit'] = $limit;
+
+ // rewrite owner_guid to container_guid to emulate old functionality
+ $container_guid = $owner_guid;
+ if ($container_guid) {
+ $options['container_guids'] = $container_guid;
+ }
+
+ if ($entity_type) {
+ $options['type'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtype'] = $entity_subtype;
+ }
+
+ if ($site_guid != -1) {
+ $options['site_guids'] = $site_guid;
+ }
+
+ if ($end_ts) {
+ $options['created_time_upper'] = $end_ts;
+ }
+
+ if ($start_ts) {
+ $options['created_time_lower'] = $start_ts;
+ }
+
+ $r = elgg_get_tags($options);
+ return $r;
+}
+
+/**
+ * Loads and displays a tagcloud given particular criteria.
+ *
+ * @deprecated 1.8 use elgg_view_tagcloud()
+ *
+ * @param int $threshold Get the threshold of minimum number of each tags
+ * to bother with (ie only show tags where there are
+ * more than $threshold occurances)
+ * @param int $limit Number of tags to return
+ * @param string $metadata_name Optionally, the name of the field you want to grab for
+ * @param string $entity_type Optionally, the entity type ('object' etc)
+ * @param string $entity_subtype The entity subtype, optionally
+ * @param int $owner_guid The GUID of the tags owner, optionally
+ * @param int $site_guid Optionally, the site to restrict to (default is the current site)
+ * @param int $start_ts Optionally specify a start timestamp for tags used to
+ * generate cloud.
+ * @param int $end_ts Optionally specify an end timestamp for tags used to generate
+ * cloud.
+ *
+ * @return string The HTML (or other, depending on view type) of the tagcloud.
+ */
+function display_tagcloud($threshold = 1, $limit = 10, $metadata_name = "", $entity_type = "object",
+$entity_subtype = "", $owner_guid = "", $site_guid = -1, $start_ts = "", $end_ts = "") {
+
+ elgg_deprecated_notice('display_tagcloud() was deprecated by elgg_view_tagcloud()!', 1.8);
+
+ $tags = get_tags($threshold, $limit, $metadata_name, $entity_type,
+ $entity_subtype, $owner_guid, $site_guid, $start_ts, $end_ts);
+
+ return elgg_view('output/tagcloud', array(
+ 'value' => $tags,
+ 'type' => $entity_type,
+ 'subtype' => $entity_subtype,
+ ));
+}
+
+
+/**
+ * Obtains a list of objects owned by a user
+ *
+ * @param int $user_guid The GUID of the owning user
+ * @param string $subtype Optionally, the subtype of objects
+ * @param int $limit The number of results to return (default 10)
+ * @param int $offset Indexing offset, if any
+ * @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 false|array An array of ElggObjects or false, depending on success
+ * @deprecated 1.8 Use elgg_get_entities() instead
+ */
+function get_user_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10,
+$offset = 0, $timelower = 0, $timeupper = 0) {
+ elgg_deprecated_notice("get_user_objects() was deprecated in favor of elgg_get_entities()", 1.8);
+ $ntt = elgg_get_entities(array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'owner_guid' => $user_guid,
+ 'limit' => $limit,
+ 'offset' => $offset,
+ 'container_guid' => $user_guid,
+ 'created_time_lower' => $timelower,
+ 'created_time_upper' => $timeupper
+ ));
+ return $ntt;
+}
+
+/**
+ * Counts the objects (optionally of a particular subtype) owned by a user
+ *
+ * @param int $user_guid The GUID of the owning user
+ * @param string $subtype Optionally, the subtype of objects
+ * @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 int The number of objects the user owns (of this subtype)
+ * @deprecated 1.8 Use elgg_get_entities() instead
+ */
+function count_user_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $timelower = 0,
+$timeupper = 0) {
+ elgg_deprecated_notice("count_user_objects() was deprecated in favor of elgg_get_entities()", 1.8);
+ $total = elgg_get_entities(array(
+ 'type' => 'object',
+ 'subtype' => $subtype,
+ 'owner_guid' => $user_guid,
+ 'count' => TRUE,
+ 'container_guid' => $user_guid,
+ 'created_time_lower' => $timelower,
+ 'created_time_upper' => $timeupper
+ ));
+ return $total;
+}
+
+/**
+ * Displays a list of user objects of a particular subtype, with navigation.
+ *
+ * @see elgg_view_entity_list
+ *
+ * @param int $user_guid The GUID of the user
+ * @param string $subtype The object subtype
+ * @param int $limit The number of entities to display on a page
+ * @param bool $fullview Whether or not to display the full view (default: true)
+ * @param bool $listtypetoggle Whether or not to allow gallery view (default: true)
+ * @param bool $pagination Whether to display pagination (default: true)
+ * @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 string The list in a form suitable to display
+ * @deprecated 1.8 Use elgg_list_entities() instead
+ */
+function list_user_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10,
+$fullview = true, $listtypetoggle = true, $pagination = true, $timelower = 0, $timeupper = 0) {
+ elgg_deprecated_notice("list_user_objects() was deprecated in favor of elgg_list_entities()", 1.8);
+
+ $offset = (int) get_input('offset');
+ $limit = (int) $limit;
+ $count = (int) count_user_objects($user_guid, $subtype, $timelower, $timeupper);
+ $entities = get_user_objects($user_guid, $subtype, $limit, $offset, $timelower, $timeupper);
+
+ return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $listtypetoggle,
+ $pagination);
+}
+
+
+/**
+ * Get user objects by an array of metadata
+ *
+ * @param int $user_guid The GUID of the owning user
+ * @param string $subtype Optionally, the subtype of objects
+ * @param array $metadata An array of metadata
+ * @param int $limit The number of results to return (default 10)
+ * @param int $offset Indexing offset, if any
+ *
+ * @return false|array An array of ElggObjects or false, depending on success
+ * @deprecated 1.8 Use elgg_get_entities_from_metadata() instead
+ */
+function get_user_objects_by_metadata($user_guid, $subtype = "", $metadata = array(),
+$limit = 0, $offset = 0) {
+ elgg_deprecated_notice("get_user_objects_by_metadata() was deprecated in favor of elgg_get_entities_from_metadata()", 1.8);
+ return get_entities_from_metadata_multi($metadata, "object", $subtype, $user_guid,
+ $limit, $offset);
+}
+
+/**
+ * Set the validation status for a user.
+ *
+ * @param bool $status Validated (true) or false
+ * @param string $method Optional method to say how a user was validated
+ * @return bool
+ * @deprecated 1.8 Use elgg_set_user_validation_status()
+ */
+function set_user_validation_status($user_guid, $status, $method = '') {
+ elgg_deprecated_notice("set_user_validation_status() is deprecated", 1.8);
+ return elgg_set_user_validation_status($user_guid, $status, $method);
+}
+
+/**
+ * Trigger an event requesting that a user guid be validated somehow - either by email address or some other way.
+ *
+ * This function invalidates any existing validation value.
+ *
+ * @param int $user_guid User's GUID
+ * @deprecated 1.8 Hook into the register, user plugin hook and request validation.
+ */
+function request_user_validation($user_guid) {
+ elgg_deprecated_notice("request_user_validation() is deprecated.
+ Plugins should register for the 'register, user' plugin hook", 1.8);
+ $user = get_entity($user_guid);
+
+ if (($user) && ($user instanceof ElggUser)) {
+ // invalidate any existing validations
+ set_user_validation_status($user_guid, false);
+
+ // request validation
+ trigger_elgg_event('validate', 'user', $user);
+ }
+}
+
+/**
+ * Register a user settings page with the admin panel.
+ * This function extends the view "usersettings/main" with the provided view.
+ * This view should provide a description and either a control or a link to.
+ *
+ * Usage:
+ * - To add a control to the main admin panel then extend usersettings/main
+ * - To add a control to a new page create a page which renders a view
+ * usersettings/subpage (where subpage is your new page -
+ * nb. some pages already exist that you can extend), extend the main view
+ * to point to it, and add controls to your new view.
+ *
+ * At the moment this is essentially a wrapper around elgg_extend_view().
+ *
+ * @param string $new_settings_view The view associated with the control you're adding
+ * @param string $view The view to extend, by default this is 'usersettings/main'.
+ * @param int $priority Optional priority to govern the appearance in the list.
+ *
+ * @return bool
+ * @deprecated 1.8 Extend one of the views in core/settings
+ */
+function extend_elgg_settings_page($new_settings_view, $view = 'usersettings/main',
+$priority = 500) {
+ // see views: /core/settings
+ elgg_deprecated_notice("extend_elgg_settings_page has been deprecated. Extend one of the settings views instead", 1.8);
+
+ return elgg_extend_view($view, $new_settings_view, $priority);
+}
+
+/**
+ * Returns a representation of a full 'page' (which might be an HTML page,
+ * RSS file, etc, depending on the current viewtype)
+ *
+ * @param string $title
+ * @param string $body
+ * @return string
+ *
+ * @deprecated 1.8 Use elgg_view_page()
+ */
+function page_draw($title, $body, $sidebar = "") {
+ elgg_deprecated_notice("page_draw() was deprecated in favor of elgg_view_page() in 1.8.", 1.8);
+
+ $vars = array(
+ 'sidebar' => $sidebar
+ );
+ echo elgg_view_page($title, $body, 'default', $vars);
+}
+
+/**
+ * Wrapper function to display search listings.
+ *
+ * @param string $icon The icon for the listing
+ * @param string $info Any information that needs to be displayed.
+ *
+ * @return string The HTML (etc) representing the listing
+ * @deprecated 1.8 use elgg_view_image_block()
+ */
+function elgg_view_listing($icon, $info) {
+ elgg_deprecated_notice('elgg_view_listing deprecated by elgg_view_image_block', 1.8);
+ return elgg_view('page/components/image_block', array('image' => $icon, 'body' => $info));
+}
+
+/**
+ * Return the icon URL for an entity.
+ *
+ * @tip Can be overridden by registering a plugin hook for entity:icon:url, $entity_type.
+ *
+ * @internal This is passed an entity rather than a guid to handle non-created entities.
+ *
+ * @param ElggEntity $entity The entity
+ * @param string $size Icon size
+ *
+ * @return string URL to the entity icon.
+ * @deprecated 1.8 Use $entity->getIconURL()
+ */
+function get_entity_icon_url(ElggEntity $entity, $size = 'medium') {
+ elgg_deprecated_notice("get_entity_icon_url() deprecated for getIconURL()", 1.8);
+ 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
+ $params = array('entity' => $entity, 'viewtype' => $viewtype, 'size' => $size);
+ $url = elgg_trigger_plugin_hook('entity:icon:url', $entity->getType(), $params, $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 = "_graphics/icons/default/$size.png";
+ }
+
+ return elgg_normalize_url($url);
+}
+
+/**
+ * Return the current logged in user, or NULL if no user is logged in.
+ *
+ * If no user can be found in the current session, a plugin
+ * hook - 'session:get' 'user' to give plugin authors another
+ * way to provide user details to the ACL system without touching the session.
+ *
+ * @deprecated 1.8 Use elgg_get_logged_in_user_entity()
+ * @return ElggUser|NULL
+ */
+function get_loggedin_user() {
+ elgg_deprecated_notice('get_loggedin_user() is deprecated by elgg_get_logged_in_user_entity()', 1.8);
+ return elgg_get_logged_in_user_entity();
+}
+
+/**
+ * Return the current logged in user by id.
+ *
+ * @deprecated 1.8 Use elgg_get_logged_in_user_guid()
+ * @see elgg_get_logged_in_user_entity()
+ * @return int
+ */
+function get_loggedin_userid() {
+ elgg_deprecated_notice('get_loggedin_userid() is deprecated by elgg_get_logged_in_user_guid()', 1.8);
+ return elgg_get_logged_in_user_guid();
+}
+
+
+/**
+ * Returns whether or not the user is currently logged in
+ *
+ * @deprecated 1.8 Use elgg_is_logged_in();
+ * @return bool
+ */
+function isloggedin() {
+ elgg_deprecated_notice('isloggedin() is deprecated by elgg_is_logged_in()', 1.8);
+ return elgg_is_logged_in();
+}
+
+/**
+ * Returns whether or not the user is currently logged in and that they are an admin user.
+ *
+ * @deprecated 1.8 Use elgg_is_admin_logged_in()
+ * @return bool
+ */
+function isadminloggedin() {
+ elgg_deprecated_notice('isadminloggedin() is deprecated by elgg_is_admin_logged_in()', 1.8);
+ return elgg_is_admin_logged_in();
+}
+
+
+/**
+ * Loads plugins
+ *
+ * @deprecated 1.8 Use elgg_load_plugins()
+ *
+ * @return bool
+ */
+function load_plugins() {
+ elgg_deprecated_notice('load_plugins() is deprecated by elgg_load_plugins()', 1.8);
+ return elgg_load_plugins();
+}
+
+/**
+ * Find the plugin settings for a user.
+ *
+ * @param string $plugin_id Plugin name.
+ * @param int $user_guid The guid who's settings to retrieve.
+ *
+ * @deprecated 1.8 Use elgg_get_all_plugin_user_settings() or ElggPlugin->getAllUserSettings()
+ * @return StdClass Object with all user settings.
+ */
+function find_plugin_usersettings($plugin_id = null, $user_guid = 0) {
+ elgg_deprecated_notice('find_plugin_usersettings() is deprecated by elgg_get_all_plugin_user_settings()', 1.8);
+ return elgg_get_all_plugin_user_settings($user_guid, $plugin_id, true);
+}
+
+/**
+ * Set a user specific setting for a plugin.
+ *
+ * @param string $name The name - note, can't be "title".
+ * @param mixed $value The value.
+ * @param int $user_guid Optional user.
+ * @param string $plugin_id Optional plugin name, if not specified then it
+ * is detected from where you are calling from.
+ *
+ * @return bool
+ * @deprecated 1.8 Use elgg_set_plugin_user_setting() or ElggPlugin->setUserSetting()
+ */
+function set_plugin_usersetting($name, $value, $user_guid = 0, $plugin_id = "") {
+ elgg_deprecated_notice('find_plugin_usersettings() is deprecated by elgg_get_all_plugin_user_settings()', 1.8);
+ return elgg_set_plugin_user_setting($name, $value, $user_guid, $plugin_id);
+}
+
+/**
+ * Clears a user-specific plugin setting
+ *
+ * @param str $name Name of the plugin setting
+ * @param int $user_guid Defaults to logged in user
+ * @param str $plugin_id Defaults to contextual plugin name
+ *
+ * @deprecated 1.8 Use elgg_unset_plugin_user_setting or ElggPlugin->unsetUserSetting().
+ * @return bool Success
+ */
+function clear_plugin_usersetting($name, $user_guid = 0, $plugin_id = '') {
+ elgg_deprecated_notice('clear_plugin_usersetting() is deprecated by elgg_unset_plugin_usersetting()', 1.8);
+ return elgg_unset_plugin_user_setting($name, $user_guid, $plugin_id);
+}
+
+/**
+ * Get a user specific setting for a plugin.
+ *
+ * @param string $name The name.
+ * @param int $user_guid Guid of owning user
+ * @param string $plugin_id Optional plugin name, if not specified
+ * it is detected from where you are calling.
+ *
+ * @deprecated 1.8 Use elgg_get_plugin_user_setting() or ElggPlugin->getUserSetting()
+ * @return mixed
+ */
+function get_plugin_usersetting($name, $user_guid = 0, $plugin_id = "") {
+ elgg_deprecated_notice('get_plugin_usersetting() is deprecated by elgg_get_plugin_user_setting()', 1.8);
+ return elgg_get_plugin_user_setting($name, $user_guid, $plugin_id);
+}
+
+/**
+ * Set a setting for a plugin.
+ *
+ * @param string $name The name - note, can't be "title".
+ * @param mixed $value The value.
+ * @param string $plugin_id Optional plugin name, if not specified
+ * then it is detected from where you are calling from.
+ *
+ * @deprecated 1.8 Use elgg_set_plugin_setting() or ElggPlugin->setSetting()
+ * @return int|false
+ */
+function set_plugin_setting($name, $value, $plugin_id = null) {
+ elgg_deprecated_notice('set_plugin_setting() is deprecated by elgg_set_plugin_setting()', 1.8);
+ return elgg_set_plugin_setting($name, $value, $plugin_id);
+}
+
+/**
+ * Get setting for a plugin.
+ *
+ * @param string $name The name.
+ * @param string $plugin_id Optional plugin name, if not specified
+ * then it is detected from where you are calling from.
+ *
+ * @deprecated 1.8 Use elgg_get_plugin_setting() or ElggPlugin->getSetting()
+ * @return mixed
+ */
+function get_plugin_setting($name, $plugin_id = "") {
+ elgg_deprecated_notice('get_plugin_setting() is deprecated by elgg_get_plugin_setting()', 1.8);
+ return elgg_get_plugin_setting($name, $plugin_id);
+}
+
+/**
+ * Clear a plugin setting.
+ *
+ * @param string $name The name.
+ * @param string $plugin_id Optional plugin name, if not specified
+ * then it is detected from where you are calling from.
+ *
+ * @deprecated 1.8 Use elgg_unset_plugin_setting() or ElggPlugin->unsetSetting()
+ * @return bool
+ */
+function clear_plugin_setting($name, $plugin_id = "") {
+ elgg_deprecated_notice('clear_plugin_setting() is deprecated by elgg_unset_plugin_setting()', 1.8);
+ return elgg_unset_plugin_setting($name, $plugin_id);
+}
+
+/**
+ * Unsets all plugin settings for a plugin.
+ *
+ * @param string $plugin_id Optional plugin name, if not specified
+ * then it is detected from where you are calling from.
+ *
+ * @return bool
+ * @deprecated 1.8 Use elgg_unset_all_plugin_settings() or ElggPlugin->unsetAllSettings()
+ * @since 1.7.0
+ */
+function clear_all_plugin_settings($plugin_id = "") {
+ elgg_deprecated_notice('clear_all_plugin_settings() is deprecated by elgg_unset_all_plugin_setting()', 1.8);
+ return elgg_unset_all_plugin_settings($plugin_id);
+}
+
+
+/**
+ * Get a list of annotations for a given object/user/annotation type.
+ *
+ * @param int|array $entity_guid GUID to return annotations of (falsey for any)
+ * @param string $entity_type Type of entity
+ * @param string $entity_subtype Subtype of entity
+ * @param string $name Name of annotation
+ * @param mixed $value Value of annotation
+ * @param int|array $owner_guid Owner(s) of annotation
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Order annotations by SQL
+ * @param int $timelower Lower time limit
+ * @param int $timeupper Upper time limit
+ * @param int $entity_owner_guid Owner guid for the entity
+ *
+ * @return array
+ * @deprecated 1.8 Use elgg_get_annotations()
+ */
+function get_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "", $name = "",
+$value = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "asc", $timelower = 0,
+$timeupper = 0, $entity_owner_guid = 0) {
+
+ elgg_deprecated_notice('get_annotations() is deprecated by elgg_get_annotations()', 1.8);
+ $options = array();
+
+ if ($entity_guid) {
+ $options['guid'] = $entity_guid;
+ }
+
+ if ($entity_type) {
+ $options['type'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtype'] = $entity_subtype;
+ }
+
+ if ($name) {
+ $options['annotation_name'] = $name;
+ }
+
+ if ($value) {
+ $options['annotation_value'] = $value;
+ }
+
+ if ($owner_guid) {
+ $options['annotation_owner_guid'] = $owner_guid;
+ }
+
+ $options['limit'] = $limit;
+ $options['offset'] = $offset;
+
+ if ($order_by == 'desc') {
+ $options['order_by'] = 'n_table.time_created desc';
+ }
+
+ if ($timelower) {
+ $options['annotation_time_lower'] = $timelower;
+ }
+
+ if ($timeupper) {
+ $options['annotation_time_upper'] = $timeupper;
+ }
+
+ if ($entity_owner_guid) {
+ $options['owner_guid'] = $entity_owner_guid;
+ }
+
+ return elgg_get_annotations($options);
+}
+
+
+/**
+ * Returns a human-readable list of annotations on a particular entity.
+ *
+ * @param int $entity_guid The entity GUID
+ * @param string $name The name of the kind of annotation
+ * @param int $limit The number of annotations to display at once
+ * @param true|false $asc Display annotations in ascending order. (Default: true)
+ *
+ * @return string HTML (etc) version of the annotation list
+ * @deprecated 1.8 Use elgg_list_annotations()
+ */
+function list_annotations($entity_guid, $name = "", $limit = 25, $asc = true) {
+ elgg_deprecated_notice('list_annotations() is deprecated by elgg_list_annotations()', 1.8);
+
+ if ($asc) {
+ $asc = "asc";
+ } else {
+ $asc = "desc";
+ }
+
+ $options = array(
+ 'guid' => $entity_guid,
+ 'limit' => $limit,
+ 'order_by' => "n_table.time_created $asc"
+ );
+
+ return elgg_list_annotations($options);
+}
+
+/**
+ * Helper function to deprecate annotation calculation functions. Don't use.
+ *
+ * @param unknown_type $entity_guid
+ * @param unknown_type $entity_type
+ * @param unknown_type $entity_subtype
+ * @param unknown_type $name
+ * @param unknown_type $value
+ * @param unknown_type $value_type
+ * @param unknown_type $owner_guid
+ * @param unknown_type $timelower
+ * @param unknown_type $timeupper
+ * @param unknown_type $calculation
+ * @internal Don't use this at all.
+ * @deprecated 1.8 Use elgg_get_annotations()
+ */
+function elgg_deprecated_annotation_calculation($entity_guid = 0, $entity_type = "", $entity_subtype = "",
+$name = "", $value = "", $value_type = "", $owner_guid = 0, $timelower = 0,
+$timeupper = 0, $calculation = '') {
+
+ $options = array('annotation_calculation' => $calculation);
+
+ if ($entity_guid) {
+ $options['guid'] = $entity_guid;
+ }
+
+ if ($entity_type) {
+ $options['type'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtype'] = $entity_subtype;
+ }
+
+ if ($name) {
+ $options['annotation_name'] = $name;
+ }
+
+ if ($value) {
+ $options['annotation_value'] = $value;
+ }
+
+ if ($owner_guid) {
+ $options['annotation_owner_guid'] = $owner_guid;
+ }
+
+ if ($order_by == 'desc') {
+ $options['order_by'] = 'n_table.time_created desc';
+ }
+
+ if ($timelower) {
+ $options['annotation_time_lower'] = $timelower;
+ }
+
+ if ($timeupper) {
+ $options['annotation_time_upper'] = $timeupper;
+ }
+
+ return elgg_get_annotations($options);
+}
+
+/**
+ * Count the number of annotations based on search parameters
+ *
+ * @param int $entity_guid Guid of Entity
+ * @param string $entity_type Type of Entity
+ * @param string $entity_subtype Subtype of Entity
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value
+ * @param int $owner_guid GUID of owner of annotation
+ * @param int $timelower Lower time limit
+ * @param int $timeupper Upper time limit
+ *
+ * @deprecated 1.8 Use elgg_get_annotations() and pass 'count' => true
+ * @return int
+ */
+function count_annotations($entity_guid = 0, $entity_type = "", $entity_subtype = "",
+$name = "", $value = "", $value_type = "", $owner_guid = 0, $timelower = 0,
+$timeupper = 0) {
+ elgg_deprecated_notice('count_annotations() is deprecated by elgg_get_annotations() and passing "count" => true', 1.8);
+ return elgg_deprecated_annotation_calculation($entity_guid, $entity_type, $entity_subtype,
+ $name, $value, $value_type, $owner_guid, $timelower, $timeupper, 'count');
+}
+
+/**
+ * Return the sum of a given integer annotation.
+ *
+ * @param int $entity_guid Guid of Entity
+ * @param string $entity_type Type of Entity
+ * @param string $entity_subtype Subtype of Entity
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value
+ * @param int $owner_guid GUID of owner of annotation
+ *
+ * @deprecated 1.8 Use elgg_get_annotations() and pass 'annotation_calculation' => 'sum'
+ * @return int
+ */
+function get_annotations_sum($entity_guid, $entity_type = "", $entity_subtype = "", $name = "",
+$value = "", $value_type = "", $owner_guid = 0) {
+ elgg_deprecated_notice('get_annotations_sum() is deprecated by elgg_get_annotations() and passing "annotation_calculation" => "sum"', 1.8);
+
+ return elgg_deprecated_annotation_calculation($entity_guid, $entity_type, $entity_subtype,
+ $name, $value, $value_type, $owner_guid, $timelower, $timeupper, 'sum');
+}
+
+/**
+ * Return the max of a given integer annotation.
+ *
+ * @param int $entity_guid Guid of Entity
+ * @param string $entity_type Type of Entity
+ * @param string $entity_subtype Subtype of Entity
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value
+ * @param int $owner_guid GUID of owner of annotation
+ *
+ * @deprecated 1.8 Use elgg_get_annotations() and pass 'annotation_calculation' => 'max'
+ * @return int
+ */
+function get_annotations_max($entity_guid, $entity_type = "", $entity_subtype = "", $name = "",
+$value = "", $value_type = "", $owner_guid = 0) {
+ elgg_deprecated_notice('get_annotations_max() is deprecated by elgg_get_annotations() and passing "annotation_calculation" => "max"', 1.8);
+
+ return elgg_deprecated_annotation_calculation($entity_guid, $entity_type, $entity_subtype,
+ $name, $value, $value_type, $owner_guid, $timelower, $timeupper, 'max');
+}
+
+
+/**
+ * Return the minumum of a given integer annotation.
+ *
+ * @param int $entity_guid Guid of Entity
+ * @param string $entity_type Type of Entity
+ * @param string $entity_subtype Subtype of Entity
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value
+ * @param int $owner_guid GUID of owner of annotation
+ *
+ * @deprecated 1.8 Use elgg_get_annotations() and pass 'annotation_calculation' => 'min'
+ * @return int
+ */
+function get_annotations_min($entity_guid, $entity_type = "", $entity_subtype = "", $name = "",
+$value = "", $value_type = "", $owner_guid = 0) {
+ elgg_deprecated_notice('get_annotations_min() is deprecated by elgg_get_annotations() and passing "annotation_calculation" => "min"', 1.8);
+
+ return elgg_deprecated_annotation_calculation($entity_guid, $entity_type, $entity_subtype,
+ $name, $value, $value_type, $owner_guid, $timelower, $timeupper, 'min');
+}
+
+
+/**
+ * Return the average of a given integer annotation.
+ *
+ * @param int $entity_guid Guid of Entity
+ * @param string $entity_type Type of Entity
+ * @param string $entity_subtype Subtype of Entity
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value
+ * @param int $owner_guid GUID of owner of annotation
+ *
+ * @deprecated 1.8 Use elgg_get_annotations() and pass 'annotation_calculation' => 'min'
+ *
+ * @return int
+ */
+function get_annotations_avg($entity_guid, $entity_type = "", $entity_subtype = "", $name = "",
+$value = "", $value_type = "", $owner_guid = 0) {
+ elgg_deprecated_notice('get_annotations_avg() is deprecated by elgg_get_annotations() and passing "annotation_calculation" => "avg"', 1.8);
+
+ return elgg_deprecated_annotation_calculation($entity_guid, $entity_type, $entity_subtype,
+ $name, $value, $value_type, $owner_guid, $timelower, $timeupper, 'avg');
+}
+
+
+/**
+ * Perform a mathmatical calculation on integer annotations.
+ *
+ * @param string $sum What sort of calculation to perform
+ * @param int $entity_guid Guid of Entity
+ * @param string $entity_type Type of Entity
+ * @param string $entity_subtype Subtype of Entity
+ * @param string $name Name of annotation
+ * @param string $value Value of annotation
+ * @param string $value_type Type of value
+ * @param int $owner_guid GUID of owner of annotation
+ * @param int $timelower Lower time limit
+ * @param int $timeupper Upper time limit
+ *
+ * @return int
+ * @deprecated 1.8 Use elgg_get_annotations() and pass anntoation_calculation => <calculation>
+ */
+function get_annotations_calculate_x($sum = "avg", $entity_guid, $entity_type = "",
+$entity_subtype = "", $name = "", $value = "", $value_type = "", $owner_guid = 0,
+$timelower = 0, $timeupper = 0) {
+ elgg_deprecated_notice('get_annotations_calculate_x() is deprecated by elgg_get_annotations() and passing "annotation_calculation" => "calculation"', 1.8);
+
+ return elgg_deprecated_annotation_calculation($entity_guid, $entity_type, $entity_subtype,
+ $name, $value, $value_type, $owner_guid, $timelower, $timeupper, $sum);
+}
+
+
+/**
+ * Lists entities by the totals of a particular kind of annotation AND
+ * the value of a piece of metadata
+ *
+ * @param string $entity_type Type of entity.
+ * @param string $entity_subtype Subtype of entity.
+ * @param string $name Name of annotation.
+ * @param string $mdname Metadata name
+ * @param string $mdvalue Metadata value
+ * @param int $limit Maximum number of results to return.
+ * @param int $owner_guid Owner.
+ * @param int $group_guid Group container. Currently only supported if entity_type is object
+ * @param boolean $asc Whether to list in ascending or descending order (default: desc)
+ * @param boolean $fullview Whether to display the entities in full
+ * @param boolean $listtypetoggle Can the 'gallery' view can be displayed (default: no)
+ * @param boolean $pagination Display pagination
+ * @param string $orderdir 'desc' or 'asc'
+ *
+ * @deprecated 1.8 Use elgg_list_entities_from_annotation_calculation().
+ *
+ * @return string Formatted entity list
+ */
+function list_entities_from_annotation_count_by_metadata($entity_type = "", $entity_subtype = "",
+$name = "", $mdname = '', $mdvalue = '', $limit = 10, $owner_guid = 0, $group_guid = 0,
+$asc = false, $fullview = true, $listtypetoggle = false, $pagination = true, $orderdir = 'desc') {
+
+ $msg = 'list_entities_from_annotation_count_by_metadata() is deprecated by elgg_list_entities_from_annotation_calculation().';
+
+ elgg_deprecated_notice($msg, 1.8);
+
+ $options = array();
+
+ $options['calculation'] = 'sum';
+
+ if ($entity_type) {
+ $options['types'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtypes'] = $entity_subtype;
+ }
+
+ $options['annotation_names'] = $name;
+
+ if ($mdname) {
+ $options['metadata_name'] = $mdname;
+ }
+
+ if ($mdvalue) {
+ $options['metadata_value'] = $mdvalue;
+ }
+
+ if ($owner_guid) {
+ if (is_array($owner_guid)) {
+ $options['owner_guids'] = $owner_guid;
+ } else {
+ $options['owner_guid'] = $owner_guid;
+ }
+ }
+
+ $options['full_view'] = $fullview;
+
+ $options['list_type_toggle'] = $listtypetoggle;
+
+ $options['pagination'] = $pagination;
+
+ $options['limit'] = $limit;
+
+ $options['order_by'] = "annotation_calculation $orderdir";
+
+ return elgg_get_entities_from_annotation_calculation($options);
+}
+
+/**
+ * Set an alternative base location for a view (as opposed to the default of $CONFIG->viewpath)
+ *
+ * @param string $view The name of the view
+ * @param string $location The base location path
+ *
+ * @deprecated 1.8 Use elgg_set_view_location()
+ */
+function set_view_location($view, $location, $viewtype = '') {
+ elgg_deprecated_notice("set_view_location() was deprecated by elgg_set_view_location()", 1.8);
+ return elgg_set_view_location($view, $location, $viewtype);
+}
+
+/**
+ * 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
+ *
+ * @deprecated 1.8 Use elgg_register_entity_url_handler()
+ */
+function register_entity_url_handler($function_name, $entity_type = "all", $entity_subtype = "all") {
+ elgg_deprecated_notice("register_entity_url_handler() was deprecated by elgg_register_entity_url_handler()", 1.8);
+ return elgg_register_entity_url_handler($entity_type, $entity_subtype, $function_name);
+}
+
+
+/**
+ * Get the metadata where the entities they are referring to match a given criteria.
+ *
+ * @param mixed $meta_name Metadata name
+ * @param mixed $meta_value Metadata value
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site GUID. 0 for current, -1 for any
+ *
+ * @return mixed
+ * @deprecated 1.8 Use elgg_get_metadata()
+ */
+function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $entity_subtype = "",
+ $limit = 10, $offset = 0, $order_by = "", $site_guid = 0) {
+
+ elgg_deprecated_notice('get_metadata() is deprecated by elgg_get_metadata()', 1.8);
+
+ $options = array();
+
+ if ($meta_name) {
+ $options['annotation_name'] = $meta_name;
+ }
+
+ if ($meta_value) {
+ $options['annotation_value'] = $meta_value;
+ }
+
+ if ($entity_type) {
+ $options['type'] = $entity_type;
+ }
+
+ if ($entity_subtype) {
+ $options['subtype'] = $entity_subtype;
+ }
+
+ $options['limit'] = $limit;
+ $options['offset'] = $offset;
+
+ if ($order_by == 'desc') {
+ $options['order_by'] = 'n_table.time_created desc';
+ }
+
+ if ($site_guid) {
+ $options['site_guid'] = $site_guid;
+ }
+
+ return elgg_get_metadata($options);
+}
+
+/**
+ * Get metadata objects by name.
+ *
+ * @param int $entity_guid Entity GUID
+ * @param string $meta_name Metadata name
+ *
+ * @return mixed ElggMetadata object, an array of ElggMetadata or false.
+ * @deprecated 1.8 Use elgg_get_metadata()
+ */
+function get_metadata_byname($entity_guid, $meta_name) {
+ elgg_deprecated_notice('get_metadata_byname() is deprecated by elgg_get_metadata()', 1.8);
+
+ if (!$entity_guid || !$meta_name) {
+ return false;
+ }
+
+ $options = array(
+ 'guid' => $entity_guid,
+ 'metadata_name' => $meta_name,
+ 'limit' => 0
+ );
+
+ $md = elgg_get_metadata($options);
+
+ if ($md && count($md) == 1) {
+ return $md[0];
+ }
+
+ return $md;
+}
+
+/**
+ * Return all the metadata for a given GUID.
+ *
+ * @param int $entity_guid Entity GUID
+ *
+ * @return mixed
+ * @deprecated 1.8 Use elgg_get_metadata()
+ */
+function get_metadata_for_entity($entity_guid) {
+ elgg_deprecated_notice('get_metadata_for_entity() is deprecated by elgg_get_metadata()', 1.8);
+
+ if (!$entity_guid) {
+ return false;
+ }
+
+ $options = array(
+ 'guid' => $entity_guid,
+ 'limit' => 0
+ );
+
+ return elgg_get_metadata($options);
+}
+
+/**
+ * Get a specific metadata object.
+ *
+ * @param int $id The id of the metadata being retrieved.
+ *
+ * @return mixed False on failure or ElggMetadata
+ * @deprecated 1.8 Use elgg_get_metadata_from_id()
+ */
+function get_metadata($id) {
+ elgg_deprecated_notice('get_metadata() is deprecated by elgg_get_metadata_from_id()', 1.8);
+ return elgg_get_metadata_from_id($id);
+}
+
+/**
+ * Clear all the metadata for a given entity, assuming you have access to that entity.
+ *
+ * @param int $guid Entity GUID
+ *
+ * @return bool
+ * @deprecated 1.8 Use elgg_delete_metadata()
+ */
+function clear_metadata($guid) {
+ elgg_deprecated_notice('clear_metadata() is deprecated by elgg_delete_metadata()', 1.8);
+ if (!$guid) {
+ return false;
+ }
+ return elgg_delete_metadata(array('guid' => $guid, 'limit' => 0));
+}
+
+/**
+ * Clear all metadata belonging to a given owner_guid
+ *
+ * @param int $owner_guid The owner
+ *
+ * @return bool
+ * @deprecated 1.8 Use elgg_delete_metadata()
+ */
+function clear_metadata_by_owner($owner_guid) {
+ elgg_deprecated_notice('clear_metadata() is deprecated by elgg_delete_metadata()', 1.8);
+ if (!$owner_guid) {
+ return false;
+ }
+ return elgg_delete_metadata(array('metadata_owner_guid' => $owner_guid, 'limit' => 0));
+}
+
+/**
+ * Delete a piece of metadata, where the current user has access.
+ *
+ * @param int $id The id of metadata to delete.
+ *
+ * @return bool
+ * @deprecated 1.8 Use elgg_delete_metadata()
+ */
+function delete_metadata($id) {
+ elgg_deprecated_notice('delete_metadata() is deprecated by elgg_delete_metadata()', 1.8);
+ if (!$id) {
+ return false;
+ }
+ return elgg_delete_metadata(array('metadata_id' => $id));
+}
+
+/**
+ * Removes metadata on an entity with a particular name, optionally with a given value.
+ *
+ * @param int $guid The entity GUID
+ * @param string $name The name of the metadata
+ * @param string $value The value of the metadata (useful to remove a single item of a set)
+ *
+ * @return bool Depending on success
+ * @deprecated 1.8 Use elgg_delete_metadata()
+ */
+function remove_metadata($guid, $name, $value = "") {
+ elgg_deprecated_notice('delete_metadata() is deprecated by elgg_delete_metadata()', 1.8);
+
+ // prevent them from deleting everything
+ if (!$guid) {
+ return false;
+ }
+
+ $options = array(
+ 'guid' => $guid,
+ 'metadata_name' => $name,
+ 'limit' => 0
+ );
+
+ if ($value) {
+ $options['metadata_value'] = $value;
+ }
+
+ return elgg_delete_metadata($options);
+}
+
+/**
+ * Get a specific annotation.
+ *
+ * @param int $annotation_id Annotation ID
+ *
+ * @return ElggAnnotation
+ * @deprecated 1.8 Use elgg_get_annotation_from_id()
+ */
+function get_annotation($annotation_id) {
+ elgg_deprecated_notice('get_annotation() is deprecated by elgg_get_annotation_from_id()', 1.8);
+ return elgg_get_annotation_from_id($annotation_id);
+}
+
+/**
+ * Delete a given annotation.
+ *
+ * @param int $id The annotation id
+ *
+ * @return bool
+ * @deprecated 1.8 Use elgg_delete_annotations()
+ */
+function delete_annotation($id) {
+ elgg_deprecated_notice('delete_annotation() is deprecated by elgg_delete_annotations()', 1.8);
+ if (!$id) {
+ return false;
+ }
+ return elgg_delete_annotations(array('annotation_id' => $annotation_id));
+}
+
+/**
+ * Clear all the annotations for a given entity, assuming you have access to that metadata.
+ *
+ * @param int $guid The entity guid
+ * @param string $name The name of the annotation to delete.
+ *
+ * @return int Number of annotations deleted or false if an error
+ * @deprecated 1.8 Use elgg_delete_annotations()
+ */
+function clear_annotations($guid, $name = "") {
+ elgg_deprecated_notice('clear_annotations() is deprecated by elgg_delete_annotations()', 1.8);
+
+ if (!$guid) {
+ return false;
+ }
+
+ $options = array(
+ 'guid' => $guid,
+ 'limit' => 0
+ );
+
+ if ($name) {
+ $options['annotation_name'] = $name;
+ }
+
+ return elgg_delete_annotations($options);
+}
+
+/**
+ * Clear all annotations belonging to a given owner_guid
+ *
+ * @param int $owner_guid The owner
+ *
+ * @return int Number of annotations deleted
+ * @deprecated 1.8 Use elgg_delete_annotations()
+ */
+function clear_annotations_by_owner($owner_guid) {
+ elgg_deprecated_notice('clear_annotations_by_owner() is deprecated by elgg_delete_annotations()', 1.8);
+
+ if (!$owner_guid) {
+ return false;
+ }
+
+ $options = array(
+ 'annotation_owner_guid' => $guid,
+ 'limit' => 0
+ );
+
+ return elgg_delete_annotations($options);
+}
+
+/**
+ * Registers a page handler for a particular identifier
+ *
+ * For example, you can register a function called 'blog_page_handler' for handler type 'blog'
+ * Now for all URLs of type http://yoururl/pg/blog/*, the blog_page_handler() function will be called.
+ * The part of the URL marked with * above will be exploded on '/' characters and passed as an
+ * array to that function.
+ * For example, the URL http://yoururl/blog/username/friends/ would result in the call:
+ * blog_page_handler(array('username','friends'), blog);
+ *
+ * Page handler functions should return true or the default page handler will be called.
+ *
+ * A request to register a page handler with the same identifier as previously registered
+ * handler will replace the previous one.
+ *
+ * The context is set to the page handler identifier before the registered
+ * page handler function is called. For the above example, the context is set to 'blog'.
+ *
+ * @param string $handler The page type to handle
+ * @param string $function Your function name
+ * @return true|false Depending on success
+ *
+ * @deprecated 1.8 Use {@link elgg_register_page_handler()}
+ */
+function register_page_handler($handler, $function){
+ elgg_deprecated_notice("register_page_handler() was deprecated by elgg_register_page_handler()", 1.8);
+ return elgg_register_page_handler($handler, $function);
+}
+
+/**
+ * Unregister a page handler for an identifier
+ *
+ * Note: to replace a page handler, call register_page_handler()
+ *
+ * @param string $handler The page type identifier
+ * @since 1.7.2
+ *
+ * @deprecated 1.8 Use {@link elgg_unregister_page_handler()}
+ */
+function unregister_page_handler($handler) {
+ elgg_deprecated_notice("unregister_page_handler() was deprecated by elgg_unregister_page_handler()", 1.8);
+ return elgg_unregister_page_handler($handler);
+}
+
+/**
+ * Register an annotation url handler.
+ *
+ * @param string $function_name The function.
+ * @param string $extender_name The name, default 'all'.
+ *
+ * @deprecated 1.8 Use {@link elgg_register_annotation_url_handler()}
+ */
+function register_annotation_url_handler($function, $extender_name) {
+ elgg_deprecated_notice("register_annotation_url_handler() was deprecated by elgg_register_annotation_url_handler()", 1.8);
+ return elgg_register_annotation_url_handler($extender_name, $function);
+}
+
+/**
+ * Sets the URL handler for a particular extender type and name.
+ * It is recommended that you do not call this directly, instead use one of the wrapper functions in the
+ * subtype files.
+ *
+ * @param string $function_name The function to register
+ * @param string $extender_type Extender type
+ * @param string $extender_name The name of the extender
+ * @return true|false Depending on success
+ *
+ * @deprecated 1.8 Use {@link elgg_register_extender_url_handler()}
+ */
+function register_extender_url_handler($function, $type = "all", $name = "all") {
+ elgg_deprecated_notice("register_extender_url_handler() was deprecated by elgg_register_extender_url_handler()", 1.8);
+ return elgg_register_extender_url_handler($type, $name, $function);
+}
+
+/**
+ * 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
+ *
+ * @deprecated 1.8 Use {@link elgg_register_entity_type()}
+ */
+function register_entity_type($type, $subtype = null) {
+ elgg_deprecated_notice("register_entity_type() was deprecated by elgg_register_entity_type()", 1.8);
+ return elgg_register_entity_type($type, $subtype);
+}
+
+/**
+ * Register a metadata url handler.
+ *
+ * @param string $function_name The function.
+ * @param string $extender_name The name, default 'all'.
+ *
+ * @deprecated 1.8 Use {@link elgg_register_metadata_url_handler()}
+ */
+function register_metadata_url_handler($function, $extender_name = "all") {
+ return elgg_register_metadata_url_handler($extender_name, $function);
+}
+
+/**
+ * Sets the URL handler for a particular relationship type
+ *
+ * @param string $function_name The function to register
+ * @param string $relationship_type The relationship type.
+ * @return true|false Depending on success
+ *
+ * @deprecated 1.8 Use {@link elgg_register_relationship_url_handler()}
+ */
+function register_relationship_url_handler($function_name, $relationship_type = "all") {
+ elgg_deprecated_notice("register_relationship_url_handler() was deprecated by elgg_register_relationship_url_handler()", 1.8);
+ return elgg_register_relationship_url_handler($relationship_type, $function_name);
+}
+
+/**
+ * Registers a view to be simply cached
+ *
+ * Views cached in this manner must take no parameters and be login agnostic -
+ * that is to say, they look the same no matter who is logged in (or logged out).
+ *
+ * CSS and the basic jS views are automatically cached like this.
+ *
+ * @param string $viewname View name
+ *
+ * @deprecated 1.8 Use {@link elgg_register_simplecache_view()}
+ */
+function elgg_view_register_simplecache($viewname) {
+ elgg_deprecated_notice("elgg_view_register_simplecache() was deprecated by elgg_register_simplecache_view()", 1.8);
+ return elgg_register_simplecache_view($viewname);
+}
+
+/**
+ * Regenerates the simple cache.
+ *
+ * @param string $viewtype Optional viewtype to regenerate
+ * @see elgg_view_register_simplecache()
+ *
+ * @deprecated 1.8 Use {@link elgg_regenerate_simplecache()}
+ */
+function elgg_view_regenerate_simplecache($viewtype = NULL) {
+ elgg_deprecated_notice("elgg_view_regenerate_simplecache() was deprecated by elgg_regenerate_simplecache()", 1.8);
+ return elgg_regenerate_simplecache($viewtype);
+}
+
+/**
+ * Enables the simple cache.
+ *
+ * @see elgg_view_register_simplecache()
+ *
+ * @deprecated 1.8 Use {@link elgg_enable_simplecache()}
+ */
+function elgg_view_enable_simplecache() {
+ elgg_deprecated_notice("elgg_view_enable_simplecache() was deprecated by elgg_enable_simplecache()", 1.8);
+ return elgg_enable_simplecache();
+}
+
+/**
+ * Disables the simple cache.
+ *
+ * @see elgg_view_register_simplecache()
+ *
+ * @deprecated 1.8 Use {@link elgg_disable_simplecache()}
+ */
+function elgg_view_disable_simplecache() {
+ elgg_deprecated_notice("elgg_view_disable_simplecache() was deprecated by elgg_disable_simplecache()", 1.8);
+ return elgg_disable_simplecache();
+}
+
+// these were internal functions that perhaps can be removed rather than deprecated
+/**
+ * @deprecated 1.8
+ */
+function is_db_installed() {
+ elgg_deprecated_notice('is_db_installed() has been deprecated', 1.8);
+ return true;
+}
+
+/**
+ * @deprecated 1.8
+ */
+function is_installed() {
+ elgg_deprecated_notice('is_installed() has been deprecated', 1.8);
+ return true;
+}
+
+/**
+ * Attempt to authenticate.
+ * This function will process all registered PAM handlers or stop when the first
+ * handler fails. A handler fails by either returning false or throwing an
+ * exception. The advantage of throwing an exception is that it returns a message
+ * through the global $_PAM_HANDLERS_MSG which can be used in communication with
+ * a user. The order that handlers are processed is determined by the order that
+ * they were registered.
+ *
+ * If $credentials are provided the PAM handler should authenticate using the
+ * provided credentials, if not then credentials should be prompted for or
+ * otherwise retrieved (eg from the HTTP header or $_SESSION).
+ *
+ * @param mixed $credentials Mixed PAM handler specific credentials (e.g. username, password)
+ * @param string $policy - the policy type, default is "user"
+ * @return bool true if authenticated, false if not.
+ *
+ * @deprecated 1.8 See {@link ElggPAM}
+ */
+function pam_authenticate($credentials = NULL, $policy = "user") {
+ elgg_deprecated_notice('pam_authenticate has been deprecated for ElggPAM', 1.8);
+ global $_PAM_HANDLERS, $_PAM_HANDLERS_MSG;
+
+ $_PAM_HANDLERS_MSG = array();
+
+ $authenticated = false;
+
+ foreach ($_PAM_HANDLERS[$policy] as $k => $v) {
+ $handler = $v->handler;
+ $importance = $v->importance;
+
+ try {
+ // Execute the handler
+ if ($handler($credentials)) {
+ // Explicitly returned true
+ $_PAM_HANDLERS_MSG[$k] = "Authenticated!";
+
+ $authenticated = true;
+ } else {
+ $_PAM_HANDLERS_MSG[$k] = "Not Authenticated.";
+
+ // If this is required then abort.
+ if ($importance == 'required') {
+ return false;
+ }
+ }
+ } catch (Exception $e) {
+ $_PAM_HANDLERS_MSG[$k] = "$e";
+
+ // If this is required then abort.
+ if ($importance == 'required') {
+ return false;
+ }
+ }
+ }
+
+ return $authenticated;
+}
+
+
+/**
+ * When given a widget entity and a new requested location, saves the new location
+ * and also provides a sensible ordering for all widgets in that column
+ *
+ * @param ElggObject $widget The widget entity
+ * @param int $order The order within the column
+ * @param int $column The column (1, 2 or 3)
+ *
+ * @return bool Depending on success
+ * @deprecated 1.8 use ElggWidget::move()
+ */
+function save_widget_location(ElggObject $widget, $order, $column) {
+ elgg_deprecated_notice('save_widget_location() is deprecated', 1.8);
+ if ($widget instanceof ElggObject) {
+ if ($widget->subtype == "widget") {
+ // If you can't move the widget, don't save a new location
+ if (!$widget->draggable) {
+ return false;
+ }
+
+ // Sanitise the column value
+ if ($column != 1 || $column != 2 || $column != 3) {
+ $column = 1;
+ }
+
+ $widget->column = (int) $column;
+
+ $ordertmp = array();
+ $params = array(
+ 'context' => $widget->context,
+ 'column' => $column,
+ );
+
+ if ($entities = get_entities_from_metadata_multi($params, 'object', 'widget')) {
+ foreach ($entities as $entity) {
+ $entityorder = $entity->order;
+ if ($entityorder < $order) {
+ $ordertmp[$entityorder] = $entity;
+ }
+ if ($entityorder >= $order) {
+ $ordertmp[$entityorder + 10000] = $entity;
+ }
+ }
+ }
+
+ $ordertmp[$order] = $widget;
+ ksort($ordertmp);
+
+ $orderticker = 10;
+ foreach ($ordertmp as $orderval => $entity) {
+ $entity->order = $orderticker;
+ $orderticker += 10;
+ }
+
+ return true;
+ } else {
+ register_error($widget->subtype);
+ }
+
+ }
+
+ return false;
+}
+
+/**
+ * Get widgets for a particular context and column, in order of display
+ *
+ * @param int $user_guid The owner user GUID
+ * @param string $context The context (profile, dashboard etc)
+ * @param int $column The column (1 or 2)
+ *
+ * @return array|false An array of widget ElggObjects, or false
+ * @deprecated 1.8 Use elgg_get_widgets()
+ */
+function get_widgets($user_guid, $context, $column) {
+ elgg_deprecated_notice('get_widgets is depecated for elgg_get_widgets', 1.8);
+ $params = array(
+ 'column' => $column,
+ 'context' => $context
+ );
+ $widgets = get_entities_from_private_setting_multi($params, "object",
+ "widget", $user_guid, "", 10000);
+
+ if ($widgets) {
+ $widgetorder = array();
+ foreach ($widgets as $widget) {
+ $order = $widget->order;
+ while (isset($widgetorder[$order])) {
+ $order++;
+ }
+ $widgetorder[$order] = $widget;
+ }
+
+ ksort($widgetorder);
+
+ return $widgetorder;
+ }
+
+ return false;
+}
+
+/**
+ * Add a new widget instance
+ *
+ * @param int $entity_guid GUID of entity that owns this widget
+ * @param string $handler The handler for this widget
+ * @param string $context The page context for this widget
+ * @param int $order The order to display this widget in
+ * @param int $column The column to display this widget in (1, 2 or 3)
+ * @param int $access_id If not specified, it is set to the default access level
+ *
+ * @return int|false Widget GUID or false on failure
+ * @deprecated 1.8 use elgg_create_widget()
+ */
+function add_widget($entity_guid, $handler, $context, $order = 0, $column = 1, $access_id = null) {
+ elgg_deprecated_notice('add_widget has been deprecated for elgg_create_widget', 1.8);
+ if (empty($entity_guid) || empty($context) || empty($handler) || !widget_type_exists($handler)) {
+ return false;
+ }
+
+ if ($entity = get_entity($entity_guid)) {
+ $widget = new ElggWidget;
+ $widget->owner_guid = $entity_guid;
+ $widget->container_guid = $entity_guid;
+ if (isset($access_id)) {
+ $widget->access_id = $access_id;
+ } else {
+ $widget->access_id = get_default_access();
+ }
+
+ $guid = $widget->save();
+
+ // private settings cannot be set until ElggWidget saved
+ $widget->handler = $handler;
+ $widget->context = $context;
+ $widget->column = $column;
+ $widget->order = $order;
+
+ return $guid;
+ }
+
+ return false;
+}
+
+/**
+ * Define a new widget type
+ *
+ * @param string $handler The identifier for the widget handler
+ * @param string $name The name of the widget type
+ * @param string $description A description for the widget type
+ * @param string $context A comma-separated list of contexts where this
+ * widget is allowed (default: 'all')
+ * @param bool $multiple Whether or not multiple instances of this widget
+ * are allowed on a single dashboard (default: false)
+ * @param string $positions A comma-separated list of positions on the page
+ * (side or main) where this widget is allowed (default: "side,main")
+ *
+ * @return bool Depending on success
+ * @deprecated 1.8 Use elgg_register_widget_type
+ */
+function add_widget_type($handler, $name, $description, $context = "all",
+$multiple = false, $positions = "side,main") {
+ elgg_deprecated_notice("add_widget_type deprecated for elgg_register_widget_type", 1.8);
+
+ return elgg_register_widget_type($handler, $name, $description, $context, $multiple);
+}
+
+/**
+ * Remove a widget type
+ *
+ * @param string $handler The identifier for the widget handler
+ *
+ * @return void
+ * @since 1.7.1
+ * @deprecated 1.8 Use elgg_unregister_widget_type
+ */
+function remove_widget_type($handler) {
+ elgg_deprecated_notice("remove_widget_type deprecated for elgg_unregister_widget_type", 1.8);
+ return elgg_unregister_widget_type($handler);
+}
+
+/**
+ * Determines whether or not widgets with the specified handler have been defined
+ *
+ * @param string $handler The widget handler identifying string
+ *
+ * @return bool Whether or not those widgets exist
+ * @deprecated 1.8 Use elgg_is_widget_type
+ */
+function widget_type_exists($handler) {
+ elgg_deprecated_notice("widget_type_exists deprecated for elgg_is_widget_type", 1.8);
+ return elgg_is_widget_type($handler);
+}
+
+/**
+ * Returns an array of stdClass objects representing the defined widget types
+ *
+ * @return array A list of types defined (if any)
+ * @deprecated 1.8 Use elgg_get_widget_types
+ */
+function get_widget_types() {
+ elgg_deprecated_notice("get_widget_types deprecrated for elgg_get_widget_types", 1.8);
+ return elgg_get_widget_types();
+}
+
+/**
+ * Saves a widget's settings (by passing an array of
+ * (name => value) pairs to save_{$handler}_widget)
+ *
+ * @param int $widget_guid The GUID of the widget we're saving to
+ * @param array $params An array of name => value parameters
+ *
+ * @return bool
+ * @deprecated 1.8 Use elgg_save_widget_settings
+ */
+function save_widget_info($widget_guid, $params) {
+ elgg_deprecated_notice("save_widget_info() is deprecated for elgg_save_widget_settings", 1.8);
+ if ($widget = get_entity($widget_guid)) {
+
+ $subtype = $widget->getSubtype();
+
+ if ($subtype != "widget") {
+ return false;
+ }
+ $handler = $widget->handler;
+ if (empty($handler) || !widget_type_exists($handler)) {
+ return false;
+ }
+
+ if (!$widget->canEdit()) {
+ return false;
+ }
+
+ // Save the params to the widget
+ if (is_array($params) && sizeof($params) > 0) {
+ foreach ($params as $name => $value) {
+
+ if (!empty($name) && !in_array($name, array(
+ 'guid', 'owner_guid', 'site_guid'
+ ))) {
+ if (is_array($value)) {
+ // @todo Handle arrays securely
+ $widget->setMetaData($name, $value, "", true);
+ } else {
+ $widget->$name = $value;
+ }
+ }
+ }
+ $widget->save();
+ }
+
+ $function = "save_{$handler}_widget";
+ if (is_callable($function)) {
+ return $function($params);
+ }
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Reorders the widgets from a widget panel
+ *
+ * @param string $panelstring1 String of guids of ElggWidget objects separated by ::
+ * @param string $panelstring2 String of guids of ElggWidget objects separated by ::
+ * @param string $panelstring3 String of guids of ElggWidget objects separated by ::
+ * @param string $context Profile or dashboard
+ * @param int $owner Owner guid
+ *
+ * @return void
+ * @deprecated 1.8 Don't use.
+ */
+function reorder_widgets_from_panel($panelstring1, $panelstring2, $panelstring3, $context, $owner) {
+ elgg_deprecated_notice("reorder_widgets_from_panel() is deprecated", 1.8);
+ $return = true;
+
+ $mainwidgets = explode('::', $panelstring1);
+ $sidewidgets = explode('::', $panelstring2);
+ $rightwidgets = explode('::', $panelstring3);
+
+ $handlers = array();
+ $guids = array();
+
+ if (is_array($mainwidgets) && sizeof($mainwidgets) > 0) {
+ foreach ($mainwidgets as $widget) {
+
+ $guid = (int) $widget;
+
+ if ("{$guid}" == "{$widget}") {
+ $guids[1][] = $widget;
+ } else {
+ $handlers[1][] = $widget;
+ }
+ }
+ }
+ if (is_array($sidewidgets) && sizeof($sidewidgets) > 0) {
+ foreach ($sidewidgets as $widget) {
+
+ $guid = (int) $widget;
+
+ if ("{$guid}" == "{$widget}") {
+ $guids[2][] = $widget;
+ } else {
+ $handlers[2][] = $widget;
+ }
+
+ }
+ }
+ if (is_array($rightwidgets) && sizeof($rightwidgets) > 0) {
+ foreach ($rightwidgets as $widget) {
+
+ $guid = (int) $widget;
+
+ if ("{$guid}" == "{$widget}") {
+ $guids[3][] = $widget;
+ } else {
+ $handlers[3][] = $widget;
+ }
+
+ }
+ }
+
+ // Reorder existing widgets or delete ones that have vanished
+ foreach (array(1, 2, 3) as $column) {
+ if ($dbwidgets = get_widgets($owner, $context, $column)) {
+
+ foreach ($dbwidgets as $dbwidget) {
+ if (in_array($dbwidget->getGUID(), $guids[1])
+ || in_array($dbwidget->getGUID(), $guids[2]) || in_array($dbwidget->getGUID(), $guids[3])) {
+
+ if (in_array($dbwidget->getGUID(), $guids[1])) {
+ $pos = array_search($dbwidget->getGUID(), $guids[1]);
+ $col = 1;
+ } else if (in_array($dbwidget->getGUID(), $guids[2])) {
+ $pos = array_search($dbwidget->getGUID(), $guids[2]);
+ $col = 2;
+ } else {
+ $pos = array_search($dbwidget->getGUID(), $guids[3]);
+ $col = 3;
+ }
+ $pos = ($pos + 1) * 10;
+ $dbwidget->column = $col;
+ $dbwidget->order = $pos;
+ } else {
+ $dbguid = $dbwidget->getGUID();
+ if (!$dbwidget->delete()) {
+ $return = false;
+ } else {
+ // Remove state cookie
+ setcookie('widget' + $dbguid, null);
+ }
+ }
+ }
+
+ }
+ // Add new ones
+ if (sizeof($guids[$column]) > 0) {
+ foreach ($guids[$column] as $key => $guid) {
+ if ($guid == 0) {
+ $pos = ($key + 1) * 10;
+ $handler = $handlers[$column][$key];
+ if (!add_widget($owner, $handler, $context, $pos, $column)) {
+ $return = false;
+ }
+ }
+ }
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Register a particular context for use with widgets.
+ *
+ * @param string $context The context we wish to enable context for
+ *
+ * @return void
+ * @deprecated 1.8 Don't use.
+ */
+function use_widgets($context) {
+ elgg_deprecated_notice("use_widgets is deprecated", 1.8);
+ global $CONFIG;
+
+ if (!isset($CONFIG->widgets)) {
+ $CONFIG->widgets = new stdClass;
+ }
+
+ if (!isset($CONFIG->widgets->contexts)) {
+ $CONFIG->widgets->contexts = array();
+ }
+
+ if (!empty($context)) {
+ $CONFIG->widgets->contexts[] = $context;
+ }
+}
+
+/**
+ * Determines whether or not the current context is using widgets
+ *
+ * @return bool Depending on widget status
+ * @deprecated 1.8 Don't use.
+ */
+function using_widgets() {
+ elgg_deprecated_notice("using_widgets is deprecated", 1.8);
+ global $CONFIG;
+
+ $context = elgg_get_context();
+ if (isset($CONFIG->widgets->contexts) && is_array($CONFIG->widgets->contexts)) {
+ if (in_array($context, $CONFIG->widgets->contexts)) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Displays a particular widget
+ *
+ * @param ElggObject $widget The widget to display
+ * @return string The HTML for the widget, including JavaScript wrapper
+ *
+ * @deprecated 1.8 Use elgg_view_entity()
+ */
+function display_widget(ElggObject $widget) {
+ elgg_deprecated_notice("display_widget() was been deprecated. Use elgg_view_entity().", 1.8);
+ return elgg_view_entity($widget);
+}
+
+/**
+ * Count the number of comments attached to an entity
+ *
+ * @param ElggEntity $entity
+ * @return int Number of comments
+ * @deprecated 1.8 Use ElggEntity->countComments()
+ */
+function elgg_count_comments($entity) {
+ elgg_deprecated_notice('elgg_count_comments() is deprecated by ElggEntity->countComments()', 1.8);
+
+ if ($entity instanceof ElggEntity) {
+ return $entity->countComments();
+ }
+
+ return 0;
+}
+
+/**
+ * Removes all items relating to a particular acting entity from the river
+ *
+ * @param int $subject_guid The GUID of the entity
+ *
+ * @return bool Depending on success
+ * @deprecated 1.8 Use elgg_delete_river()
+ */
+function remove_from_river_by_subject($subject_guid) {
+ elgg_deprecated_notice("remove_from_river_by_subject() deprecated by elgg_delete_river()", 1.8);
+
+ return elgg_delete_river(array('subject_guid' => $subject_guid));
+}
+
+/**
+ * Removes all items relating to a particular entity being acted upon from the river
+ *
+ * @param int $object_guid The GUID of the entity
+ *
+ * @return bool Depending on success
+ * @deprecated 1.8 Use elgg_delete_river()
+ */
+function remove_from_river_by_object($object_guid) {
+ elgg_deprecated_notice("remove_from_river_by_object() deprecated by elgg_delete_river()", 1.8);
+
+ return elgg_delete_river(array('object_guid' => $object_guid));
+}
+
+/**
+ * Removes all items relating to a particular annotation being acted upon from the river
+ *
+ * @param int $annotation_id The ID of the annotation
+ *
+ * @return bool Depending on success
+ * @since 1.7.0
+ * @deprecated 1.8 Use elgg_delete_river()
+ */
+function remove_from_river_by_annotation($annotation_id) {
+ elgg_deprecated_notice("remove_from_river_by_annotation() deprecated by elgg_delete_river()", 1.8);
+
+ return elgg_delete_river(array('annotation_id' => $annotation_id));
+}
+
+/**
+ * Removes a single river entry
+ *
+ * @param int $id The ID of the river entry
+ *
+ * @return bool Depending on success
+ * @since 1.7.2
+ * @deprecated 1.8 Use elgg_delete_river()
+ */
+function remove_from_river_by_id($id) {
+ elgg_deprecated_notice("remove_from_river_by_id() deprecated by elgg_delete_river()", 1.8);
+
+ return elgg_delete_river(array('id' => $id));
+}
+
+/**
+ * A default page handler
+ * Tries to locate a suitable file to include. Only works for core pages, not plugins.
+ *
+ * @param array $page The page URL elements
+ * @param string $handler The base handler
+ *
+ * @return true|false Depending on success
+ * @deprecated 1.8
+ */
+function default_page_handler($page, $handler) {
+ global $CONFIG;
+
+ elgg_deprecated_notice("default_page_handler is deprecated", "1.8");
+
+ $page = implode('/', $page);
+
+ // protect against including arbitary files
+ $page = str_replace("..", "", $page);
+
+ $callpath = $CONFIG->path . $handler . "/" . $page;
+ if (is_dir($callpath)) {
+ $callpath = sanitise_filepath($callpath);
+ $callpath .= "index.php";
+ if (file_exists($callpath)) {
+ if (include($callpath)) {
+ return TRUE;
+ }
+ }
+ } else if (file_exists($callpath)) {
+ include($callpath);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Invalidate this class's entry in the cache.
+ *
+ * @param int $guid The entity guid
+ *
+ * @return void
+ * @access private
+ * @deprecated 1.8
+ */
+function invalidate_cache_for_entity($guid) {
+ elgg_deprecated_notice('invalidate_cache_for_entity() is a private function and should not be used.', 1.8);
+ _elgg_invalidate_cache_for_entity($guid);
+}
+
+/**
+ * Cache an entity.
+ *
+ * Stores an entity in $ENTITY_CACHE;
+ *
+ * @param ElggEntity $entity Entity to cache
+ *
+ * @return void
+ * @access private
+ * @deprecated 1.8
+ */
+function cache_entity(ElggEntity $entity) {
+ elgg_deprecated_notice('cache_entity() is a private function and should not be used.', 1.8);
+ _elgg_cache_entity($entity);
+}
+
+/**
+ * Retrieve a entity from the cache.
+ *
+ * @param int $guid The guid
+ *
+ * @return ElggEntity|bool false if entity not cached, or not fully loaded
+ * @access private
+ * @deprecated 1.8
+ */
+function retrieve_cached_entity($guid) {
+ elgg_deprecated_notice('retrieve_cached_entity() is a private function and should not be used.', 1.8);
+ return _elgg_retrieve_cached_entity($guid);
+}
diff --git a/engine/lib/deprecated-1.9.php b/engine/lib/deprecated-1.9.php
new file mode 100644
index 000000000..31d03428f
--- /dev/null
+++ b/engine/lib/deprecated-1.9.php
@@ -0,0 +1,582 @@
+<?php
+/**
+ * Return a timestamp for the start of a given day (defaults today).
+ *
+ * @param int $day Day
+ * @param int $month Month
+ * @param int $year Year
+ *
+ * @return int
+ * @access private
+ * @deprecated 1.9
+ */
+function get_day_start($day = null, $month = null, $year = null) {
+ elgg_deprecated_notice('get_day_start() has been deprecated', 1.9);
+ return mktime(0, 0, 0, $month, $day, $year);
+}
+
+/**
+ * Return a timestamp for the end of a given day (defaults today).
+ *
+ * @param int $day Day
+ * @param int $month Month
+ * @param int $year Year
+ *
+ * @return int
+ * @access private
+ * @deprecated 1.9
+ */
+function get_day_end($day = null, $month = null, $year = null) {
+ elgg_deprecated_notice('get_day_end() has been deprecated', 1.9);
+ return mktime(23, 59, 59, $month, $day, $year);
+}
+
+/**
+ * Return the notable entities for a given time period.
+ *
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @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 instead of entities. Defaults to false.
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any.
+ * @param mixed $container_guid Container or containers to get entities from (default: any).
+ *
+ * @return array|false
+ * @access private
+ * @deprecated 1.9
+ */
+function get_notable_entities($start_time, $end_time, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "asc", $limit = 10, $offset = 0, $count = false, $site_guid = 0,
+$container_guid = null) {
+ elgg_deprecated_notice('get_notable_entities() has been deprecated', 1.9);
+ global $CONFIG;
+
+ if ($subtype === false || $subtype === null || $subtype === 0) {
+ return false;
+ }
+
+ $start_time = (int)$start_time;
+ $end_time = (int)$end_time;
+ $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);
+ if (!empty($subtypeval)) {
+ $subtypeval = (int) get_subtype_id($typekey, $subtypeval);
+ } else {
+ $subtypeval = 0;
+ }
+ if (!empty($tempwhere)) {
+ $tempwhere .= " or ";
+ }
+ $tempwhere .= "(e.type = '{$typekey}' and e.subtype = {$subtypeval})";
+ }
+ }
+ }
+ if (!empty($tempwhere)) {
+ $where[] = "({$tempwhere})";
+ }
+ } else {
+ $type = sanitise_string($type);
+ $subtype = get_subtype_id($type, $subtype);
+
+ 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[] = "e.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 = implode(",", $owner_guid);
+ $where[] = "e.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}";
+ }
+ }
+
+ // Add the calendar stuff
+ $cal_join = "
+ JOIN {$CONFIG->dbprefix}metadata cal_start on e.guid=cal_start.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_name on cal_start.name_id=cal_start_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_value on cal_start.value_id=cal_start_value.id
+
+ JOIN {$CONFIG->dbprefix}metadata cal_end on e.guid=cal_end.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_name on cal_end.name_id=cal_end_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_value on cal_end.value_id=cal_end_value.id
+ ";
+ $where[] = "cal_start_name.string='calendar_start'";
+ $where[] = "cal_start_value.string>=$start_time";
+ $where[] = "cal_end_name.string='calendar_end'";
+ $where[] = "cal_end_value.string <= $end_time";
+
+
+ if (!$count) {
+ $query = "SELECT e.* from {$CONFIG->dbprefix}entities e $cal_join where ";
+ } else {
+ $query = "SELECT count(e.guid) as total from {$CONFIG->dbprefix}entities e $cal_join where ";
+ }
+ foreach ($where as $w) {
+ $query .= " $w and ";
+ }
+
+ $query .= get_access_sql_suffix('e'); // Add access controls
+
+ if (!$count) {
+ $query .= " order by n.calendar_start $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;
+ }
+}
+
+/**
+ * Return the notable entities for a given time period based on an item of metadata.
+ *
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @param mixed $meta_name Metadata name
+ * @param mixed $meta_value Metadata value
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any.
+ * @param bool $count If true, returns count instead of entities. (Default: false)
+ *
+ * @return int|array A list of entities, or a count if $count is set to true
+ * @access private
+ * @deprecated 1.9
+ */
+function get_notable_entities_from_metadata($start_time, $end_time, $meta_name, $meta_value = "",
+$entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "",
+$site_guid = 0, $count = false) {
+ elgg_deprecated_notice('get_notable_entities_from_metadata() has been deprecated', 1.9);
+
+ global $CONFIG;
+
+ $meta_n = get_metastring_id($meta_name);
+ $meta_v = get_metastring_id($meta_value);
+
+ $start_time = (int)$start_time;
+ $end_time = (int)$end_time;
+ $entity_type = sanitise_string($entity_type);
+ $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
+ $limit = (int)$limit;
+ $offset = (int)$offset;
+ if ($order_by == "") {
+ $order_by = "e.time_created desc";
+ }
+ $order_by = sanitise_string($order_by);
+ $site_guid = (int) $site_guid;
+ if ((is_array($owner_guid) && (count($owner_guid)))) {
+ foreach ($owner_guid as $key => $guid) {
+ $owner_guid[$key] = (int) $guid;
+ }
+ } else {
+ $owner_guid = (int) $owner_guid;
+ }
+
+ if ($site_guid == 0) {
+ $site_guid = $CONFIG->site_guid;
+ }
+
+ //$access = get_access_list();
+
+ $where = array();
+
+ if ($entity_type != "") {
+ $where[] = "e.type='$entity_type'";
+ }
+
+ if ($entity_subtype) {
+ $where[] = "e.subtype=$entity_subtype";
+ }
+
+ if ($meta_name != "") {
+ $where[] = "m.name_id='$meta_n'";
+ }
+
+ if ($meta_value != "") {
+ $where[] = "m.value_id='$meta_v'";
+ }
+
+ if ($site_guid > 0) {
+ $where[] = "e.site_guid = {$site_guid}";
+ }
+
+ if (is_array($owner_guid)) {
+ $where[] = "e.container_guid in (" . implode(",", $owner_guid) . ")";
+ } else if ($owner_guid > 0) {
+ $where[] = "e.container_guid = {$owner_guid}";
+ }
+
+ // Add the calendar stuff
+ $cal_join = "
+ JOIN {$CONFIG->dbprefix}metadata cal_start on e.guid=cal_start.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_name on cal_start.name_id=cal_start_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_value on cal_start.value_id=cal_start_value.id
+
+ JOIN {$CONFIG->dbprefix}metadata cal_end on e.guid=cal_end.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_name on cal_end.name_id=cal_end_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_value on cal_end.value_id=cal_end_value.id
+ ";
+
+ $where[] = "cal_start_name.string='calendar_start'";
+ $where[] = "cal_start_value.string>=$start_time";
+ $where[] = "cal_end_name.string='calendar_end'";
+ $where[] = "cal_end_value.string <= $end_time";
+
+ if (!$count) {
+ $query = "SELECT distinct e.* ";
+ } else {
+ $query = "SELECT count(distinct e.guid) as total ";
+ }
+
+ $query .= "from {$CONFIG->dbprefix}entities e"
+ . " JOIN {$CONFIG->dbprefix}metadata m on e.guid = m.entity_guid $cal_join where";
+
+ foreach ($where as $w) {
+ $query .= " $w and ";
+ }
+
+ // Add access controls
+ $query .= get_access_sql_suffix("e");
+ $query .= ' and ' . get_access_sql_suffix("m");
+
+ if (!$count) {
+ // Add order and limit
+ $query .= " order by $order_by limit $offset, $limit";
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($row = get_data_row($query)) {
+ return $row->total;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Return the notable entities for a given time period based on their relationship.
+ *
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @param string $relationship The relationship eg "friends_of"
+ * @param int $relationship_guid The guid of the entity to use query
+ * @param bool $inverse_relationship Reverse the normal function of the query to say
+ * "give me all entities for whom $relationship_guid is a
+ * $relationship of"
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param int $owner_guid Owner GUID
+ * @param string $order_by Optional Order by
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param boolean $count If true returns a count of entities (default false)
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
+ *
+ * @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @access private
+ * @deprecated 1.9
+ */
+function get_noteable_entities_from_relationship($start_time, $end_time, $relationship,
+$relationship_guid, $inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+ elgg_deprecated_notice('get_noteable_entities_from_relationship() has been deprecated', 1.9);
+
+ global $CONFIG;
+
+ $start_time = (int)$start_time;
+ $end_time = (int)$end_time;
+ $relationship = sanitise_string($relationship);
+ $relationship_guid = (int)$relationship_guid;
+ $inverse_relationship = (bool)$inverse_relationship;
+ $type = sanitise_string($type);
+ $subtype = get_subtype_id($type, $subtype);
+ $owner_guid = (int)$owner_guid;
+ 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;
+ if ($site_guid == 0) {
+ $site_guid = $CONFIG->site_guid;
+ }
+
+ //$access = get_access_list();
+
+ $where = array();
+
+ if ($relationship != "") {
+ $where[] = "r.relationship='$relationship'";
+ }
+ if ($relationship_guid) {
+ $where[] = $inverse_relationship ?
+ "r.guid_two='$relationship_guid'" : "r.guid_one='$relationship_guid'";
+ }
+ if ($type != "") {
+ $where[] = "e.type='$type'";
+ }
+ if ($subtype) {
+ $where[] = "e.subtype=$subtype";
+ }
+ if ($owner_guid != "") {
+ $where[] = "e.container_guid='$owner_guid'";
+ }
+ if ($site_guid > 0) {
+ $where[] = "e.site_guid = {$site_guid}";
+ }
+
+ // Add the calendar stuff
+ $cal_join = "
+ JOIN {$CONFIG->dbprefix}metadata cal_start on e.guid=cal_start.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_name on cal_start.name_id=cal_start_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_start_value on cal_start.value_id=cal_start_value.id
+
+ JOIN {$CONFIG->dbprefix}metadata cal_end on e.guid=cal_end.entity_guid
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_name on cal_end.name_id=cal_end_name.id
+ JOIN {$CONFIG->dbprefix}metastrings cal_end_value on cal_end.value_id=cal_end_value.id
+ ";
+ $where[] = "cal_start_name.string='calendar_start'";
+ $where[] = "cal_start_value.string>=$start_time";
+ $where[] = "cal_end_name.string='calendar_end'";
+ $where[] = "cal_end_value.string <= $end_time";
+
+ // Select what we're joining based on the options
+ $joinon = "e.guid = r.guid_one";
+ if (!$inverse_relationship) {
+ $joinon = "e.guid = r.guid_two";
+ }
+
+ if ($count) {
+ $query = "SELECT count(distinct e.guid) as total ";
+ } else {
+ $query = "SELECT distinct e.* ";
+ }
+ $query .= " from {$CONFIG->dbprefix}entity_relationships r"
+ . " JOIN {$CONFIG->dbprefix}entities e on $joinon $cal_join where ";
+
+ foreach ($where as $w) {
+ $query .= " $w and ";
+ }
+ // Add access controls
+ $query .= get_access_sql_suffix("e");
+ if (!$count) {
+ $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
+ return get_data($query, "entity_row_to_elggstar");
+ } else {
+ if ($count = get_data_row($query)) {
+ return $count->total;
+ }
+ }
+ return false;
+}
+
+/**
+ * Get all entities for today.
+ *
+ * @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 If true returns a count of entities (default false)
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
+ * @param mixed $container_guid Container(s) to get entities from (default: any).
+ *
+ * @return array|false
+ * @access private
+ * @deprecated 1.9
+ */
+function get_todays_entities($type = "", $subtype = "", $owner_guid = 0, $order_by = "",
+$limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid = null) {
+ elgg_deprecated_notice('get_todays_entities() has been deprecated', 1.9);
+
+ $day_start = get_day_start();
+ $day_end = get_day_end();
+
+ return get_notable_entities($day_start, $day_end, $type, $subtype, $owner_guid, $order_by,
+ $limit, $offset, $count, $site_guid, $container_guid);
+}
+
+/**
+ * Get entities for today from metadata.
+ *
+ * @param mixed $meta_name Metadata name
+ * @param mixed $meta_value Metadata value
+ * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
+ * @param string $entity_subtype The subtype of the entity.
+ * @param int $owner_guid Owner GUID
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param string $order_by Optional ordering.
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any.
+ * @param bool $count If true, returns count instead of entities. (Default: false)
+ *
+ * @return int|array A list of entities, or a count if $count is set to true
+ * @access private
+ * @deprecated 1.9
+ */
+function get_todays_entities_from_metadata($meta_name, $meta_value = "", $entity_type = "",
+$entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0,
+$count = false) {
+ elgg_deprecated_notice('get_todays_entities_from_metadata() has been deprecated', 1.9);
+
+ $day_start = get_day_start();
+ $day_end = get_day_end();
+
+ return get_notable_entities_from_metadata($day_start, $day_end, $meta_name, $meta_value,
+ $entity_type, $entity_subtype, $owner_guid, $limit, $offset, $order_by, $site_guid, $count);
+}
+
+/**
+ * Get entities for today from a relationship
+ *
+ * @param string $relationship The relationship eg "friends_of"
+ * @param int $relationship_guid The guid of the entity to use query
+ * @param bool $inverse_relationship Reverse the normal function of the query to say
+ * "give me all entities for whom $relationship_guid is a
+ * $relationship of"
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param int $owner_guid Owner GUID
+ * @param string $order_by Optional Order by
+ * @param int $limit Limit
+ * @param int $offset Offset
+ * @param boolean $count If true returns a count of entities (default false)
+ * @param int $site_guid Site to get entities for. Default 0 = current site. -1 = any
+ *
+ * @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @access private
+ * @deprecated 1.9
+ */
+function get_todays_entities_from_relationship($relationship, $relationship_guid,
+$inverse_relationship = false, $type = "", $subtype = "", $owner_guid = 0,
+$order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
+ elgg_deprecated_notice('get_todays_entities_from_relationship() has been deprecated', 1.9);
+
+ $day_start = get_day_start();
+ $day_end = get_day_end();
+
+ return get_notable_entities_from_relationship($day_start, $day_end, $relationship,
+ $relationship_guid, $inverse_relationship, $type, $subtype, $owner_guid, $order_by,
+ $limit, $offset, $count, $site_guid);
+}
+
+/**
+ * Returns a viewable list of entities for a given time period.
+ *
+ * @see elgg_view_entity_list
+ *
+ * @param int $start_time The start time as a unix timestamp.
+ * @param int $end_time The end time as a unix timestamp.
+ * @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 return; 10 by default
+ * @param boolean $fullview Whether or not to display the full view (default: true)
+ * @param boolean $listtypetoggle Whether or not to allow gallery view
+ * @param boolean $navigation Display pagination? Default: true
+ *
+ * @return string A viewable list of entities
+ * @access private
+ * @deprecated 1.9
+ */
+function list_notable_entities($start_time, $end_time, $type= "", $subtype = "", $owner_guid = 0,
+$limit = 10, $fullview = true, $listtypetoggle = false, $navigation = true) {
+ elgg_deprecated_notice('list_notable_entities() has been deprecated', 1.9);
+
+ $offset = (int) get_input('offset');
+ $count = get_notable_entities($start_time, $end_time, $type, $subtype,
+ $owner_guid, "", $limit, $offset, true);
+
+ $entities = get_notable_entities($start_time, $end_time, $type, $subtype,
+ $owner_guid, "", $limit, $offset);
+
+ return elgg_view_entity_list($entities, $count, $offset, $limit,
+ $fullview, $listtypetoggle, $navigation);
+}
+
+/**
+ * Return a list of today's entities.
+ *
+ * @see list_notable_entities
+ *
+ * @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 return; 10 by default
+ * @param boolean $fullview Whether or not to display the full view (default: true)
+ * @param boolean $listtypetoggle Whether or not to allow gallery view
+ * @param boolean $navigation Display pagination? Default: true
+ *
+ * @return string A viewable list of entities
+ * @access private
+ * @deprecated 1.9
+ */
+function list_todays_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10,
+$fullview = true, $listtypetoggle = false, $navigation = true) {
+ elgg_deprecated_notice('list_todays_entities() has been deprecated', 1.9);
+
+ $day_start = get_day_start();
+ $day_end = get_day_end();
+
+ return list_notable_entities($day_start, $day_end, $type, $subtype, $owner_guid, $limit,
+ $fullview, $listtypetoggle, $navigation);
+}
diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php
index a4e83e40b..34111c69d 100644
--- a/engine/lib/elgglib.php
+++ b/engine/lib/elgglib.php
@@ -1,785 +1,546 @@
<?php
/**
- * Elgg library
- * Contains important functionality core to Elgg
+ * Bootstrapping and helper procedural code available for use in Elgg core and plugins.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @todo These functions can't be subpackaged because they cover a wide mix of
+ * purposes and subsystems. Many of them should be moved to more relevant files.
*/
-/**
- * Getting directories and moving the browser
- */
+// prep core classes to be autoloadable
+spl_autoload_register('_elgg_autoload');
+elgg_register_classes(dirname(dirname(__FILE__)) . '/classes');
/**
- * Forwards the browser.
- * Returns false if headers have already been sent and the browser cannot be moved.
+ * Autoload classes
*
- * @param string $location URL to forward to browser to. Can be relative path.
- * @return nothing|false
- */function forward($location = "") {
- global $CONFIG;
-
- if (!headers_sent()) {
- if ($location === REFERER) {
- $location = $_SERVER['HTTP_REFERER'];
- }
-
- $current_page = current_page_url();
- if ((substr_count($location, 'http://') == 0) && (substr_count($location, 'https://') == 0)) {
- $location = $CONFIG->url . $location;
- }
-
- // return new forward location or false to stop the forward or empty string to exit
- $params = array('current_url' => $current_page, 'forward_url' => $location);
- $location = trigger_plugin_hook('forward', 'system', $params, $location);
- if ($location) {
- header("Location: {$location}");
- exit;
- } else if ($location === '') {
- exit;
- }
- }
-
- return false;
-}
-
-/**
- * Return the current page URL.
- */
-function current_page_url() {
- global $CONFIG;
-
- $url = parse_url($CONFIG->wwwroot);
-
- $page = $url['scheme'] . "://";
-
- // user/pass
- if ((isset($url['user'])) && ($url['user'])) {
- $page .= $url['user'];
- }
- if ((isset($url['pass'])) && ($url['pass'])) {
- $page .= ":".$url['pass'];
- }
- if ((isset($url['user']) && $url['user']) ||
- (isset($url['pass']) && $url['pass'])) {
- $page .="@";
- }
-
- $page .= $url['host'];
-
- if ((isset($url['port'])) && ($url['port'])) {
- $page .= ":" . $url['port'];
- }
-
- //$page.="/";
- $page = trim($page, "/");
-
- $page .= $_SERVER['REQUEST_URI'];
-
- return $page;
-}
-
-/**
- * This is a factory function which produces an ElggCache object suitable for caching file load paths.
+ * @param string $class The name of the class
*
- * TODO: Can this be done in a cleaner way?
- * TODO: Swap to memcache etc?
+ * @return void
+ * @throws Exception
+ * @access private
*/
-function elgg_get_filepath_cache() {
+function _elgg_autoload($class) {
global $CONFIG;
- static $FILE_PATH_CACHE;
- if (!$FILE_PATH_CACHE) $FILE_PATH_CACHE = new ElggFileCache($CONFIG->dataroot);
- return $FILE_PATH_CACHE;
+ if (!isset($CONFIG->classes[$class]) || !include($CONFIG->classes[$class])) {
+ return false;
+ }
}
/**
- * Function which resets the file path cache.
+ * Register all files found in $dir as classes
+ * Need to be named MyClass.php
*
- */
-function elgg_filepath_cache_reset() {
- $cache = elgg_get_filepath_cache();
- return $cache->delete('view_paths');
-}
-
-/**
- * Saves a filepath cache.
+ * @param string $dir The dir to look in
*
- * @param mixed $data
+ * @return void
+ * @since 1.8.0
*/
-function elgg_filepath_cache_save($data) {
- global $CONFIG;
+function elgg_register_classes($dir) {
+ $classes = elgg_get_file_list($dir, array(), array(), array('.php'));
- if ($CONFIG->viewpath_cache_enabled) {
- $cache = elgg_get_filepath_cache();
- return $cache->save('view_paths', $data);
+ foreach ($classes as $class) {
+ elgg_register_class(basename($class, '.php'), $class);
}
-
- return false;
}
/**
- * Retrieve the contents of the filepath cache.
+ * Register a classname to a file.
*
+ * @param string $class The name of the class
+ * @param string $location The location of the file
+ *
+ * @return true
+ * @since 1.8.0
*/
-function elgg_filepath_cache_load() {
+function elgg_register_class($class, $location) {
global $CONFIG;
- if ($CONFIG->viewpath_cache_enabled) {
- $cache = elgg_get_filepath_cache();
- $cached_view_paths = $cache->load('view_paths');
-
- if ($cached_view_paths) {
- return $cached_view_paths;
- }
+ if (!isset($CONFIG->classes)) {
+ $CONFIG->classes = array();
}
- return NULL;
-}
+ $CONFIG->classes[$class] = $location;
-/**
- * Enable the filepath cache.
- *
- */
-function elgg_enable_filepath_cache() {
- global $CONFIG;
-
- datalist_set('viewpath_cache_enabled',1);
- $CONFIG->viewpath_cache_enabled = 1;
- elgg_filepath_cache_reset();
+ return true;
}
/**
- * Disable filepath cache.
+ * Register a php library.
*
- */
-function elgg_disable_filepath_cache() {
- global $CONFIG;
-
- datalist_set('viewpath_cache_enabled',0);
- $CONFIG->viewpath_cache_enabled = 0;
- elgg_filepath_cache_reset();
-}
-
-/**
- * Deprecated by elgg_add_submenu_item()
+ * @param string $name The name of the library
+ * @param string $location The location of the file
*
- * @see elgg_add_submenu_item()
- * @deprecated 1.8
+ * @return void
+ * @since 1.8.0
*/
-function add_submenu_item($label, $link, $group = 'default', $onclick = false, $selected = NULL) {
- elgg_deprecated_notice('add_submenu_item was deprecated by elgg_add_submenu_item', 1.8);
-
- $item = array(
- 'text' => $label,
- 'href' => $link,
- 'selected' => $selected
- );
-
- if (!$group) {
- $group = 'default';
- }
+function elgg_register_library($name, $location) {
+ global $CONFIG;
- if ($onclick) {
- $js = "onclick=\"javascript:return confirm('". elgg_echo('deleteconfirm') . "')\"";
- $item['vars'] = array('js' => $js);
+ if (!isset($CONFIG->libraries)) {
+ $CONFIG->libraries = array();
}
- // submenu items were added in the page setup hook usually by checking
- // the context. We'll pass in the current context here, which will
- // emulate that effect.
- // if context == 'main' (default) it probably means they always wanted
- // the menu item to show up everywhere.
- $context = get_context();
- if ($context == 'main') {
- $context = 'all';
- }
- return elgg_add_submenu_item($item, $context, $group);
+ $CONFIG->libraries[$name] = $location;
}
/**
- * Add an entry to the submenu.
+ * Load a php library.
*
- * @param array $item The item as array(
- * 'title' => 'Text to display',
- * 'url' => 'URL of the link',
- * 'id' => 'entry_unique_id' //used by children items to identify parents
- * 'parent_id' => 'id_of_parent',
- * 'selected' => BOOL // Is this item selected? (If NULL or unset will attempt to guess)
- * 'vars' => array() // Array of vars to pass to the navigation/submenu_item view
- * )
+ * @param string $name The name of the library
*
- * @param string $context Context in which to display this menu item. 'all' will make it show up all the time. Use sparingly.
- * @param string $group Group for the item. Each submenu group has its own <ul>
- * @return BOOL
- * @since 1.8
+ * @return void
+ * @throws InvalidParameterException
+ * @since 1.8.0
+ * @todo return boolean in 1.9 to indicate whether the library has been loaded
*/
-function elgg_add_submenu_item(array $item, $context = 'all', $group = 'default') {
+function elgg_load_library($name) {
global $CONFIG;
- if (!isset($CONFIG->submenu_items)) {
- $CONFIG->submenu_items = array();
- }
+ static $loaded_libraries = array();
- if (!isset($CONFIG->submenu_items[$context])) {
- $CONFIG->submenu_items[$context] = array();
+ if (in_array($name, $loaded_libraries)) {
+ return;
}
- if (!isset($CONFIG->submenu_items[$context][$group])) {
- $CONFIG->submenu_items[$context][$group] = array();
+ if (!isset($CONFIG->libraries)) {
+ $CONFIG->libraries = array();
}
- if (!isset($item['text'])) {
- return FALSE;
+ if (!isset($CONFIG->libraries[$name])) {
+ $error = elgg_echo('InvalidParameterException:LibraryNotRegistered', array($name));
+ throw new InvalidParameterException($error);
}
- // we use persistent object properties in the submenu
- // setup function, so normalize the array to an object.
- // we pass it in as an array because this would be the only
- // place in elgg that we ask for an object like this.
- // consistency ftw.
- $item_obj = new StdClass();
-
- foreach ($item as $k => $v) {
- switch ($k) {
- case 'parent_id':
- case 'id':
- // make sure '' and false make sense
- $v = (empty($v)) ? NULL : $v;
-
- default:
- $item_obj->$k = $v;
- break;
- }
+ if (!include_once($CONFIG->libraries[$name])) {
+ $error = elgg_echo('InvalidParameterException:LibraryNotFound', array(
+ $name,
+ $CONFIG->libraries[$name])
+ );
+ throw new InvalidParameterException($error);
}
- $CONFIG->submenu_items[$context][$group][] = $item_obj;
-
- return TRUE;
+ $loaded_libraries[] = $name;
}
/**
- * Properly nest all submenu entries for contexts $context and 'all'
+ * Forward to $location.
+ *
+ * Sends a 'Location: $location' header and exists. If headers have
+ * already been sent, returns FALSE.
+ *
+ * @param string $location URL to forward to browser to. Can be path relative to the network's URL.
+ * @param string $reason Short explanation for why we're forwarding
*
- * @param string $context
- * @param bool $sort Sort the menu items alphabetically
- * @since 1.8
+ * @return false False if headers have been sent. Terminates execution if forwarding.
+ * @throws SecurityException
*/
-function elgg_prepare_submenu($context = 'main', $sort = FALSE) {
- global $CONFIG;
-
- if (!isset($CONFIG->submenu_items) || !($CONFIG->submenu_items)) {
- return FALSE;
- }
-
- $groups = array();
-
- if (isset($CONFIG->submenu_items['all'])) {
- $groups = $CONFIG->submenu_items['all'];
- }
-
- if (isset($CONFIG->submenu_items[$context])) {
- $groups = array_merge_recursive($groups, $CONFIG->submenu_items[$context]);
- }
-
- if (!$groups) {
- return FALSE;
- }
-
- foreach ($groups as $group => $items) {
- if ($sort) {
- usort($items, 'elgg_submenu_item_cmp');
+function forward($location = "", $reason = 'system') {
+ if (!headers_sent($file, $line)) {
+ if ($location === REFERER) {
+ $location = $_SERVER['HTTP_REFERER'];
}
- $parsed_menu = array();
- // determin which children need to go in this item.
- foreach ($items as $i => $item) {
- // can only support children if there's an id
- if (isset($item->id)) {
- foreach ($items as $child_i => $child_item) {
- // don't check ourselves or used children.
- if ($child_i == $i || $child_item->used == TRUE) {
- continue;
- }
-
- if (isset($child_item->parent_id) && $child_item->parent_id == $item->id) {
- if (!isset($item->children)) {
- $item->children = array();
- }
- $item->children[] = $child_item;
- $child_item->parent = $item;
- // don't unset because we still need to check this item for children
- $child_item->used = TRUE;
- }
- }
+ $location = elgg_normalize_url($location);
- // if the parent doesn't have a url, make it the first child item.
- if (isset($item->children) && $item->children && !$item->href) {
- $child = $item->children[0];
- while ($child && !isset($child->href)) {
- if (isset($child->children) && isset($child->children[0])) {
- $child = $child->children[0];
- } else {
- $child = NULL;
- }
- }
-
- if ($child && isset($child->href)) {
- $item->href = $child->href;
- } else {
- // @todo There are no URLs anywhere in this tree.
- $item->href = $CONFIG->url;
- }
- }
- }
+ // return new forward location or false to stop the forward or empty string to exit
+ $current_page = current_page_url();
+ $params = array('current_url' => $current_page, 'forward_url' => $location);
+ $location = elgg_trigger_plugin_hook('forward', $reason, $params, $location);
- // only add top-level elements to the menu.
- // the rest are children.
- if (!isset($item->parent_id)) {
- $parsed_menu[] = $item;
- }
+ if ($location) {
+ header("Location: {$location}");
+ exit;
+ } else if ($location === '') {
+ exit;
}
-
- $CONFIG->submenu[$context][$group] = $parsed_menu;
+ } else {
+ throw new SecurityException(elgg_echo('SecurityException:ForwardFailedToRedirect', array($file, $line)));
}
-
- return TRUE;
}
/**
- * Helper function used to sort submenu items by their display text.
+ * Register a JavaScript file for inclusion
+ *
+ * This function handles adding JavaScript to a web page. If multiple
+ * calls are made to register the same JavaScript file based on the $id
+ * variable, only the last file is included. This allows a plugin to add
+ * JavaScript from a view that may be called more than once. It also handles
+ * more than one plugin adding the same JavaScript.
+ *
+ * jQuery plugins often have filenames such as jquery.rating.js. A best practice
+ * is to base $name on the filename: "jquery.rating". It is recommended to not
+ * use version numbers in the name.
*
- * @param object $a
- * @param object $b
- * @since 1.8
+ * The JavaScript files can be local to the server or remote (such as
+ * Google's CDN).
+ *
+ * @param string $name An identifier for the JavaScript library
+ * @param string $url URL of the JavaScript file
+ * @param string $location Page location: head or footer. (default: head)
+ * @param int $priority Priority of the JS file (lower numbers load earlier)
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function elgg_submenu_item_cmp($a, $b) {
- $a = $a->text;
- $b = $b->text;
-
- return strnatcmp($a, $b);
+function elgg_register_js($name, $url, $location = 'head', $priority = null) {
+ return elgg_register_external_file('js', $name, $url, $location, $priority);
}
/**
- * Use elgg_get_submenu().
+ * Unregister a JavaScript file
*
- * @see elgg_get_submenu()
- * @deprecated 1.8
+ * @param string $name The identifier for the JavaScript library
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function get_submenu() {
- elgg_deprecated_notice("get_submenu() has been deprecated by elgg_get_submenu()", 1.8);
- return elgg_get_submenu();
+function elgg_unregister_js($name) {
+ return elgg_unregister_external_file('js', $name);
}
/**
- * Return the HTML for a sidemenu.
+ * Load a JavaScript resource on this page
+ *
+ * This must be called before elgg_view_page(). It can be called before the
+ * script is registered. If you do not want a script loaded, unregister it.
*
- * @param string $context The context of the submenu (defaults to main)
- * @param BOOL $sort Sort by display name?
- * @return string Formatted HTML.
- * @since 1.8
+ * @param string $name Identifier of the JavaScript resource
+ *
+ * @return void
+ * @since 1.8.0
*/
-function elgg_get_submenu($context = NULL, $sort = FALSE) {
- global $CONFIG;
-
- if (!$context) {
- $context = get_context();
- }
-
- if (!elgg_prepare_submenu($context, $sort)) {
- return '';
- }
-
- $groups = $CONFIG->submenu[$context];
- $submenu_html = '';
-
- foreach ($groups as $group => $items) {
- // how far down we are in children arrays
- $depth = 0;
- // push and pop parent items
- $temp_items = array();
-
- while ($item = current($items)) {
- $t = '';
- // ignore parents created by a child but parent never defined properly
- if (!isset($item->text) || !($item->text)) {
- next($items);
- continue;
- }
-
- // try to guess if this should be selected if they don't specify
- if ((!isset($item->selected) || $item->selected === NULL) && isset($item->href)) {
- $item->selected = elgg_http_url_is_identical(full_url(), $item->href);
- }
-
- // traverse up the parent tree if matached to mark all parents as selected/expanded.
- if ($item->selected && isset($item->parent)) {
- $parent = $item->parent;
- while ($parent) {
- $parent->selected = TRUE;
- if (isset($parent->parent)) {
- $parent = $parent->parent;
- } else {
- $parent = NULL;
- }
- }
- }
-
- // get the next item
- if (isset($item->children) && $item->children) {
- $depth++;
- array_push($temp_items, $items);
- $items = $item->children;
- } elseif ($depth > 0) {
- // check if there are more children elements in the current items
- // pop back up to the parent(s) if not
- if ($item = next($items)) {
- continue;
- } else {
- while($depth > 0) {
- $depth--;
- $items = array_pop($temp_items);
- if ($item = next($items)) {
- break;
- }
- }
- }
- } else {
- next($items);
- }
- }
-
- $submenu_html .= elgg_view('navigation/submenu_group', array('group' => $group, 'items' => $items));
- }
-
- // include the JS for the expand menus too
- return elgg_view('navigation/submenu_js') . $submenu_html;
+function elgg_load_js($name) {
+ elgg_load_external_file('js', $name);
}
/**
- * Automatically views likes and a like input relating to the given entity
+ * Get the JavaScript URLs that are loaded
*
- * @param ElggEntity $entity The entity to like
- * @return string|false The HTML (etc) for the likes, or false on failure
- * @since 1.8
+ * @param string $location 'head' or 'footer'
+ *
+ * @return array
+ * @since 1.8.0
*/
-function elgg_view_likes($entity){
- if (!($entity instanceof ElggEntity)) {
- return false;
- }
- if ($likes = trigger_plugin_hook('likes', $entity->getType(), array('entity' => $entity), false)) {
- return $likes;
- } else {
- //display the form
- $likes = elgg_view('likes/forms/edit', array('entity' => $entity));
- return $likes;
- }
+function elgg_get_loaded_js($location = 'head') {
+ return elgg_get_loaded_external_files('js', $location);
}
/**
- * Count the number of likes attached to an entity
+ * Register a CSS file for inclusion in the HTML head
*
- * @param ElggEntity $entity
- * @return int Number of likes
- * @since 1.8
+ * @param string $name An identifier for the CSS file
+ * @param string $url URL of the CSS file
+ * @param int $priority Priority of the CSS file (lower numbers load earlier)
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function elgg_count_likes($entity) {
- if ($likeno = trigger_plugin_hook('likes:count', $entity->getType(),
- array('entity' => $entity), false)) {
- return $likeno;
- } else {
- return count_annotations($entity->getGUID(), "", "", "likes");
- }
+function elgg_register_css($name, $url, $priority = null) {
+ return elgg_register_external_file('css', $name, $url, 'head', $priority);
}
/**
- * Count the number of comments attached to an entity
+ * Unregister a CSS file
*
- * @param ElggEntity $entity
- * @return int Number of comments
+ * @param string $name The identifier for the CSS file
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function elgg_count_comments($entity) {
- if ($commentno = trigger_plugin_hook('comments:count', $entity->getType(),
- array('entity' => $entity), false)) {
- return $commentno;
- } else {
- return count_annotations($entity->getGUID(), "", "", "generic_comment");
- }
+function elgg_unregister_css($name) {
+ return elgg_unregister_external_file('css', $name);
}
-
-
/**
- * Library loading and handling
+ * Load a CSS file for this page
+ *
+ * This must be called before elgg_view_page(). It can be called before the
+ * CSS file is registered. If you do not want a CSS file loaded, unregister it.
+ *
+ * @param string $name Identifier of the CSS file
+ *
+ * @return void
+ * @since 1.8.0
*/
+function elgg_load_css($name) {
+ elgg_load_external_file('css', $name);
+}
/**
- * @deprecated 1.7
+ * Get the loaded CSS URLs
+ *
+ * @return array
+ * @since 1.8.0
*/
-function get_library_files($directory, $exceptions = array(), $list = array()) {
- elgg_deprecated_notice('get_library_files() deprecated by elgg_get_file_list()', 1.7);
- return elgg_get_file_list($directory, $exceptions, $list, array('.php'));
+function elgg_get_loaded_css() {
+ return elgg_get_loaded_external_files('css', 'head');
}
/**
- * Returns a list of files in $directory
+ * Core registration function for external files
*
- * @param str $directory
- * @param array $exceptions Array of filenames to ignore
- * @param array $list Array of files to append to
- * @param mixed $extensions Array of extensions to allow, NULL for all. (With a dot: array('.php'))
- * @return array of filenames including $directory
+ * @param string $type Type of external resource (js or css)
+ * @param string $name Identifier used as key
+ * @param string $url URL
+ * @param string $location Location in the page to include the file
+ * @param int $priority Loading priority of the file
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function elgg_get_file_list($directory, $exceptions = array(), $list = array(), $extensions = NULL) {
- $directory = sanitise_filepath($directory);
- if ($handle = opendir($directory)) {
- while (($file = readdir($handle)) !== FALSE) {
- if (!is_file($directory . $file) || in_array($file, $exceptions)) {
- continue;
- }
+function elgg_register_external_file($type, $name, $url, $location, $priority = 500) {
+ global $CONFIG;
- if (is_array($extensions)) {
- if (in_array(strrchr($file, '.'), $extensions)) {
- $list[] = $directory . $file;
- }
- } else {
- $list[] = $directory . $file;
- }
- }
- closedir($handle);
+ if (empty($name) || empty($url)) {
+ return false;
}
- return $list;
-}
+ $url = elgg_format_url($url);
+ $url = elgg_normalize_url($url);
+
+ elgg_bootstrap_externals_data_structure($type);
-/**
- * Ensures that the installation has all the correct files, that PHP is configured correctly, and so on.
- * Leaves appropriate messages in the error register if not.
- *
- * @return true|false True if everything is ok (or Elgg is fit enough to run); false if not.
- */
-function sanitised() {
- $sanitised = true;
+ $name = trim(strtolower($name));
- if (!file_exists(dirname(dirname(__FILE__)) . "/settings.php")) {
- // See if we are being asked to save the file
- $save_vars = get_input('db_install_vars');
- $result = "";
- if ($save_vars) {
- $rtn = db_check_settings($save_vars['CONFIG_DBUSER'],
- $save_vars['CONFIG_DBPASS'],
- $save_vars['CONFIG_DBNAME'],
- $save_vars['CONFIG_DBHOST'] );
- if ($rtn == FALSE) {
- register_error(elgg_view("messages/sanitisation/dbsettings_error"));
- register_error(elgg_view("messages/sanitisation/settings",
- array( 'settings.php' => $result,
- 'sticky' => $save_vars)));
- return FALSE;
- }
+ // normalize bogus priorities, but allow empty, null, and false to be defaults.
+ if (!is_numeric($priority)) {
+ $priority = 500;
+ }
- $result = create_settings($save_vars, dirname(dirname(__FILE__)) . "/settings.example.php");
+ // no negative priorities right now.
+ $priority = max((int)$priority, 0);
+ $item = elgg_extract($name, $CONFIG->externals_map[$type]);
- if (file_put_contents(dirname(dirname(__FILE__)) . "/settings.php", $result)) {
- // blank result to stop it being displayed in textarea
- $result = "";
- }
- }
+ if ($item) {
+ // updating a registered item
+ // don't update loaded because it could already be set
+ $item->url = $url;
+ $item->location = $location;
- // Recheck to see if the file is still missing
- if (!file_exists(dirname(dirname(__FILE__)) . "/settings.php")) {
- register_error(elgg_view("messages/sanitisation/settings", array('settings.php' => $result)));
- $sanitised = false;
+ // if loaded before registered, that means it hasn't been added to the list yet
+ if ($CONFIG->externals[$type]->contains($item)) {
+ $priority = $CONFIG->externals[$type]->move($item, $priority);
+ } else {
+ $priority = $CONFIG->externals[$type]->add($item, $priority);
}
- }
+ } else {
+ $item = new stdClass();
+ $item->loaded = false;
+ $item->url = $url;
+ $item->location = $location;
- if (!file_exists(dirname(dirname(dirname(__FILE__))) . "/.htaccess")) {
- if (!@copy(dirname(dirname(dirname(__FILE__))) . "/htaccess_dist", dirname(dirname(dirname(__FILE__))) . "/.htaccess")) {
- register_error(elgg_view("messages/sanitisation/htaccess", array('.htaccess' => file_get_contents(dirname(dirname(dirname(__FILE__))) . "/htaccess_dist"))));
- $sanitised = false;
- }
+ $priority = $CONFIG->externals[$type]->add($item, $priority);
}
- return $sanitised;
-}
+ $CONFIG->externals_map[$type][$name] = $item;
-/**
- * Registers
- */
+ return $priority !== false;
+}
/**
- * Adds an array with a name to a given generic array register.
- * For example, these are used for menus.
+ * Unregister an external file
+ *
+ * @param string $type Type of file: js or css
+ * @param string $name The identifier of the file
*
- * @param string $register_name The name of the top-level register
- * @param string $subregister_name The name of the subregister
- * @param mixed $subregister_value The value of the subregister
- * @param array $children_array Optionally, an array of children
- * @return true|false Depending on success
+ * @return bool
+ * @since 1.8.0
*/
-function add_to_register($register_name, $subregister_name, $subregister_value, $children_array = array()) {
+function elgg_unregister_external_file($type, $name) {
global $CONFIG;
- if (empty($register_name) || empty($subregister_name)) {
- return false;
- }
-
- if (!isset($CONFIG->registers)) {
- $CONFIG->registers = array();
- }
-
- if (!isset($CONFIG->registers[$register_name])) {
- $CONFIG->registers[$register_name] = array();
- }
+ elgg_bootstrap_externals_data_structure($type);
- $subregister = new stdClass;
- $subregister->name = $subregister_name;
- $subregister->value = $subregister_value;
+ $name = trim(strtolower($name));
+ $item = elgg_extract($name, $CONFIG->externals_map[$type]);
- if (is_array($children_array)) {
- $subregister->children = $children_array;
+ if ($item) {
+ unset($CONFIG->externals_map[$type][$name]);
+ return $CONFIG->externals[$type]->remove($item);
}
- $CONFIG->registers[$register_name][$subregister_name] = $subregister;
- return true;
+ return false;
}
/**
- * Removes what has been registered at [register_name][subregister_name]
+ * Load an external resource for use on this page
*
- * @param string $register_name The name of the top-level register
- * @param string $subregister_name The name of the subregister
- * @return true|false Depending on success
+ * @param string $type Type of file: js or css
+ * @param string $name The identifier for the file
+ *
+ * @return void
+ * @since 1.8.0
*/
-function remove_from_register($register_name, $subregister_name) {
+function elgg_load_external_file($type, $name) {
global $CONFIG;
- if (empty($register_name) || empty($subregister_name)) {
- return false;
- }
-
- if (!isset($CONFIG->registers)) {
- return false;
- }
+ elgg_bootstrap_externals_data_structure($type);
- if (!isset($CONFIG->registers[$register_name])) {
- return false;
- }
+ $name = trim(strtolower($name));
- if (isset($CONFIG->registers[$register_name][$subregister_name])) {
- unset($CONFIG->registers[$register_name][$subregister_name]);
- return true;
- }
+ $item = elgg_extract($name, $CONFIG->externals_map[$type]);
- return false;
-}
+ if ($item) {
+ // update a registered item
+ $item->loaded = true;
+ } else {
+ $item = new stdClass();
+ $item->loaded = true;
+ $item->url = '';
+ $item->location = '';
-/**
- * Returns a register object
- *
- * @param string $register_name The name of the register
- * @param mixed $register_value The value of the register
- * @param array $children_array Optionally, an array of children
- * @return false|stdClass Depending on success
- */
-function make_register_object($register_name, $register_value, $children_array = array()) {
- elgg_deprecated_notice('make_register_object() is deprecated by add_submenu_item()', 1.7);
- if (empty($register_name) || empty($register_value)) {
- return false;
+ $CONFIG->externals[$type]->add($item);
+ $CONFIG->externals_map[$type][$name] = $item;
}
-
- $register = new stdClass;
- $register->name = $register_name;
- $register->value = $register_value;
- $register->children = $children_array;
-
- return $register;
}
/**
- * If it exists, returns a particular register as an array
+ * Get external resource descriptors
+ *
+ * @param string $type Type of file: js or css
+ * @param string $location Page location
*
- * @param string $register_name The name of the register
- * @return array|false Depending on success
+ * @return array
+ * @since 1.8.0
*/
-function get_register($register_name) {
+function elgg_get_loaded_external_files($type, $location) {
global $CONFIG;
- if (isset($CONFIG->registers[$register_name])) {
- return $CONFIG->registers[$register_name];
- }
+ if (isset($CONFIG->externals) && $CONFIG->externals[$type] instanceof ElggPriorityList) {
+ $items = $CONFIG->externals[$type]->getElements();
- return false;
+ $callback = "return \$v->loaded == true && \$v->location == '$location';";
+ $items = array_filter($items, create_function('$v', $callback));
+ if ($items) {
+ array_walk($items, create_function('&$v,$k', '$v = $v->url;'));
+ }
+ return $items;
+ }
+ return array();
}
/**
- * Adds an item to the menu register
- * This is used in the core to create the tools dropdown menu
- * You can obtain the menu array by calling get_register('menu')
+ * Bootstraps the externals data structure in $CONFIG.
*
- * @param string $menu_name The name of the menu item
- * @param string $menu_url The URL of the page
- * @param array $menu_children Optionally, an array of submenu items (not currently used)
- * @param string $context
- * @return true|false Depending on success
+ * @param string $type The type of external, js or css.
+ * @access private
*/
-function add_menu($menu_name, $menu_url, $menu_children = array(), $context = "") {
+function elgg_bootstrap_externals_data_structure($type) {
global $CONFIG;
- if (!isset($CONFIG->menucontexts)) {
- $CONFIG->menucontexts = array();
+ if (!isset($CONFIG->externals)) {
+ $CONFIG->externals = array();
}
- if (empty($context)) {
- $context = get_plugin_name();
+ if (!isset($CONFIG->externals[$type]) || !$CONFIG->externals[$type] instanceof ElggPriorityList) {
+ $CONFIG->externals[$type] = new ElggPriorityList();
}
- $value = new stdClass();
- $value->url = $menu_url;
- $value->context = $context;
+ if (!isset($CONFIG->externals_map)) {
+ $CONFIG->externals_map = array();
+ }
- $CONFIG->menucontexts[] = $context;
- return add_to_register('menu', $menu_name, $value, $menu_children);
+ if (!isset($CONFIG->externals_map[$type])) {
+ $CONFIG->externals_map[$type] = array();
+ }
}
/**
- * Removes an item from the menu register
+ * Returns a list of files in $directory.
+ *
+ * Only returns files. Does not recurse into subdirs.
+ *
+ * @param string $directory Directory to look in
+ * @param array $exceptions Array of filenames to ignore
+ * @param array $list Array of files to append to
+ * @param mixed $extensions Array of extensions to allow, NULL for all. Use a dot: array('.php').
*
- * @param string $menu_name The name of the menu item
- * @return true|false Depending on success
+ * @return array Filenames in $directory, in the form $directory/filename.
*/
-function remove_menu($menu_name) {
- return remove_from_register('menu', $menu_name);
+function elgg_get_file_list($directory, $exceptions = array(), $list = array(),
+$extensions = NULL) {
+
+ $directory = sanitise_filepath($directory);
+ if ($handle = opendir($directory)) {
+ while (($file = readdir($handle)) !== FALSE) {
+ if (!is_file($directory . $file) || in_array($file, $exceptions)) {
+ continue;
+ }
+
+ if (is_array($extensions)) {
+ if (in_array(strrchr($file, '.'), $extensions)) {
+ $list[] = $directory . $file;
+ }
+ } else {
+ $list[] = $directory . $file;
+ }
+ }
+ closedir($handle);
+ }
+
+ return $list;
}
/**
- * Returns a menu item for use in the children section of add_menu()
- * This is not currently used in the Elgg core
+ * Sanitise file paths ensuring that they begin and end with slashes etc.
*
- * @param string $menu_name The name of the menu item
- * @param string $menu_url Its URL
- * @return stdClass|false Depending on success
+ * @param string $path The path
+ * @param bool $append_slash Add tailing slash
+ *
+ * @return string
*/
-function menu_item($menu_name, $menu_url) {
- elgg_deprecated_notice('menu_item() is deprecated by add_submenu_item', 1.7);
- return make_register_object($menu_name, $menu_url);
+function sanitise_filepath($path, $append_slash = TRUE) {
+ // Convert to correct UNIX paths
+ $path = str_replace('\\', '/', $path);
+ $path = str_replace('../', '/', $path);
+ // replace // with / except when preceeded by :
+ $path = preg_replace("/([^:])\/\//", "$1/", $path);
+
+ // Sort trailing slash
+ $path = trim($path);
+ // rtrim defaults plus /
+ $path = rtrim($path, " \n\t\0\x0B/");
+
+ if ($append_slash) {
+ $path = $path . '/';
+ }
+
+ return $path;
}
/**
- * Message register handling
- * If a null $message parameter is given, the function returns the array of messages so far and empties it
- * based on the $register parameters. Otherwise, any message or array of messages is added.
+ * Queues a message to be displayed.
+ *
+ * Messages will not be displayed immediately, but are stored in
+ * for later display, usually upon next page load.
+ *
+ * The method of displaying these messages differs depending upon plugins and
+ * viewtypes. The core default viewtype retrieves messages in
+ * {@link views/default/page/shells/default.php} and displays messages as
+ * javascript popups.
+ *
+ * @internal Messages are stored as strings in the $_SESSION['msg'][$register] array.
+ *
+ * @warning This function is used to both add to and clear the message
+ * stack. If $messages is null, $register will be returned and cleared.
+ * If $messages is null and $register is empty, all messages will be
+ * returned and removed.
+ *
+ * @important This function handles the standard {@link system_message()} ($register =
+ * 'messages') as well as {@link register_error()} messages ($register = 'errors').
+ *
+ * @param mixed $message Optionally, a single message or array of messages to add, (default: null)
+ * @param string $register Types of message: "error", "success" (default: success)
+ * @param bool $count Count the number of messages (default: false)
*
- * @param string|array $message Optionally, a single message or array of messages to add, (default: null)
- * @param string $register This allows for different types of messages: "errors", "messages" (default: messages)
- * @param bool $count Count the number of messages (default: false)
- * @return true|false|array Either the array of messages, or a response regarding whether the message addition was successful
+ * @return bool|array Either the array of messages, or a response regarding
+ * whether the message addition was successful.
+ * @todo Clean up. Separate registering messages and retrieving them.
*/
-function system_messages($message = null, $register = "messages", $count = false) {
+function system_messages($message = null, $register = "success", $count = false) {
if (!isset($_SESSION['msg'])) {
$_SESSION['msg'] = array();
}
@@ -809,7 +570,7 @@ function system_messages($message = null, $register = "messages", $count = false
return sizeof($_SESSION['msg'][$register]);
} else {
$count = 0;
- foreach($_SESSION['msg'] as $register => $submessages) {
+ foreach ($_SESSION['msg'] as $submessages) {
$count += sizeof($submessages);
}
return $count;
@@ -822,287 +583,414 @@ function system_messages($message = null, $register = "messages", $count = false
* Counts the number of messages, either globally or in a particular register
*
* @param string $register Optionally, the register
+ *
* @return integer The number of messages
*/
function count_messages($register = "") {
- return system_messages(null,$register,true);
+ return system_messages(null, $register, true);
}
/**
- * An alias for system_messages($message) to handle standard user information messages
+ * Display a system message on next page load.
+ *
+ * @see system_messages()
*
* @param string|array $message Message or messages to add
- * @return true|false Success response
+ *
+ * @return bool
*/
function system_message($message) {
- return system_messages($message, "messages");
+ return system_messages($message, "success");
}
/**
- * An alias for system_messages($message) to handle error messages
+ * Display an error on next page load.
+ *
+ * @see system_messages()
*
- * @param string|array $message Error or errors to add
- * @return true|false Success response
+ * @param string|array $error Error or errors to add
+ *
+ * @return bool
*/
function register_error($error) {
- return system_messages($error, "errors");
+ return system_messages($error, "error");
}
/**
- * Event register
- * Adds functions to the register for a particular event, but also calls all functions registered to an event when required
+ * Register a callback as an Elgg event handler.
*
- * Event handler functions must be of the form:
+ * Events are emitted by Elgg when certain actions occur. Plugins
+ * can respond to these events or halt them completely by registering a handler
+ * as a callback to an event. Multiple handlers can be registered for
+ * the same event and will be executed in order of $priority. Any handler
+ * returning false will halt the execution chain.
*
- * event_handler_function($event, $object_type, $object);
+ * This function is called with the event name, event type, and handler callback name.
+ * Setting the optional $priority allows plugin authors to specify when the
+ * callback should be run. Priorities for plugins should be 1-1000.
*
- * And must return true or false depending on success. A false will halt the event in its tracks and no more functions will be called.
+ * The callback is passed 3 arguments when called: $event, $type, and optional $params.
*
- * You can then simply register them using the following function. Optionally, this can be called with a priority nominally from 0 to 1000, where functions with lower priority values are called first (note that priorities CANNOT be negative):
+ * $event is the name of event being emitted.
+ * $type is the type of event or object concerned.
+ * $params is an optional parameter passed that can include a related object. See
+ * specific event documentation for details on which events pass what parameteres.
*
- * register_elgg_event_handler($event, $object_type, $function_name [, $priority = 500]);
+ * @tip If a priority isn't specified it is determined by the order the handler was
+ * registered relative to the event and type. For plugins, this generally means
+ * the earlier the plugin is in the load order, the earlier the priorities are for
+ * any event handlers.
*
- * Note that you can also use 'all' in place of both the event and object type.
+ * @tip $event and $object_type can use the special keyword 'all'. Handler callbacks registered
+ * with $event = all will be called for all events of type $object_type. Similarly,
+ * callbacks registered with $object_type = all will be called for all events of type
+ * $event, regardless of $object_type. If $event and $object_type both are 'all', the
+ * handler callback will be called for all events.
*
- * To trigger an event properly, you should always use:
+ * @tip Event handler callbacks are considered in the follow order:
+ * - Specific registration where 'all' isn't used.
+ * - Registration where 'all' is used for $event only.
+ * - Registration where 'all' is used for $type only.
+ * - Registration where 'all' is used for both.
*
- * trigger_elgg_event($event, $object_type [, $object]);
+ * @warning If you use the 'all' keyword, you must have logic in the handler callback to
+ * test the passed parameters before taking an action.
*
- * Where $object is optional, and represents the $object_type the event concerns. This will return true if successful, or false if it fails.
+ * @tip When referring to events, the preferred syntax is "event, type".
*
- * @param string $event The type of event (eg 'init', 'update', 'delete')
- * @param string $object_type The type of object (eg 'system', 'blog', 'user')
- * @param string $function The name of the function that will handle the event
- * @param int $priority A priority to add new event handlers at. Lower numbers will be called first (default 500)
- * @param boolean $call Set to true to call the event rather than add to it (default false)
- * @param mixed $object Optionally, the object the event is being performed on (eg a user)
- * @return true|false Depending on success
+ * @internal Events are stored in $CONFIG->events as:
+ * <code>
+ * $CONFIG->events[$event][$type][$priority] = $callback;
+ * </code>
+ *
+ * @param string $event The event type
+ * @param string $object_type The object type
+ * @param string $callback The handler callback
+ * @param int $priority The priority - 0 is default, negative before, positive after
+ *
+ * @return bool
+ * @link http://docs.elgg.org/Tutorials/Plugins/Events
+ * @example events/basic.php Basic example of registering an event handler callback.
+ * @example events/advanced.php Advanced example of registering an event handler
+ * callback and halting execution.
+ * @example events/all.php Example of how to use the 'all' keyword.
*/
-function events($event = "", $object_type = "", $function = "", $priority = 500, $call = false, $object = null) {
+function elgg_register_event_handler($event, $object_type, $callback, $priority = 500) {
global $CONFIG;
+ if (empty($event) || empty($object_type)) {
+ return false;
+ }
+
if (!isset($CONFIG->events)) {
$CONFIG->events = array();
- } else if (!isset($CONFIG->events[$event]) && !empty($event)) {
+ }
+ if (!isset($CONFIG->events[$event])) {
$CONFIG->events[$event] = array();
- } else if (!isset($CONFIG->events[$event][$object_type]) && !empty($event) && !empty($object_type)) {
+ }
+ if (!isset($CONFIG->events[$event][$object_type])) {
$CONFIG->events[$event][$object_type] = array();
}
- if (!$call) {
- if (!empty($event) && !empty($object_type) && is_callable($function)) {
- $priority = (int) $priority;
- if ($priority < 0) {
- $priority = 0;
- }
- while (isset($CONFIG->events[$event][$object_type][$priority])) {
- $priority++;
- }
- $CONFIG->events[$event][$object_type][$priority] = $function;
- ksort($CONFIG->events[$event][$object_type]);
- return true;
- } else {
- return false;
- }
- } else {
- $return = true;
- if (!empty($CONFIG->events[$event][$object_type]) && is_array($CONFIG->events[$event][$object_type])) {
- foreach($CONFIG->events[$event][$object_type] as $eventfunction) {
- if ($eventfunction($event, $object_type, $object) === false) {
- return false;
- }
- }
- }
-
- if (!empty($CONFIG->events['all'][$object_type]) && is_array($CONFIG->events['all'][$object_type])) {
- foreach($CONFIG->events['all'][$object_type] as $eventfunction) {
- if ($eventfunction($event, $object_type, $object) === false) {
- return false;
- }
- }
- }
-
- if (!empty($CONFIG->events[$event]['all']) && is_array($CONFIG->events[$event]['all'])) {
- foreach($CONFIG->events[$event]['all'] as $eventfunction) {
- if ($eventfunction($event, $object_type, $object) === false) {
- return false;
- }
- }
- }
-
- if (!empty($CONFIG->events['all']['all']) && is_array($CONFIG->events['all']['all'])) {
- foreach($CONFIG->events['all']['all'] as $eventfunction) {
- if ($eventfunction($event, $object_type, $object) === false) {
- return false;
- }
- }
- }
+ if (!is_callable($callback, true)) {
+ return false;
+ }
- return $return;
+ $priority = max((int) $priority, 0);
+ while (isset($CONFIG->events[$event][$object_type][$priority])) {
+ $priority++;
}
-
- return false;
+ $CONFIG->events[$event][$object_type][$priority] = $callback;
+ ksort($CONFIG->events[$event][$object_type]);
+ return true;
}
/**
- * Alias function for events, that registers a function to a particular kind of event
+ * Unregisters a callback for an event.
*
- * @param string $event The event type
+ * @param string $event The event type
* @param string $object_type The object type
- * @param string $function The function name
- * @return true|false Depending on success
- */
-function register_elgg_event_handler($event, $object_type, $function, $priority = 500) {
- return events($event, $object_type, $function, $priority);
-}
-
-/**
- * Unregisters a function to a particular kind of event
+ * @param string $callback The callback
*
- * @param string $event The event type
- * @param string $object_type The object type
- * @param string $function The function name
+ * @return void
+ * @since 1.7
*/
-function unregister_elgg_event_handler($event, $object_type, $function) {
+function elgg_unregister_event_handler($event, $object_type, $callback) {
global $CONFIG;
- foreach($CONFIG->events[$event][$object_type] as $key => $event_function) {
- if ($event_function == $function) {
- unset($CONFIG->events[$event][$object_type][$key]);
+
+ if (isset($CONFIG->events[$event]) && isset($CONFIG->events[$event][$object_type])) {
+ foreach ($CONFIG->events[$event][$object_type] as $key => $event_callback) {
+ if ($event_callback == $callback) {
+ unset($CONFIG->events[$event][$object_type][$key]);
+ }
}
}
}
/**
- * Alias function for events, that triggers a particular kind of event
+ * Trigger an Elgg Event and run all handler callbacks registered to that event, type.
+ *
+ * This function runs all handlers registered to $event, $object_type or
+ * the special keyword 'all' for either or both.
+ *
+ * $event is usually a verb: create, update, delete, annotation.
+ *
+ * $object_type is usually a noun: object, group, user, annotation, relationship, metadata.
+ *
+ * $object is usually an Elgg* object assciated with the event.
*
- * @param string $event The event type
+ * @warning Elgg events should only be triggered by core. Plugin authors should use
+ * {@link trigger_elgg_plugin_hook()} instead.
+ *
+ * @tip When referring to events, the preferred syntax is "event, type".
+ *
+ * @internal Only rarely should events be changed, added, or removed in core.
+ * When making changes to events, be sure to first create a ticket on Github.
+ *
+ * @internal @tip Think of $object_type as the primary namespace element, and
+ * $event as the secondary namespace.
+ *
+ * @param string $event The event type
* @param string $object_type The object type
- * @param string $function The function name
- * @return true|false Depending on success
+ * @param string $object The object involved in the event
+ *
+ * @return bool The result of running all handler callbacks.
+ * @link http://docs.elgg.org/Tutorials/Core/Events
+ * @internal @example events/emit.php Basic emitting of an Elgg event.
*/
-function trigger_elgg_event($event, $object_type, $object = null) {
- $return = true;
- $return1 = events($event, $object_type, "", null, true, $object);
- if (!is_null($return1)) {
- $return = $return1;
+function elgg_trigger_event($event, $object_type, $object = null) {
+ global $CONFIG;
+
+ $events = array();
+ if (isset($CONFIG->events[$event][$object_type])) {
+ $events[] = $CONFIG->events[$event][$object_type];
}
- return $return;
+ if (isset($CONFIG->events['all'][$object_type])) {
+ $events[] = $CONFIG->events['all'][$object_type];
+ }
+ if (isset($CONFIG->events[$event]['all'])) {
+ $events[] = $CONFIG->events[$event]['all'];
+ }
+ if (isset($CONFIG->events['all']['all'])) {
+ $events[] = $CONFIG->events['all']['all'];
+ }
+
+ $args = array($event, $object_type, $object);
+
+ foreach ($events as $callback_list) {
+ if (is_array($callback_list)) {
+ foreach ($callback_list as $callback) {
+ if (is_callable($callback) && (call_user_func_array($callback, $args) === false)) {
+ return false;
+ }
+ }
+ }
+ }
+
+ return true;
}
/**
- * Register a function to a plugin hook for a particular hook name and type, with a given priority.
+ * Register a callback as a plugin hook handler.
+ *
+ * Plugin hooks allow developers to losely couple plugins and features by
+ * repsonding to and emitting {@link elgg_trigger_plugin_hook()} customizable hooks.
+ * Handler callbacks can respond to the hook, change the details of the hook, or
+ * ignore it.
+ *
+ * Multiple handlers can be registered for a plugin hook, and each callback
+ * is called in order of priority. If the return value of a handler is not
+ * null, that value is passed to the next callback in the call stack. When all
+ * callbacks have been run, the final value is passed back to the caller
+ * via {@link elgg_trigger_plugin_hook()}.
+ *
+ * Similar to Elgg Events, plugin hook handler callbacks are registered by passing
+ * a hook, a type, and a priority.
+ *
+ * The callback is passed 4 arguments when called: $hook, $type, $value, and $params.
+ *
+ * - str $hook The name of the hook.
+ * - str $type The type of hook.
+ * - mixed $value The return value of the last handler or the default
+ * value if no other handlers have been called.
+ * - mixed $params An optional array of parameters. Used to provide additional
+ * information to plugins.
*
- * eg if you want the function "export_user" to be called when the hook "export" for "user" entities
- * is run, use:
+ * @internal Plugin hooks are stored in $CONFIG->hooks as:
+ * <code>
+ * $CONFIG->hooks[$hook][$type][$priority] = $callback;
+ * </code>
*
- * register_plugin_hook("export", "user", "export_user");
+ * @tip Plugin hooks are similar to Elgg Events in that Elgg emits
+ * a plugin hook when certain actions occur, but a plugin hook allows you to alter the
+ * parameters, as well as halt execution.
*
- * "all" is a valid value for both $hook and $entity_type. "none" is a valid value for $entity_type.
+ * @tip If a priority isn't specified it is determined by the order the handler was
+ * registered relative to the event and type. For plugins, this generally means
+ * the earlier the plugin is in the load order, the earlier the priorities are for
+ * any event handlers.
*
- * The export_user function would then be defined as:
+ * @tip Like Elgg Events, $hook and $type can use the special keyword 'all'.
+ * Handler callbacks registered with $hook = all will be called for all hooks
+ * of type $type. Similarly, handlers registered with $type = all will be
+ * called for all hooks of type $event, regardless of $object_type. If $hook
+ * and $type both are 'all', the handler will be called for all hooks.
*
- * function export_user($hook, $entity_type, $returnvalue, $params);
+ * @tip Plugin hooks are sometimes used to gather lists from plugins. This is
+ * usually done by pushing elements into an array passed in $params. Be sure
+ * to append to and then return $value so you don't overwrite other plugin's
+ * values.
*
- * Where $returnvalue is the return value returned by the last function returned by the hook, and
- * $params is an array containing a set of parameters (or nothing).
+ * @warning Unlike Elgg Events, a handler that returns false will NOT halt the
+ * execution chain.
*
- * @param string $hook The name of the hook
- * @param string $type The type of the hook (NB Can be an ElggEntity type [user, object, group, site] or custom-defined 'get_sections')
- * @param string $function The name of a valid function to be run
- * @param string $priority The priority - 0 is first, 1000 last, default is 500
- * @return true|false Depending on success
+ * @param string $hook The name of the hook
+ * @param string $type The type of the hook
+ * @param callable $callback The name of a valid function or an array with object and method
+ * @param int $priority The priority - 500 is default, lower numbers called first
+ *
+ * @return bool
+ *
+ * @example hooks/register/basic.php Registering for a plugin hook and examining the variables.
+ * @example hooks/register/advanced.php Registering for a plugin hook and changing the params.
+ * @link http://docs.elgg.org/Tutorials/Plugins/Hooks
+ * @since 1.8.0
*/
-function register_plugin_hook($hook, $type, $function, $priority = 500) {
+function elgg_register_plugin_hook_handler($hook, $type, $callback, $priority = 500) {
global $CONFIG;
+ if (empty($hook) || empty($type)) {
+ return false;
+ }
+
if (!isset($CONFIG->hooks)) {
$CONFIG->hooks = array();
- } else if (!isset($CONFIG->hooks[$hook]) && !empty($hook)) {
+ }
+ if (!isset($CONFIG->hooks[$hook])) {
$CONFIG->hooks[$hook] = array();
- } else if (!isset($CONFIG->hooks[$hook][$type]) && !empty($type)) {
+ }
+ if (!isset($CONFIG->hooks[$hook][$type])) {
$CONFIG->hooks[$hook][$type] = array();
}
- if (!empty($hook) && !empty($type) && is_callable($function)) {
- $priority = (int) $priority;
- if ($priority < 0) {
- $priority = 0;
- }
- while (isset($CONFIG->hooks[$hook][$type][$priority])) {
- $priority++;
- }
- $CONFIG->hooks[$hook][$type][$priority] = $function;
- ksort($CONFIG->hooks[$hook][$type]);
- return true;
- } else {
+ if (!is_callable($callback, true)) {
return false;
}
+
+ $priority = max((int) $priority, 0);
+
+ while (isset($CONFIG->hooks[$hook][$type][$priority])) {
+ $priority++;
+ }
+ $CONFIG->hooks[$hook][$type][$priority] = $callback;
+ ksort($CONFIG->hooks[$hook][$type]);
+ return true;
}
/**
- * Unregister a function to a plugin hook for a particular entity type
+ * Unregister a callback as a plugin hook.
+ *
+ * @param string $hook The name of the hook
+ * @param string $entity_type The name of the type of entity (eg "user", "object" etc)
+ * @param callable $callback The PHP callback to be removed
*
- * @param string $hook The name of the hook
- * @param string $entity_type The name of the type of entity (eg "user", "object" etc)
- * @param string $function The name of a valid function to be run
+ * @return void
+ * @since 1.8.0
*/
-function unregister_plugin_hook($hook, $entity_type, $function) {
+function elgg_unregister_plugin_hook_handler($hook, $entity_type, $callback) {
global $CONFIG;
- foreach($CONFIG->hooks[$hook][$entity_type] as $key => $hook_function) {
- if ($hook_function == $function) {
- unset($CONFIG->hooks[$hook][$entity_type][$key]);
+
+ if (isset($CONFIG->hooks[$hook]) && isset($CONFIG->hooks[$hook][$entity_type])) {
+ foreach ($CONFIG->hooks[$hook][$entity_type] as $key => $hook_callback) {
+ if ($hook_callback == $callback) {
+ unset($CONFIG->hooks[$hook][$entity_type][$key]);
+ }
}
}
}
/**
- * Triggers a plugin hook, with various parameters as an array. For example, to provide
- * a 'foo' hook that concerns the type 'bar', with a parameter called 'param1'
- * with value 'value1', that by default returns true, you'd call:
+ * Trigger a Plugin Hook and run all handler callbacks registered to that hook:type.
+ *
+ * This function runs all handlers regsitered to $hook, $type or
+ * the special keyword 'all' for either or both.
+ *
+ * Use $params to send additional information to the handler callbacks.
+ *
+ * $returnvalue Is the initial value to pass to the handlers, which can
+ * then change it. It is useful to use $returnvalue to set defaults.
+ * If no handlers are registered, $returnvalue is immediately returned.
+ *
+ * $hook is usually a verb: import, get_views, output.
+ *
+ * $type is usually a noun: user, ecml, page.
+ *
+ * @tip Like Elgg Events, $hook and $type can use the special keyword 'all'.
+ * Handler callbacks registered with $hook = all will be called for all hooks
+ * of type $type. Similarly, handlers registered with $type = all will be
+ * called for all hooks of type $event, regardless of $object_type. If $hook
+ * and $type both are 'all', the handler will be called for all hooks.
*
- * trigger_plugin_hook('foo', 'bar', array('param1' => 'value1'), true);
+ * @internal The checks for $hook and/or $type not being equal to 'all' is to
+ * prevent a plugin hook being registered with an 'all' being called more than
+ * once if the trigger occurs with an 'all'. An example in core of this is in
+ * actions.php:
+ * elgg_trigger_plugin_hook('action_gatekeeper:permissions:check', 'all', ...)
*
- * @see register_plugin_hook
- * @param string $hook The name of the hook to trigger (NB: "all" will trigger for all $types regardless of $hook value)
- * @param string $type The type of the hook to trigger (NB: "all" will trigger for all $hooks regardless of $type value)
- * @param array $params Any parameters. It's good practice to name the keys, i.e. by using array('name' => 'value', 'name2' => 'value2')
- * @param mixed $returnvalue An initial return value
- * @return mixed|null The cumulative return value for the plugin hook functions
+ * @see elgg_register_plugin_hook_handler()
+ *
+ * @param string $hook The name of the hook to trigger ("all" will
+ * trigger for all $types regardless of $hook value)
+ * @param string $type The type of the hook to trigger ("all" will
+ * trigger for all $hooks regardless of $type value)
+ * @param mixed $params Additional parameters to pass to the handlers
+ * @param mixed $returnvalue An initial return value
+ *
+ * @return mixed|null The return value of the last handler callback called
+ *
+ * @example hooks/trigger/basic.php Trigger a hook that determins if execution
+ * should continue.
+ * @example hooks/trigger/advanced.php Trigger a hook with a default value and use
+ * the results to populate a menu.
+ * @example hooks/basic.php Trigger and respond to a basic plugin hook.
+ * @link http://docs.elgg.org/Tutorials/Plugins/Hooks
+ *
+ * @since 1.8.0
*/
-function trigger_plugin_hook($hook, $type, $params = null, $returnvalue = null) {
+function elgg_trigger_plugin_hook($hook, $type, $params = null, $returnvalue = null) {
global $CONFIG;
- if (!empty($CONFIG->hooks[$hook][$type]) && is_array($CONFIG->hooks[$hook][$type])) {
- foreach($CONFIG->hooks[$hook][$type] as $hookfunction) {
- $temp_return_value = $hookfunction($hook, $type, $returnvalue, $params);
- if (!is_null($temp_return_value)) {
- $returnvalue = $temp_return_value;
- }
+ $hooks = array();
+ if (isset($CONFIG->hooks[$hook][$type])) {
+ if ($hook != 'all' && $type != 'all') {
+ $hooks[] = $CONFIG->hooks[$hook][$type];
}
}
-
- if (!empty($CONFIG->hooks['all'][$type]) && is_array($CONFIG->hooks['all'][$type])) {
- foreach($CONFIG->hooks['all'][$type] as $hookfunction) {
- $temp_return_value = $hookfunction($hook, $type, $returnvalue, $params);
- if (!is_null($temp_return_value)) $returnvalue = $temp_return_value;
+ if (isset($CONFIG->hooks['all'][$type])) {
+ if ($type != 'all') {
+ $hooks[] = $CONFIG->hooks['all'][$type];
}
}
-
- if (!empty($CONFIG->hooks[$hook]['all']) && is_array($CONFIG->hooks[$hook]['all'])) {
- foreach($CONFIG->hooks[$hook]['all'] as $hookfunction) {
- $temp_return_value = $hookfunction($hook, $type, $returnvalue, $params);
- if (!is_null($temp_return_value)) {
- $returnvalue = $temp_return_value;
- }
+ if (isset($CONFIG->hooks[$hook]['all'])) {
+ if ($hook != 'all') {
+ $hooks[] = $CONFIG->hooks[$hook]['all'];
}
}
+ if (isset($CONFIG->hooks['all']['all'])) {
+ $hooks[] = $CONFIG->hooks['all']['all'];
+ }
- if (!empty($CONFIG->hooks['all']['all']) && is_array($CONFIG->hooks['all']['all'])) {
- foreach($CONFIG->hooks['all']['all'] as $hookfunction) {
- $temp_return_value = $hookfunction($hook, $type, $returnvalue, $params);
- if (!is_null($temp_return_value)) {
- $returnvalue = $temp_return_value;
+ foreach ($hooks as $callback_list) {
+ if (is_array($callback_list)) {
+ foreach ($callback_list as $hookcallback) {
+ if (is_callable($hookcallback)) {
+ $args = array($hook, $type, $returnvalue, $params);
+ $temp_return_value = call_user_func_array($hookcallback, $args);
+ if (!is_null($temp_return_value)) {
+ $returnvalue = $temp_return_value;
+ }
+ }
}
}
}
@@ -1111,26 +999,85 @@ function trigger_plugin_hook($hook, $type, $params = null, $returnvalue = null)
}
/**
- * Error handling
+ * Intercepts, logs, and displays uncaught exceptions.
+ *
+ * @warning This function should never be called directly.
+ *
+ * @see http://www.php.net/set-exception-handler
+ *
+ * @param Exception $exception The exception being handled
+ *
+ * @return void
+ * @access private
*/
+function _elgg_php_exception_handler($exception) {
+ $timestamp = time();
+ error_log("Exception #$timestamp: $exception");
+
+ // Wipe any existing output buffer
+ ob_end_clean();
+
+ // make sure the error isn't cached
+ header("Cache-Control: no-cache, must-revalidate", true);
+ header('Expires: Fri, 05 Feb 1982 00:00:00 -0500', true);
+ // @note Do not send a 500 header because it is not a server error
+
+ try {
+ // we don't want the 'pagesetup', 'system' event to fire
+ global $CONFIG;
+ $CONFIG->pagesetupdone = true;
+
+ elgg_set_viewtype('failsafe');
+ if (elgg_is_admin_logged_in()) {
+ $body = elgg_view("messages/exceptions/admin_exception", array(
+ 'object' => $exception,
+ 'ts' => $timestamp
+ ));
+ } else {
+ $body = elgg_view("messages/exceptions/exception", array(
+ 'object' => $exception,
+ 'ts' => $timestamp
+ ));
+ }
+ echo elgg_view_page(elgg_echo('exception:title'), $body);
+ } catch (Exception $e) {
+ $timestamp = time();
+ $message = $e->getMessage();
+ echo "Fatal error in exception handler. Check log for Exception #$timestamp";
+ error_log("Exception #$timestamp : fatal error in exception handler : $message");
+ }
+}
/**
- * PHP Error handler function.
- * This function acts as a wrapper to catch and report PHP error messages.
+ * Intercepts catchable PHP errors.
+ *
+ * @warning This function should never be called directly.
+ *
+ * @internal
+ * For catchable fatal errors, throws an Exception with the error.
+ *
+ * For non-fatal errors, depending upon the debug settings, either
+ * log the error or ignore it.
*
* @see http://www.php.net/set-error-handler
- * @param int $errno The level of the error raised
- * @param string $errmsg The error message
+ *
+ * @param int $errno The level of the error raised
+ * @param string $errmsg The error message
* @param string $filename The filename the error was raised in
- * @param int $linenum The line number the error was raised at
- * @param array $vars An array that points to the active symbol table at the point that the error occurred
+ * @param int $linenum The line number the error was raised at
+ * @param array $vars An array that points to the active symbol table where error occurred
+ *
+ * @return true
+ * @throws Exception
+ * @access private
+ * @todo Replace error_log calls with elgg_log calls.
*/
-function __elgg_php_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
+function _elgg_php_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
$error = date("Y-m-d H:i:s (T)") . ": \"$errmsg\" in file $filename (line $linenum)";
switch ($errno) {
case E_USER_ERROR:
- error_log("ERROR: $error");
+ error_log("PHP ERROR: $error");
register_error("ERROR: $error");
// Since this is a fatal error, we want to stop any further execution but do so gracefully.
@@ -1139,13 +1086,18 @@ function __elgg_php_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
case E_WARNING :
case E_USER_WARNING :
- error_log("WARNING: $error");
+ case E_RECOVERABLE_ERROR: // (e.g. type hint violation)
+
+ // check if the error wasn't suppressed by the error control operator (@)
+ if (error_reporting()) {
+ error_log("PHP WARNING: $error");
+ }
break;
default:
global $CONFIG;
if (isset($CONFIG->debug) && $CONFIG->debug === 'NOTICE') {
- error_log("NOTICE: $error");
+ error_log("PHP NOTICE: $error");
}
}
@@ -1153,19 +1105,25 @@ function __elgg_php_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
}
/**
- * Throws a message to the Elgg logger
+ * Display or log a message.
+ *
+ * If $level is >= to the debug setting in {@link $CONFIG->debug}, the
+ * message will be sent to {@link elgg_dump()}. Messages with lower
+ * priority than {@link $CONFIG->debug} are ignored.
*
- * The Elgg log is currently implemented such that any messages sent at a level
- * greater than or equal to the debug setting will be sent to elgg_dump.
- * The default location for elgg_dump is the screen except for notices.
+ * {@link elgg_dump()} outputs all levels but NOTICE to screen by default.
*
- * Note: No messages will be displayed unless debugging has been enabled.
+ * @note No messages will be displayed unless debugging has been enabled.
+ *
+ * @param string $message User message
+ * @param string $level NOTICE | WARNING | ERROR | DEBUG
*
- * @param str $message User message
- * @param str $level NOTICE | WARNING | ERROR | DEBUG
* @return bool
+ * @since 1.7.0
+ * @todo This is complicated and confusing. Using int constants for debug levels will
+ * make things easier.
*/
-function elgg_log($message, $level='NOTICE') {
+function elgg_log($message, $level = 'NOTICE') {
global $CONFIG;
// only log when debugging is enabled
@@ -1201,25 +1159,31 @@ function elgg_log($message, $level='NOTICE') {
}
/**
- * Extremely generic var_dump-esque wrapper
+ * Logs or displays $value.
+ *
+ * If $to_screen is true, $value is displayed to screen. Else,
+ * it is handled by PHP's {@link error_log()} function.
*
- * Immediately dumps the given $value as a human-readable string.
- * The $value can instead be written to the screen or server log depending on
- * the value of the $to_screen flag.
+ * A {@elgg_plugin_hook debug log} is called. If a handler returns
+ * false, it will stop the default logging method.
+ *
+ * @param mixed $value The value
+ * @param bool $to_screen Display to screen?
+ * @param string $level The debug level
*
- * @param mixed $value
- * @param bool $to_screen
- * @param string $level
* @return void
+ * @since 1.7.0
*/
function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') {
global $CONFIG;
// plugin can return false to stop the default logging method
- $params = array('level' => $level,
- 'msg' => $value,
- 'to_screen' => $to_screen);
- if (!trigger_plugin_hook('debug', 'log', $params, true)) {
+ $params = array(
+ 'level' => $level,
+ 'msg' => $value,
+ 'to_screen' => $to_screen,
+ );
+ if (!elgg_trigger_plugin_hook('debug', 'log', $params, true)) {
return;
}
@@ -1230,6 +1194,11 @@ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') {
$to_screen = FALSE;
}
+ // Do not want to write to JS or CSS pages
+ if (elgg_in_context('js') || elgg_in_context('css')) {
+ $to_screen = FALSE;
+ }
+
if ($to_screen == TRUE) {
echo '<pre>';
print_r($value);
@@ -1240,606 +1209,165 @@ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') {
}
/**
- * Custom exception handler.
- * This function catches any thrown exceptions and handles them appropriately.
+ * Sends a notice about deprecated use of a function, view, etc.
*
- * @see http://www.php.net/set-exception-handler
- * @param Exception $exception The exception being handled
- */
-function __elgg_php_exception_handler($exception) {
- error_log("*** FATAL EXCEPTION *** : " . $exception);
-
- ob_end_clean(); // Wipe any existing output buffer
-
- // make sure the error isn't cached
- header("Cache-Control: no-cache, must-revalidate", true);
- header('Expires: Fri, 05 Feb 1982 00:00:00 -0500', true);
- //header("Internal Server Error", true, 500);
-
- $body = elgg_view("messages/exceptions/exception",array('object' => $exception));
- page_draw(elgg_echo('exception:title'), $body);
-}
-
-/**
- * Data lists
- */
-
-$DATALIST_CACHE = array();
-
-/**
- * Get the value of a particular piece of data in the datalist
+ * This function either displays or logs the deprecation message,
+ * depending upon the deprecation policies in {@link CODING.txt}.
+ * Logged messages are sent with the level of 'WARNING'. Only admins
+ * get visual deprecation notices. When non-admins are logged in, the
+ * notices are sent to PHP's log through elgg_dump().
*
- * @param string $name The name of the datalist
- * @return string|false Depending on success
- */
-function datalist_get($name) {
- global $CONFIG, $DATALIST_CACHE;
-
- // We need this, because sometimes datalists are received before the database is created
- if (!is_db_installed()) {
- return false;
- }
-
- $name = sanitise_string($name);
- if (isset($DATALIST_CACHE[$name])) {
- return $DATALIST_CACHE[$name];
- }
-
- // If memcache enabled then cache value in memcache
- $value = null;
- static $datalist_memcache;
- if ((!$datalist_memcache) && (is_memcache_available())) {
- $datalist_memcache = new ElggMemcache('datalist_memcache');
- }
- if ($datalist_memcache) {
- $value = $datalist_memcache->load($name);
- }
- if ($value) {
- return $value;
- }
-
- // [Marcus Povey 20090217 : Now retrieving all datalist values on first load as this saves about 9 queries per page]
- $result = get_data("SELECT * from {$CONFIG->dbprefix}datalists");
- if ($result) {
- foreach ($result as $row) {
- $DATALIST_CACHE[$row->name] = $row->value;
-
- // Cache it if memcache is available
- if ($datalist_memcache) {
- $datalist_memcache->save($row->name, $row->value);
- }
- }
-
- if (isset($DATALIST_CACHE[$name])) {
- return $DATALIST_CACHE[$name];
- }
- }
-
-
- /*if ($row = get_data_row("SELECT value from {$CONFIG->dbprefix}datalists where name = '{$name}' limit 1")) {
- $DATALIST_CACHE[$name] = $row->value;
-
- // Cache it if memcache is available
- if ($datalist_memcache) $datalist_memcache->save($name, $row->value);
-
- return $row->value;
- }*/
-
- return false;
-}
-
-/**
- * Sets the value for a system-wide piece of data (overwriting a previous value if it exists)
- *
- * @param string $name The name of the datalist
- * @param string $value The new value
- * @return true
- */
-function datalist_set($name, $value) {
-
- global $CONFIG, $DATALIST_CACHE;
-
- $name = sanitise_string($name);
- $value = sanitise_string($value);
-
- // If memcache is available then invalidate the cached copy
- static $datalist_memcache;
- if ((!$datalist_memcache) && (is_memcache_available())) {
- $datalist_memcache = new ElggMemcache('datalist_memcache');
- }
-
- if ($datalist_memcache) {
- $datalist_memcache->delete($name);
- }
-
- //delete_data("delete from {$CONFIG->dbprefix}datalists where name = '{$name}'");
- insert_data("INSERT into {$CONFIG->dbprefix}datalists set name = '{$name}', value = '{$value}' ON DUPLICATE KEY UPDATE value='{$value}'");
-
- $DATALIST_CACHE[$name] = $value;
-
- return true;
-}
-
-/**
- * Runs a function once - not per page load, but per installation.
- * If you like, you can also set the threshold for the function execution - i.e.,
- * if the function was executed before or on $timelastupdatedcheck, this
- * function will run it again.
+ * A user-visual message will be displayed if $dep_version is greater
+ * than 1 minor releases lower than the current Elgg version, or at all
+ * lower than the current Elgg major version.
*
- * @param string $functionname The name of the function you want to run.
- * @param int $timelastupdatedcheck Optionally, the UNIX epoch timestamp of the execution threshold
- * @return true|false Depending on success.
- */
-function run_function_once($functionname, $timelastupdatedcheck = 0) {
- if ($lastupdated = datalist_get($functionname)) {
- $lastupdated = (int) $lastupdated;
- } else {
- $lastupdated = 0;
- }
- if (is_callable($functionname) && $lastupdated <= $timelastupdatedcheck) {
- $functionname();
- datalist_set($functionname,time());
- return true;
- } else {
- return false;
- }
-}
-
-/**
- * Sends a notice about deprecated use of a function, view, etc.
- * Note: This will ALWAYS at least log a warning. Don't use to pre-deprecate things.
+ * @note This will always at least log a warning. Don't use to pre-deprecate things.
* This assumes we are releasing in order and deprecating according to policy.
*
- * @param str $msg Message to log / display.
- * @param str $version human-readable *release* version the function was deprecated. No bloody A, B, (R)C, or D.
+ * @see CODING.txt
+ *
+ * @param string $msg Message to log / display.
+ * @param string $dep_version Human-readable *release* version: 1.7, 1.8, ...
+ * @param int $backtrace_level How many levels back to display the backtrace.
+ * Useful if calling from functions that are called
+ * from other places (like elgg_view()). Set to -1
+ * for a full backtrace.
*
* @return bool
+ * @since 1.7.0
*/
-function elgg_deprecated_notice($msg, $dep_version) {
+function elgg_deprecated_notice($msg, $dep_version, $backtrace_level = 1) {
// if it's a major release behind, visual and logged
- // if it's a 2 minor releases behind, visual and logged
- // if it's 1 minor release behind, logged.
- // bugfixes don't matter because you're not deprecating between them, RIGHT?
+ // if it's a 1 minor release behind, visual and logged
+ // if it's for current minor release, logged.
+ // bugfixes don't matter because we are not deprecating between them
if (!$dep_version) {
- return FALSE;
+ return false;
}
- $elgg_version = get_version(TRUE);
+ $elgg_version = get_version(true);
$elgg_version_arr = explode('.', $elgg_version);
- $elgg_major_version = $elgg_version_arr[0];
- $elgg_minor_version = $elgg_version_arr[1];
+ $elgg_major_version = (int)$elgg_version_arr[0];
+ $elgg_minor_version = (int)$elgg_version_arr[1];
- $dep_version_arr = explode('.', $dep_version);
- $dep_major_version = $dep_version_arr[0];
- $dep_minor_version = $dep_version_arr[1];
+ $dep_major_version = (int)$dep_version;
+ $dep_minor_version = 10 * ($dep_version - $dep_major_version);
- $last_working_version = $dep_minor_version - 1;
+ $visual = false;
- $visual = FALSE;
-
- // use version_compare to account for 1.7a < 1.7
- if (($dep_major_version < $elgg_major_version)
- || (($elgg_minor_version - $last_working_version) > 1)) {
- $visual = TRUE;
+ if (($dep_major_version < $elgg_major_version) ||
+ ($dep_minor_version < $elgg_minor_version)) {
+ $visual = true;
}
- $msg = "Deprecated in $dep_version: $msg";
+ $msg = "Deprecated in $dep_major_version.$dep_minor_version: $msg";
- if ($visual) {
+ if ($visual && elgg_is_admin_logged_in()) {
register_error($msg);
}
// Get a file and line number for the log. Never show this in the UI.
// Skip over the function that sent this notice and see who called the deprecated
// function itself.
+ $msg .= " Called from ";
+ $stack = array();
$backtrace = debug_backtrace();
- $caller = $backtrace[1];
- $msg .= " (Called from {$caller['file']}:{$caller['line']})";
+ // never show this call.
+ array_shift($backtrace);
+ $i = count($backtrace);
- elgg_log($msg, 'WARNING');
+ foreach ($backtrace as $trace) {
+ $stack[] = "[#$i] {$trace['file']}:{$trace['line']}";
+ $i--;
- return TRUE;
-}
-
-
-/**
- * Privilege elevation and gatekeeper code
- */
-
-
-/**
- * Gatekeeper function which ensures that a we are being executed from
- * a specified location.
- *
- * To use, call this function with the function name (and optional file location) that it has to be called
- * from, it will either return true or false.
- *
- * e.g.
- *
- * function my_secure_function()
- * {
- * if (!call_gatekeeper("my_call_function"))
- * return false;
- *
- * ... do secure stuff ...
- * }
- *
- * function my_call_function()
- * {
- * // will work
- * my_secure_function();
- * }
- *
- * function bad_function()
- * {
- * // Will not work
- * my_secure_function();
- * }
- *
- * @param mixed $function The function that this function must have in its call stack,
- * to test against a method pass an array containing a class and method name.
- * @param string $file Optional file that the function must reside in.
- */
-function call_gatekeeper($function, $file = "") {
- // Sanity check
- if (!$function) {
- return false;
- }
-
- // Check against call stack to see if this is being called from the correct location
- $callstack = debug_backtrace();
- $stack_element = false;
-
- foreach ($callstack as $call) {
- if (is_array($function)) {
- if (
- (strcmp($call['class'], $function[0]) == 0) &&
- (strcmp($call['function'], $function[1]) == 0)
- ) {
- $stack_element = $call;
- }
- } else {
- if (strcmp($call['function'], $function) == 0) {
- $stack_element = $call;
+ if ($backtrace_level > 0) {
+ if ($backtrace_level <= 1) {
+ break;
}
+ $backtrace_level--;
}
}
- if (!$stack_element) {
- return false;
- }
-
-
- // If file then check that this it is being called from this function
- if ($file) {
- $mirror = null;
+ $msg .= implode("<br /> -> ", $stack);
- if (is_array($function)) {
- $mirror = new ReflectionMethod($function[0], $function[1]);
- } else {
- $mirror = new ReflectionFunction($function);
- }
-
- if ((!$mirror) || (strcmp($file,$mirror->getFileName())!=0)) {
- return false;
- }
- }
+ elgg_log($msg, 'WARNING');
return true;
}
/**
- * This function checks to see if it is being called at somepoint by a function defined somewhere
- * on a given path (optionally including subdirectories).
+ * Returns the current page's complete URL.
*
- * This function is similar to call_gatekeeper() but returns true if it is being called by a method or function which has been defined on a given path or by a specified file.
+ * The current URL is assembled using the network's wwwroot and the request URI
+ * in $_SERVER as populated by the web server. This function will include
+ * any schemes, usernames and passwords, and ports.
*
- * @param string $path The full path and filename that this function must have in its call stack If a partial path is given and $include_subdirs is true, then the function will return true if called by any function in or below the specified path.
- * @param bool $include_subdirs Are subdirectories of the path ok, or must you specify an absolute path and filename.
- * @param bool $strict_mode If true then the calling method or function must be directly called by something on $path, if false the whole call stack is searched.
+ * @return string The current page URL.
*/
-function callpath_gatekeeper($path, $include_subdirs = true, $strict_mode = false) {
- global $CONFIG;
-
- $path = sanitise_string($path);
-
- if ($path) {
- $callstack = debug_backtrace();
-
- foreach ($callstack as $call) {
- $call['file'] = str_replace("\\","/",$call['file']);
-
- if ($include_subdirs) {
- if (strpos($call['file'], $path) === 0) {
-
- if ($strict_mode) {
- $callstack[1]['file'] = str_replace("\\","/",$callstack[1]['file']);
- if ($callstack[1] === $call) { return true; }
- } else {
- return true;
- }
- }
- } else {
- if (strcmp($path, $call['file'])==0) {
- if ($strict_mode) {
- if ($callstack[1] === $call) {
- return true;
- }
- } else {
- return true;
- }
- }
- }
+function current_page_url() {
+ $url = parse_url(elgg_get_site_url());
- }
- return false;
- }
+ $page = $url['scheme'] . "://";
- if (isset($CONFIG->debug)) {
- system_message("Gatekeeper'd function called from {$callstack[1]['file']}:{$callstack[1]['line']}\n\nStack trace:\n\n" . print_r($callstack, true));
+ // user/pass
+ if ((isset($url['user'])) && ($url['user'])) {
+ $page .= $url['user'];
}
-
- return false;
-}
-
-/**
- * Returns true or false depending on whether a PHP .ini setting is on or off
- *
- * @param string $ini_get_arg The INI setting
- * @return true|false Depending on whether it's on or off
- */
-function ini_get_bool($ini_get_arg) {
- $temp = ini_get($ini_get_arg);
-
- if ($temp == '1' or strtolower($temp) == 'on') {
- return true;
+ if ((isset($url['pass'])) && ($url['pass'])) {
+ $page .= ":" . $url['pass'];
}
- return false;
-}
-
-/**
- * Function to be used in array_filter which returns true if $string is not null.
- *
- * @param string $string
- * @return bool
- */
-function is_not_null($string) {
- if (($string==='') || ($string===false) || ($string===null)) {
- return false;
+ if ((isset($url['user']) && $url['user']) ||
+ (isset($url['pass']) && $url['pass'])) {
+ $page .= "@";
}
- return true;
-}
+ $page .= $url['host'];
+ if ((isset($url['port'])) && ($url['port'])) {
+ $page .= ":" . $url['port'];
+ }
-/**
- * Normalise the singular keys in an options array
- * to the plural keys.
- *
- * @param $options
- * @param $singulars
- * @return array
- */
-function elgg_normalise_plural_options_array($options, $singulars) {
- foreach ($singulars as $singular) {
- $plural = $singular . 's';
+ $page = trim($page, "/");
- // normalize the singular to plural
- // isset() returns FALSE for array values of NULL, so they are ignored.
- // everything else falsy is included.
- //if (isset($options[$singular]) && $options[$singular] !== NULL && $options[$singular] !== FALSE) {
- if (isset($options[$singular])) {
- if (isset($options[$plural])) {
- if (is_array($options[$plural])) {
- $options[$plural][] = $options[$singlar];
- } else {
- $options[$plural] = array($options[$plural], $options[$singular]);
- }
- } else {
- $options[$plural] = array($options[$singular]);
- }
- }
- unset($options[$singular]);
- }
+ $page .= $_SERVER['REQUEST_URI'];
- return $options;
+ return $page;
}
/**
- * Get the full URL of the current page.
+ * Return the full URL of the current page.
*
* @return string The URL
+ * @todo Combine / replace with current_page_url()
*/
function full_url() {
$s = empty($_SERVER["HTTPS"]) ? '' : ($_SERVER["HTTPS"] == "on") ? "s" : "";
- $protocol = substr(strtolower($_SERVER["SERVER_PROTOCOL"]), 0, strpos(strtolower($_SERVER["SERVER_PROTOCOL"]), "/")) . $s;
- $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ? "" : (":".$_SERVER["SERVER_PORT"]);
+ $protocol = substr(strtolower($_SERVER["SERVER_PROTOCOL"]), 0,
+ strpos(strtolower($_SERVER["SERVER_PROTOCOL"]), "/")) . $s;
+
+ $port = ($_SERVER["SERVER_PORT"] == "80" || $_SERVER["SERVER_PORT"] == "443") ?
+ "" : (":" . $_SERVER["SERVER_PORT"]);
+ // This is here to prevent XSS in poorly written browsers used by 80% of the population.
+ // https://github.com/Elgg/Elgg/commit/0c947e80f512cb0a482b1864fd0a6965c8a0cd4a
$quotes = array('\'', '"');
$encoded = array('%27', '%22');
- return $protocol . "://" . $_SERVER['SERVER_NAME'] . $port . str_replace($quotes, $encoded, $_SERVER['REQUEST_URI']);
+ return $protocol . "://" . $_SERVER['SERVER_NAME'] . $port .
+ str_replace($quotes, $encoded, $_SERVER['REQUEST_URI']);
}
/**
- * Useful function found in the comments on the PHP man page for ip2long.
- * Returns 1 if an IP matches a given range.
+ * Builds a URL from the a parts array like one returned by {@link parse_url()}.
*
- * TODO: Check licence... assuming this is PD since it was found several places on the interwebs..
- * please check or rewrite.
+ * @note If only partial information is passed, a partial URL will be returned.
*
- * Matches:
- * xxx.xxx.xxx.xxx (exact)
- * xxx.xxx.xxx.[yyy-zzz] (range)
- * xxx.xxx.xxx.xxx/nn (nn = # bits, cisco style -- i.e. /24 = class C)
- * Does not match:
- * xxx.xxx.xxx.xx[yyy-zzz] (range, partial octets not supported)
- */
-function test_ip($range, $ip) {
- $result = 1;
-
- # IP Pattern Matcher
- # J.Adams <jna@retina.net>
- #
- # Matches:
- #
- # xxx.xxx.xxx.xxx (exact)
- # xxx.xxx.xxx.[yyy-zzz] (range)
- # xxx.xxx.xxx.xxx/nn (nn = # bits, cisco style -- i.e. /24 = class C)
- #
- # Does not match:
- # xxx.xxx.xxx.xx[yyy-zzz] (range, partial octets not supported)
-
- if (ereg("([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/([0-9]+)",$range,$regs)) {
- # perform a mask match
- $ipl = ip2long($ip);
- $rangel = ip2long($regs[1] . "." . $regs[2] . "." . $regs[3] . "." . $regs[4]);
-
- $maskl = 0;
-
- for ($i = 0; $i< 31; $i++) {
- if ($i < $regs[5]-1) {
- $maskl = $maskl + pow(2,(30-$i));
- }
- }
-
- if (($maskl & $rangel) == ($maskl & $ipl)) {
- return 1;
- } else {
- return 0;
- }
- } else {
- # range based
- $maskocts = split("\.",$range);
- $ipocts = split("\.",$ip);
-
- # perform a range match
- for ($i=0; $i<4; $i++) {
- if (ereg("\[([0-9]+)\-([0-9]+)\]",$maskocts[$i],$regs)) {
- if ( ($ipocts[$i] > $regs[2]) || ($ipocts[$i] < $regs[1])) {
- $result = 0;
- }
- } else {
- if ($maskocts[$i] <> $ipocts[$i]) {
- $result = 0;
- }
- }
- }
- }
-
- return $result;
-}
-
-/**
- * Match an IP address against a number of ip addresses or ranges, returning true if found.
+ * @param array $parts Associative array of URL components like parse_url() returns
+ * @param bool $html_encode HTML Encode the url?
*
- * @param array $networks
- * @param string $ip
- * @return bool
- */
-function is_ip_in_array(array $networks, $ip) {
- global $SYSTEM_LOG;
-
- foreach ($networks as $network) {
- if (test_ip(trim($network), $ip)) {
- return true;
- }
- }
-
- return false;
-}
-
-/**
- * An interface for objects that behave as elements within a social network that have a profile.
- *
- */
-interface Friendable {
- /**
- * Adds a user as a friend
- *
- * @param int $friend_guid The GUID of the user to add
- */
- public function addFriend($friend_guid);
-
- /**
- * Removes a user as a friend
- *
- * @param int $friend_guid The GUID of the user to remove
- */
- public function removeFriend($friend_guid);
-
- /**
- * Determines whether or not the current user is a friend of this entity
- *
- */
- public function isFriend();
-
- /**
- * Determines whether or not this entity is friends with a particular entity
- *
- * @param int $user_guid The GUID of the entity this entity may or may not be friends with
- */
- public function isFriendsWith($user_guid);
-
- /**
- * Determines whether or not a foreign entity has made this one a friend
- *
- * @param int $user_guid The GUID of the foreign entity
- */
- public function isFriendOf($user_guid);
-
- /**
- * Returns this entity's friends
- *
- * @param string $subtype The subtype of entity to return
- * @param int $limit The number of entities to return
- * @param int $offset Indexing offset
- */
- public function getFriends($subtype = "", $limit = 10, $offset = 0);
-
- /**
- * Returns entities that have made this entity a friend
- *
- * @param string $subtype The subtype of entity to return
- * @param int $limit The number of entities to return
- * @param int $offset Indexing offset
- */
- public function getFriendsOf($subtype = "", $limit = 10, $offset = 0);
-
- /**
- * Returns objects in this entity's container
- *
- * @param string $subtype The subtype of entity to return
- * @param int $limit The number of entities to return
- * @param int $offset Indexing offset
- */
- public function getObjects($subtype="", $limit = 10, $offset = 0);
-
- /**
- * Returns objects in the containers of this entity's friends
- *
- * @param string $subtype The subtype of entity to return
- * @param int $limit The number of entities to return
- * @param int $offset Indexing offset
- */
- public function getFriendsObjects($subtype = "", $limit = 10, $offset = 0);
-
- /**
- * Returns the number of object entities in this entity's container
- *
- * @param string $subtype The subtype of entity to count
- */
- public function countObjects($subtype = "");
-}
-
-/**
- * Rebuilds a parsed (partial) URL
- *
- * @param array $parts Associative array of URL components like parse_url() returns
- * @param bool $htmlencode HTML Encode the url?
- * @return str Full URL
- * @since 1.7
+ * @return string Full URL
+ * @since 1.7.0
*/
function elgg_http_build_url(array $parts, $html_encode = TRUE) {
// build only what's given to us.
@@ -1858,17 +1386,26 @@ function elgg_http_build_url(array $parts, $html_encode = TRUE) {
}
}
-
/**
* Adds action tokens to URL
*
- * @param str $link Full action URL
- * @param bool $htmlencode html encode the url?
- * @return str URL with action tokens
- * @since 1.7
+ * As of 1.7.0 action tokens are required on all actions.
+ * Use this function to append action tokens to a URL's GET parameters.
+ * This will preserve any existing GET parameters.
+ *
+ * @note If you are using {@elgg_view input/form} you don't need to
+ * add tokens to the action. The form view automatically handles
+ * tokens.
+ *
+ * @param string $url Full action URL
+ * @param bool $html_encode HTML encode the url? (default: false)
+ *
+ * @return string URL with action tokens
+ * @since 1.7.0
+ * @link http://docs.elgg.org/Tutorials/Actions
*/
-function elgg_add_action_tokens_to_url($url, $html_encode = TRUE) {
- $components = parse_url($url);
+function elgg_add_action_tokens_to_url($url, $html_encode = FALSE) {
+ $components = parse_url(elgg_normalize_url($url));
if (isset($components['query'])) {
$query = elgg_parse_str($components['query']);
@@ -1890,20 +1427,15 @@ function elgg_add_action_tokens_to_url($url, $html_encode = TRUE) {
}
/**
- * @deprecated 1.7 final
- */
-function elgg_validate_action_url($url) {
- elgg_deprecated_notice('elgg_validate_action_url had a short life. Use elgg_add_action_tokens_to_url() instead.', '1.7b');
-
- return elgg_add_action_tokens_to_url($url);
-}
-
-/**
- * Removes a single elementry from a (partial) url query.
+ * Removes an element from a URL's query string.
*
- * @param string $url
- * @param string $element
- * @return string
+ * @note You can send a partial URL string.
+ *
+ * @param string $url Full URL
+ * @param string $element The element to remove
+ *
+ * @return string The new URL with the query element removed.
+ * @since 1.7.0
*/
function elgg_http_remove_url_query_element($url, $element) {
$url_array = parse_url($url);
@@ -1920,17 +1452,18 @@ function elgg_http_remove_url_query_element($url, $element) {
}
$url_array['query'] = http_build_query($query);
- $string = elgg_http_build_url($url_array);
+ $string = elgg_http_build_url($url_array, false);
return $string;
}
-
/**
- * Adds get params to $url
+ * Adds an element or elements to a URL's query string.
*
- * @param str $url
- * @param array $elements k/v pairs.
- * @return str
+ * @param string $url The URL
+ * @param array $elements Key/value pairs to add to the URL
+ *
+ * @return string The new URL with the query strings added
+ * @since 1.7.0
*/
function elgg_http_add_url_query_elements($url, array $elements) {
$url_array = parse_url($url);
@@ -1946,168 +1479,203 @@ function elgg_http_add_url_query_elements($url, array $elements) {
}
$url_array['query'] = http_build_query($query);
- $string = elgg_http_build_url($url_array);
+ $string = elgg_http_build_url($url_array, false);
return $string;
}
-
-/**
- * Breadcrumb support.
- */
-
/**
- * Adds a breadcrumb to the stack
+ * Test if two URLs are functionally identical.
+ *
+ * @tip If $ignore_params is used, neither the name nor its value will be considered when comparing.
+ *
+ * @tip The order of GET params doesn't matter.
*
- * @param string $title The title to display
- * @param string $link Optional. The link for the title.
+ * @param string $url1 First URL
+ * @param string $url2 Second URL
+ * @param array $ignore_params GET params to ignore in the comparison
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function elgg_push_breadcrumb($title, $link = NULL) {
- global $CONFIG;
- if (!is_array($CONFIG->breadcrumbs)) {
- $CONFIG->breadcrumbs = array();
+function elgg_http_url_is_identical($url1, $url2, $ignore_params = array('offset', 'limit')) {
+ // if the server portion is missing but it starts with / then add the url in.
+ // @todo use elgg_normalize_url()
+ if (elgg_substr($url1, 0, 1) == '/') {
+ $url1 = elgg_get_site_url() . ltrim($url1, '/');
}
- // avoid key collisions.
- $CONFIG->breadcrumbs[] = array('title' => $title, 'link' => $link);
-}
+ if (elgg_substr($url1, 0, 1) == '/') {
+ $url2 = elgg_get_site_url() . ltrim($url2, '/');
+ }
-/**
- * Removes last breadcrumb entry.
- *
- * @return array popped item.
- */
-function elgg_pop_breadcrumb() {
- global $CONFIG;
+ // @todo - should probably do something with relative URLs
- if (is_array($CONFIG->breadcrumbs)) {
- array_pop($CONFIG->breadcrumbs);
+ if ($url1 == $url2) {
+ return TRUE;
}
- return FALSE;
-}
+ $url1_info = parse_url($url1);
+ $url2_info = parse_url($url2);
-/**
- * Returns all breadcrumbs
- *
- * @return array Breadcrumbs
- */
-function elgg_get_breadcrumbs() {
- global $CONFIG;
+ if (isset($url1_info['path'])) {
+ $url1_info['path'] = trim($url1_info['path'], '/');
+ }
+ if (isset($url2_info['path'])) {
+ $url2_info['path'] = trim($url2_info['path'], '/');
+ }
- return (is_array($CONFIG->breadcrumbs)) ? $CONFIG->breadcrumbs : array();
-}
+ // compare basic bits
+ $parts = array('scheme', 'host', 'path');
+ foreach ($parts as $part) {
+ if ((isset($url1_info[$part]) && isset($url2_info[$part]))
+ && $url1_info[$part] != $url2_info[$part]) {
+ return FALSE;
+ } elseif (isset($url1_info[$part]) && !isset($url2_info[$part])) {
+ return FALSE;
+ } elseif (!isset($url1_info[$part]) && isset($url2_info[$part])) {
+ return FALSE;
+ }
+ }
-/**
- * Sticky forms
- */
+ // quick compare of get params
+ if (isset($url1_info['query']) && isset($url2_info['query'])
+ && $url1_info['query'] == $url2_info['query']) {
+ return TRUE;
+ }
-/**
- * Load all the REQUEST variables into the sticky form cache
- *
- * Call this from an action when you want all your submitted variables
- * available if the submission fails validation and is sent back to the form
- */
-function elgg_make_sticky_form($form_name) {
- global $CONFIG;
+ // compare get params that might be out of order
+ $url1_params = array();
+ $url2_params = array();
- $CONFIG->active_sticky_form = $form_name;
- elgg_clear_sticky_form($form_name);
+ if (isset($url1_info['query'])) {
+ if ($url1_info['query'] = html_entity_decode($url1_info['query'])) {
+ $url1_params = elgg_parse_str($url1_info['query']);
+ }
+ }
- if (!isset($_SESSION['sticky_forms'])) {
- $_SESSION['sticky_forms'] = array();
+ if (isset($url2_info['query'])) {
+ if ($url2_info['query'] = html_entity_decode($url2_info['query'])) {
+ $url2_params = elgg_parse_str($url2_info['query']);
+ }
}
- $_SESSION['sticky_forms'][$form_name] = array();
- foreach($_REQUEST as $key => $var) {
- // will go through XSS filtering on the get function
- $_SESSION['sticky_forms'][$form_name][$key] = $var;
+ // drop ignored params
+ foreach ($ignore_params as $param) {
+ if (isset($url1_params[$param])) {
+ unset($url1_params[$param]);
+ }
+ if (isset($url2_params[$param])) {
+ unset($url2_params[$param]);
+ }
}
-}
+ // array_diff_assoc only returns the items in arr1 that aren't in arrN
+ // but not the items that ARE in arrN but NOT in arr1
+ // if arr1 is an empty array, this function will return 0 no matter what.
+ // since we only care if they're different and not how different,
+ // add the results together to get a non-zero (ie, different) result
+ $diff_count = count(array_diff_assoc($url1_params, $url2_params));
+ $diff_count += count(array_diff_assoc($url2_params, $url1_params));
+ if ($diff_count > 0) {
+ return FALSE;
+ }
-/**
- * Clear the sticky form cache
- *
- * Call this if validation is successful in the action handler or
- * when they sticky values have been used to repopulate the form
- * after a validation error.
- *
- * @param string $name Form namespace
- */
-function elgg_clear_sticky_form($form_name) {
- unset($_SESSION['sticky_forms'][$form_name]);
+ return TRUE;
}
/**
- * Has this form been made sticky
+ * Checks for $array[$key] and returns its value if it exists, else
+ * returns $default.
*
- * @param string $name Form namespace
- * @return boolean
- */
-function elgg_is_sticky_form($form_name) {
- return isset($_SESSION['sticky_forms'][$form_name]);
-}
-
-/**
- * Get a specific stick variable
+ * Shorthand for $value = (isset($array['key'])) ? $array['key'] : 'default';
*
- * @param string $variable The name of the variable
- * @param mixed $default Default value if the variable does not exist in sticky cache
- * @param boolean $filter_result Filter for bad input if true
- * @return mixed
+ * @param string $key The key to check.
+ * @param array $array The array to check against.
+ * @param mixed $default Default value to return if nothing is found.
+ * @param bool $strict Return array key if it's set, even if empty. If false,
+ * return $default if the array key is unset or empty.
*
- * @todo should this filter the default value?
+ * @return mixed
+ * @since 1.8.0
*/
-function elgg_get_sticky_value($form_name, $variable, $default = NULL, $filter_result = true) {
- if (isset($_SESSION['sticky_forms'][$form_name][$variable])) {
- $value = $_SESSION['sticky_forms'][$form_name][$variable];
- if ($filter_result) {
- // XSS filter result
- $value = filter_tags($value);
- }
- return $value;
+function elgg_extract($key, array $array, $default = null, $strict = true) {
+ if (!is_array($array)) {
+ return $default;
+ }
+
+ if ($strict) {
+ return (isset($array[$key])) ? $array[$key] : $default;
+ } else {
+ return (isset($array[$key]) && !empty($array[$key])) ? $array[$key] : $default;
}
- return $default;
}
/**
- * Clear a specific sticky variable
+ * Sorts a 3d array by specific element.
*
- * @param string $variable The name of the variable to clear
+ * @warning Will re-index numeric indexes.
+ *
+ * @note This operates the same as the built-in sort functions.
+ * It sorts the array and returns a bool for success.
+ *
+ * Do this: elgg_sort_3d_array_by_value($my_array);
+ * Not this: $my_array = elgg_sort_3d_array_by_value($my_array);
+ *
+ * @param array &$array Array to sort
+ * @param string $element Element to sort by
+ * @param int $sort_order PHP sort order
+ * {@see http://us2.php.net/array_multisort}
+ * @param int $sort_type PHP sort type
+ * {@see http://us2.php.net/sort}
+ *
+ * @return bool
*/
-function elgg_clear_sticky_value($form_name, $variable) {
- unset($_SESSION['sticky_forms'][$form_name][$variable]);
+function elgg_sort_3d_array_by_value(&$array, $element, $sort_order = SORT_ASC,
+$sort_type = SORT_LOCALE_STRING) {
+
+ $sort = array();
+
+ foreach ($array as $v) {
+ if (isset($v[$element])) {
+ $sort[] = strtolower($v[$element]);
+ } else {
+ $sort[] = NULL;
+ }
+ };
+
+ return array_multisort($sort, $sort_order, $sort_type, $array);
}
/**
- * Returns the current active sticky form.
- * @return mixed Str | FALSE
+ * Return the state of a php.ini setting as a bool
+ *
+ * @warning Using this on ini settings that are not boolean
+ * will be inaccurate!
+ *
+ * @param string $ini_get_arg The INI setting
+ *
+ * @return bool Depending on whether it's on or off
*/
-function elgg_get_active_sticky_form() {
- global $CONFIG;
+function ini_get_bool($ini_get_arg) {
+ $temp = strtolower(ini_get($ini_get_arg));
- if (isset($CONFIG->active_sticky_form)) {
- $form_name = $CONFIG->active_sticky_form;
- } else {
- return FALSE;
+ if ($temp == '1' || $temp == 'on' || $temp == 'true') {
+ return true;
}
-
- return (elgg_is_sticky_form($form_name)) ? $form_name : FALSE;
+ return false;
}
-function elgg_set_active_sticky_form($form_name) {
- global $CONFIG;
-
- $CONFIG->active_sticky_form = $form_name;
-}
/**
- * Returns the PHP INI setting in bytes
+ * Returns a PHP INI setting in bytes.
+ *
+ * @tip Use this for arithmetic when determining if a file can be uploaded.
+ *
+ * @param string $setting The php.ini setting
*
- * @param str $setting
* @return int
- * @since 1.7
+ * @since 1.7.0
* @link http://www.php.net/manual/en/function.ini-get.php
*/
function elgg_get_ini_setting_in_bytes($setting) {
@@ -2115,12 +1683,14 @@ function elgg_get_ini_setting_in_bytes($setting) {
$val = ini_get($setting);
// convert INI setting when shorthand notation is used
- $last = strtolower($val[strlen($val)-1]);
+ $last = strtolower($val[strlen($val) - 1]);
switch($last) {
case 'g':
$val *= 1024;
+ // fallthrough intentional
case 'm':
$val *= 1024;
+ // fallthrough intentional
case 'k':
$val *= 1024;
}
@@ -2130,339 +1700,605 @@ function elgg_get_ini_setting_in_bytes($setting) {
}
/**
- * Server javascript pages.
+ * Returns true is string is not empty, false, or null.
+ *
+ * Function to be used in array_filter which returns true if $string is not null.
+ *
+ * @param string $string The string to test
*
- * @param $page
- * @return unknown_type
+ * @return bool
+ * @todo This is used once in metadata.php. Use a lambda function instead.
*/
-function js_page_handler($page) {
- if (is_array($page) && sizeof($page)) {
- $js = str_replace('.js','',$page[0]);
- $return = elgg_view('js/' . $js);
-
- header('Content-type: text/javascript');
- header('Expires: ' . date('r',time() + 864000));
- header("Pragma: public");
- header("Cache-Control: public");
- header("Content-Length: " . strlen($return));
-
- echo $return;
- exit;
+function is_not_null($string) {
+ if (($string === '') || ($string === false) || ($string === null)) {
+ return false;
}
+
+ return true;
}
/**
- * This function is a shutdown hook registered on startup which does nothing more than trigger a
- * shutdown event when the script is shutting down, but before database connections have been dropped etc.
+ * Normalise the singular keys in an options array to plural keys.
*
+ * Used in elgg_get_entities*() functions to support shortcutting plural
+ * names by singular names.
+ *
+ * @param array $options The options array. $options['keys'] = 'values';
+ * @param array $singulars A list of singular words to pluralize by adding 's'.
+ *
+ * @return array
+ * @since 1.7.0
+ * @access private
*/
-function __elgg_shutdown_hook() {
- global $START_MICROTIME;
+function elgg_normalise_plural_options_array($options, $singulars) {
+ foreach ($singulars as $singular) {
+ $plural = $singular . 's';
- trigger_elgg_event('shutdown', 'system');
+ if (array_key_exists($singular, $options)) {
+ if ($options[$singular] === ELGG_ENTITIES_ANY_VALUE) {
+ $options[$plural] = $options[$singular];
+ } else {
+ // Test for array refs #2641
+ if (!is_array($options[$singular])) {
+ $options[$plural] = array($options[$singular]);
+ } else {
+ $options[$plural] = $options[$singular];
+ }
+ }
+ }
+
+ unset($options[$singular]);
+ }
- $time = (float)(microtime(TRUE) - $START_MICROTIME);
- // demoted to NOTICE from DEBUG so javascript is not corrupted
- elgg_log("Page {$_SERVER['REQUEST_URI']} generated in $time seconds", 'NOTICE');
+ return $options;
}
/**
- * Register functions for Elgg core
+ * Emits a shutdown:system event upon PHP shutdown, but before database connections are dropped.
+ *
+ * @tip Register for the shutdown:system event to perform functions at the end of page loads.
*
- * @return unknown_type
+ * @warning Using this event to perform long-running functions is not very
+ * useful. Servers will hold pages until processing is done before sending
+ * them out to the browser.
+ *
+ * @see http://www.php.net/register-shutdown-function
+ *
+ * @return void
+ * @see register_shutdown_hook()
+ * @access private
*/
-function elgg_init() {
- global $CONFIG;
+function _elgg_shutdown_hook() {
+ global $START_MICROTIME;
- // Page handler for JS
- register_page_handler('js','js_page_handler');
+ try {
+ elgg_trigger_event('shutdown', 'system');
- // Register an event triggered at system shutdown
- register_shutdown_function('__elgg_shutdown_hook');
+ $time = (float)(microtime(TRUE) - $START_MICROTIME);
+ // demoted to NOTICE from DEBUG so javascript is not corrupted
+ elgg_log("Page {$_SERVER['REQUEST_URI']} generated in $time seconds", 'NOTICE');
+ } catch (Exception $e) {
+ $message = 'Error: ' . get_class($e) . ' thrown within the shutdown handler. ';
+ $message .= "Message: '{$e->getMessage()}' in file {$e->getFile()} (line {$e->getLine()})";
+ error_log($message);
+ error_log("Exception trace stack: {$e->getTraceAsString()}");
+ }
}
-function elgg_walled_garden_index() {
- $login = elgg_view('account/forms/login_walled_garden');
- echo elgg_view('page_shells/walled_garden', array(
- 'body' => $login,
- 'sysmessages' => system_messages(NULL, ''),
- ));
-
- // @hack Index must exit to keep plugins from continuing to extend
- exit;
- return TRUE;
+/**
+ * Serve javascript pages.
+ *
+ * Searches for views under js/ and outputs them with special
+ * headers for caching control.
+ *
+ * @param array $page The page array
+ *
+ * @return bool
+ * @elgg_pagehandler js
+ * @access private
+ */
+function elgg_js_page_handler($page) {
+ return elgg_cacheable_view_page_handler($page, 'js');
}
/**
- * Boot Elgg
- * @return unknown_type
+ * Serve individual views for Ajax.
+ *
+ * /ajax/view/<name of view>?<key/value params>
+ *
+ * @param array $page The page array
+ *
+ * @return bool
+ * @elgg_pagehandler ajax
+ * @access private
*/
-function elgg_boot() {
- global $CONFIG;
-
- // Actions
- register_action('comments/add');
- register_action('comments/delete');
- register_action('likes/add');
- register_action('likes/delete');
-
- elgg_view_register_simplecache('css');
- elgg_view_register_simplecache('js/friendsPickerv1');
- elgg_view_register_simplecache('js/initialise_elgg');
+function elgg_ajax_page_handler($page) {
+ if (is_array($page) && sizeof($page)) {
+ // throw away 'view' and form the view name
+ unset($page[0]);
+ $view = implode('/', $page);
- // discover the built-in view types
- // @todo cache this
- $view_path = $CONFIG->viewpath;
- $CONFIG->view_types = array();
+ $allowed_views = elgg_get_config('allowed_ajax_views');
+ if (!array_key_exists($view, $allowed_views)) {
+ header('HTTP/1.1 403 Forbidden');
+ exit;
+ }
- $views = scandir($view_path);
+ // pull out GET parameters through filter
+ $vars = array();
+ foreach ($_GET as $name => $value) {
+ $vars[$name] = get_input($name);
+ }
- foreach ($views as $view) {
- if ('.' !== substr($view, 0, 1) && is_dir($view_path . $view)) {
- $CONFIG->view_types[] = $view;
+ if (isset($vars['guid'])) {
+ $vars['entity'] = get_entity($vars['guid']);
}
- }
+ echo elgg_view($view, $vars);
+ return true;
+ }
+ return false;
}
/**
- * Runs unit tests for the API.
+ * Serve CSS
+ *
+ * Serves CSS from the css views directory with headers for caching control
+ *
+ * @param array $page The page array
+ *
+ * @return bool
+ * @elgg_pagehandler css
+ * @access private
*/
-function elgg_api_test($hook, $type, $value, $params) {
- global $CONFIG;
- $value[] = $CONFIG->path . 'engine/tests/api/entity_getter_functions.php';
- $value[] = $CONFIG->path . 'engine/tests/api/helpers.php';
- $value[] = $CONFIG->path . 'engine/tests/regression/trac_bugs.php';
- return $value;
+function elgg_css_page_handler($page) {
+ if (!isset($page[0])) {
+ // default css
+ $page[0] = 'elgg';
+ }
+
+ return elgg_cacheable_view_page_handler($page, 'css');
}
/**
- * Sorts out the featured URLs and the "more" dropdown
- * @return array ('featured_urls' and 'more')
- * @since 1.8
+ * Serves a JS or CSS view with headers for caching.
+ *
+ * /<css||js>/name/of/view.<last_cache>.<css||js>
+ *
+ * @param array $page The page array
+ * @param string $type The type: js or css
+ *
+ * @return bool
+ * @access private
*/
-function elgg_get_nav_items() {
- $menu_items = get_register('menu');
- $featured_urls_info = get_config('menu_items_featured_urls');
+function elgg_cacheable_view_page_handler($page, $type) {
- $more = array();
- $featured_urls = array();
- $featured_urls_sanitised = array();
+ switch ($type) {
+ case 'js':
+ $content_type = 'text/javascript';
+ break;
+
+ case 'css':
+ $content_type = 'text/css';
+ break;
- // easier to compare with in_array() than embedded foreach()es
- $valid_urls = array();
- foreach ($menu_items as $info) {
- $valid_urls[] = $info->value->url;
+ default:
+ return false;
+ break;
}
- // make sure the url is a valid link.
- // this prevents disabled plugins leaving behind
- // valid links when no using a pagehandler.
- foreach ($featured_urls_info as $info) {
- if (in_array($info->value->url, $valid_urls)) {
- $featured_urls[] = $info->value->url;
- $featured_urls_sanitised[] = $info;
- }
+ if ($page) {
+ // the view file names can have multiple dots
+ // eg: views/default/js/calendars/jquery.fullcalendar.min.php
+ // translates to the url /js/calendars/jquery.fullcalendar.min.<ts>.js
+ // and the view js/calendars/jquery.fullcalendar.min
+ // we ignore the last two dots for the ts and the ext.
+ // Additionally, the timestamp is optional.
+ $page = implode('/', $page);
+ $regex = '|(.+?)\.([\d]+\.)?\w+$|';
+ preg_match($regex, $page, $matches);
+ $view = $matches[1];
+ $return = elgg_view("$type/$view");
+
+ header("Content-type: $content_type");
+
+ // @todo should js be cached when simple cache turned off
+ //header('Expires: ' . gmdate('D, d M Y H:i:s \G\M\T', strtotime("+10 days")), true);
+ //header("Pragma: public");
+ //header("Cache-Control: public");
+ //header("Content-Length: " . strlen($return));
+
+ echo $return;
+ return true;
}
+ return false;
+}
- // add toolbar entries if not hiding dupes.
- foreach ($menu_items as $name => $info) {
- if (!in_array($info->value->url, $featured_urls)) {
- $more[] = $info;
- }
+/**
+ * Reverses the ordering in an ORDER BY clause. This is achived by replacing
+ * asc with desc, or appending desc to the end of the clause.
+ *
+ * This is used mostly for elgg_get_entities() and other similar functions.
+ *
+ * @param string $order_by An order by clause
+ * @access private
+ * @return string
+ * @access private
+ */
+function elgg_sql_reverse_order_by_clause($order_by) {
+ $order_by = strtolower($order_by);
+
+ if (strpos($order_by, ' asc') !== false) {
+ $return = str_replace(' asc', ' desc', $order_by);
+ } elseif (strpos($order_by, ' desc') !== false) {
+ $return = str_replace(' desc', ' asc', $order_by);
+ } else {
+ // no order specified, so default to desc since mysql defaults to asc
+ $return = $order_by . ' desc';
}
- return array(
- 'featured' => $featured_urls_sanitised,
- 'more' => $more
- );
+ return $return;
}
/**
- * Hook that registers the custom menu items.
- * @since 1.8
+ * Enable objects with an enable() method.
+ *
+ * Used as a callback for ElggBatch.
+ *
+ * @todo why aren't these static methods on ElggBatch?
+ *
+ * @param object $object The object to enable
+ * @return bool
+ * @access private
*/
-function add_custom_menu_items() {
- if ($custom_items = get_config('menu_items_custom_items')) {
- foreach ($custom_items as $url => $name) {
- add_menu($name, $url);
- }
- }
+function elgg_batch_enable_callback($object) {
+ // our db functions return the number of rows affected...
+ return $object->enable() ? true : false;
}
/**
- * Test two URLs to see if they are functionally identical.
+ * Disable objects with a disable() method.
*
- * @param string $url1
- * @param string $url2
- * @param array $ignore_params - GET params to ignore in the comparison
- * @return BOOL
- * @since 1.8
+ * Used as a callback for ElggBatch.
+ *
+ * @param object $object The object to disable
+ * @return bool
+ * @access private
*/
-function elgg_http_url_is_identical($url1, $url2, $ignore_params = array('offset', 'limit')) {
- global $CONFIG;
+function elgg_batch_disable_callback($object) {
+ // our db functions return the number of rows affected...
+ return $object->disable() ? true : false;
+}
- // if the server portion is missing but it starts with / then add the url in.
- if (elgg_substr($url1, 0, 1) == '/') {
- $url1 = $CONFIG->url . ltrim($url1, '/');
- }
+/**
+ * Delete objects with a delete() method.
+ *
+ * Used as a callback for ElggBatch.
+ *
+ * @param object $object The object to disable
+ * @return bool
+ * @access private
+ */
+function elgg_batch_delete_callback($object) {
+ // our db functions return the number of rows affected...
+ return $object->delete() ? true : false;
+}
- if (elgg_substr($url1, 0, 1) == '/') {
- $url2 = $CONFIG->url . ltrim($url2, '/');
+/**
+ * Checks if there are some constraints on the options array for
+ * potentially dangerous operations.
+ *
+ * @param array $options Options array
+ * @param string $type Options type: metadata or annotations
+ * @return bool
+ * @access private
+ */
+function elgg_is_valid_options_for_batch_operation($options, $type) {
+ if (!$options || !is_array($options)) {
+ return false;
}
- // @todo - should probably do something with relative URLs
+ // at least one of these is required.
+ $required = array(
+ // generic restraints
+ 'guid', 'guids'
+ );
- if ($url1 == $url2) {
- return TRUE;
- }
+ switch ($type) {
+ case 'metadata':
+ $metadata_required = array(
+ 'metadata_owner_guid', 'metadata_owner_guids',
+ 'metadata_name', 'metadata_names',
+ 'metadata_value', 'metadata_values'
+ );
- $url1_info = parse_url($url1);
- $url2_info = parse_url($url2);
+ $required = array_merge($required, $metadata_required);
+ break;
- $url1_info['path'] = trim($url1_info['path'], '/');
- $url2_info['path'] = trim($url2_info['path'], '/');
+ case 'annotations':
+ case 'annotation':
+ $annotations_required = array(
+ 'annotation_owner_guid', 'annotation_owner_guids',
+ 'annotation_name', 'annotation_names',
+ 'annotation_value', 'annotation_values'
+ );
- // compare basic bits
- $parts = array('scheme', 'host', 'path');
+ $required = array_merge($required, $annotations_required);
+ break;
- foreach ($parts as $part) {
- if ((isset($url1_info[$part]) && isset($url2_info[$part])) && $url1_info[$part] != $url2_info[$part]) {
- return FALSE;
- } elseif (isset($url1_info[$part]) && !isset($url2_info[$part])) {
- return FALSE;
- } elseif (!isset($url1_info[$part]) && isset($url2_info[$part])) {
- return FALSE;
- }
+ default:
+ return false;
}
- // quick compare of get params
- if (isset($url1_info['query']) && isset($url2_info['query']) && $url1_info['query'] == $url2_info['query']) {
- return TRUE;
+ foreach ($required as $key) {
+ // check that it exists and is something.
+ if (isset($options[$key]) && $options[$key]) {
+ return true;
+ }
}
- // compare get params that might be out of order
- $url1_params = array();
- $url2_params = array();
+ return false;
+}
- if (isset($url1_info['query'])) {
- if ($url1_info['query'] = html_entity_decode($url1_info['query'])) {
- $url1_params = elgg_parse_str($url1_info['query']);
- }
+/**
+ * Intercepts the index page when Walled Garden mode is enabled.
+ *
+ * @link http://docs.elgg.org/Tutorials/WalledGarden
+ * @elgg_plugin_hook index system
+ *
+ * @param string $hook The name of the hook
+ * @param string $type The type of hook
+ * @param bool $value Has a plugin already rendered an index page?
+ * @param array $params Array of parameters (should be empty)
+ * @return bool
+ * @access private
+ */
+function elgg_walled_garden_index($hook, $type, $value, $params) {
+ if ($value) {
+ // do not create a second index page so return
+ return;
}
- if (isset($url2_info['query'])) {
- if ($url2_info['query'] = html_entity_decode($url2_info['query'])) {
- $url2_params = elgg_parse_str($url2_info['query']);
- }
- }
+ elgg_load_css('elgg.walled_garden');
+ elgg_load_js('elgg.walled_garden');
+
+ $content = elgg_view('core/walled_garden/login');
- // drop ignored params
- foreach ($ignore_params as $param) {
- if (isset($url1_params[$param])) {
- unset($url1_params[$param]);
- }
- if (isset($url2_params[$param])) {
- unset($url2_params[$param]);
- }
- }
+ $params = array(
+ 'content' => $content,
+ 'class' => 'elgg-walledgarden-double',
+ 'id' => 'elgg-walledgarden-login',
+ );
+ $body = elgg_view_layout('walled_garden', $params);
+ echo elgg_view_page('', $body, 'walled_garden');
- // array_diff_assoc only returns the items in arr1 that aren't in arrN
- // but not the items that ARE in arrN but NOT in arr1
- // if arr1 is an empty array, this function will return 0 no matter what.
- // since we only care if they're different and not how different,
- // add the results together to get a non-zero (ie, different) result
- $diff_count = count(array_diff_assoc($url1_params, $url2_params));
- $diff_count += count(array_diff_assoc($url2_params, $url1_params));
- if ($diff_count > 0) {
- return FALSE;
- }
+ // return true to prevent other plugins from adding a front page
+ return true;
+}
- return TRUE;
+/**
+ * Serve walled garden sections
+ *
+ * @param array $page Array of URL segments
+ * @return string
+ * @access private
+ */
+function _elgg_walled_garden_ajax_handler($page) {
+ $view = $page[0];
+ $params = array(
+ 'content' => elgg_view("core/walled_garden/$view"),
+ 'class' => 'elgg-walledgarden-single hidden',
+ 'id' => str_replace('_', '-', "elgg-walledgarden-$view"),
+ );
+ echo elgg_view_layout('walled_garden', $params);
+ return true;
}
/**
- * Checks walled garden status upon Elgg init.
+ * Checks the status of the Walled Garden and forwards to a login page
+ * if required.
*
- * @since 1.8
+ * If the site is in Walled Garden mode, all page except those registered as
+ * plugin pages by {@elgg_hook public_pages walled_garden} will redirect to
+ * a login page.
+ *
+ * @since 1.8.0
+ * @elgg_event_handler init system
+ * @link http://docs.elgg.org/Tutorials/WalledGarden
+ * @return void
+ * @access private
*/
function elgg_walled_garden() {
global $CONFIG;
+ elgg_register_css('elgg.walled_garden', '/css/walled_garden.css');
+ elgg_register_js('elgg.walled_garden', '/js/walled_garden.js');
+
+ elgg_register_page_handler('walled_garden', '_elgg_walled_garden_ajax_handler');
+
// check for external page view
if (isset($CONFIG->site) && $CONFIG->site instanceof ElggSite) {
- $CONFIG->site->check_walled_garden();
+ $CONFIG->site->checkWalledGarden();
}
}
/**
- * Checks for $array[$key] and returns its value if it exists, else
- * returns $default.
+ * Remove public access for walled gardens
*
- * Shorthand for $value = (isset($array['key'])) ? $array['key'] : 'default';
+ * @param string $hook
+ * @param string $type
+ * @param array $accesses
+ * @return array
+ * @access private
+ */
+function _elgg_walled_garden_remove_public_access($hook, $type, $accesses) {
+ if (isset($accesses[ACCESS_PUBLIC])) {
+ unset($accesses[ACCESS_PUBLIC]);
+ }
+ return $accesses;
+}
+
+/**
+ * Boots the engine
*
- * @param string $key The key to check.
- * @param array $array The array to check against.
- * @param mixed $default Default value to return if nothing is found.
- * @since 1.8
+ * 1. sets error handlers
+ * 2. connects to database
+ * 3. verifies the installation suceeded
+ * 4. loads application configuration
+ * 5. loads i18n data
+ * 6. loads site configuration
+ *
+ * @access private
*/
-function elgg_get_array_value($key, array $array, $default = NULL) {
- return (isset($array[$key])) ? $array[$key] : $default;
+function _elgg_engine_boot() {
+ // Register the error handlers
+ set_error_handler('_elgg_php_error_handler');
+ set_exception_handler('_elgg_php_exception_handler');
+
+ setup_db_connections();
+
+ verify_installation();
+
+ _elgg_load_application_config();
+
+ _elgg_load_site_config();
+
+ _elgg_session_boot();
+
+ _elgg_load_cache();
+
+ _elgg_load_translations();
}
/**
- * Sorts a 3d array by specific element.
- * Will re-index numeric indexes.
- * NB: This operates the same as the built-in sort functions.
- * ie, sorts the array and returns a bool for success.
+ * Elgg's main init.
*
- * Do this: elgg_sort_3d_array_by_value($my_array);
- * Not this: $my_array = elgg_sort_3d_array_by_value($my_array);
+ * Handles core actions for comments, the JS pagehandler, and the shutdown function.
*
- * @param array $array Array to sort
- * @param string $element Element to sort by
- * @param $sort_order
- * @param $sort_type
- * @return bool
+ * @elgg_event_handler init system
+ * @return void
+ * @access private
*/
-function elgg_sort_3d_array_by_value(&$array, $element, $sort_order = SORT_ASC, $sort_type = SORT_LOCALE_STRING) {
- $sort = array();
+function elgg_init() {
+ global $CONFIG;
+
+ elgg_register_action('comments/add');
+ elgg_register_action('comments/delete');
+
+ elgg_register_page_handler('js', 'elgg_js_page_handler');
+ elgg_register_page_handler('css', 'elgg_css_page_handler');
+ elgg_register_page_handler('ajax', 'elgg_ajax_page_handler');
+
+ elgg_register_js('elgg.autocomplete', 'js/lib/ui.autocomplete.js');
+ elgg_register_js('jquery.ui.autocomplete.html', 'vendors/jquery/jquery.ui.autocomplete.html.js');
+ elgg_register_js('elgg.userpicker', 'js/lib/ui.userpicker.js');
+ elgg_register_js('elgg.friendspicker', 'js/lib/ui.friends_picker.js');
+ elgg_register_js('jquery.easing', 'vendors/jquery/jquery.easing.1.3.packed.js');
+ elgg_register_js('elgg.avatar_cropper', 'js/lib/ui.avatar_cropper.js');
+ elgg_register_js('jquery.imgareaselect', 'vendors/jquery/jquery.imgareaselect-0.9.8/scripts/jquery.imgareaselect.min.js');
+ elgg_register_js('elgg.ui.river', 'js/lib/ui.river.js');
+
+ elgg_register_css('jquery.imgareaselect', 'vendors/jquery/jquery.imgareaselect-0.9.8/css/imgareaselect-deprecated.css');
- foreach ($array as $k => $v) {
- if (isset($v[$element])) {
- $sort[] = strtolower($v[$element]);
- } else {
- $sort[] = NULL;
- }
- };
+ // Trigger the shutdown:system event upon PHP shutdown.
+ register_shutdown_function('_elgg_shutdown_hook');
+
+ $logo_url = elgg_get_site_url() . "_graphics/elgg_toolbar_logo.gif";
+ elgg_register_menu_item('topbar', array(
+ 'name' => 'elgg_logo',
+ 'href' => 'http://www.elgg.org/',
+ 'text' => "<img src=\"$logo_url\" alt=\"Elgg logo\" width=\"38\" height=\"20\" />",
+ 'priority' => 1,
+ 'link_class' => 'elgg-topbar-logo',
+ ));
- return array_multisort($sort, $sort_order, $sort_type, $array);
+ // Sets a blacklist of words in the current language.
+ // This is a comma separated list in word:blacklist.
+ // @todo possibly deprecate
+ $CONFIG->wordblacklist = array();
+ $list = explode(',', elgg_echo('word:blacklist'));
+ if ($list) {
+ foreach ($list as $l) {
+ $CONFIG->wordblacklist[] = trim($l);
+ }
+ }
}
/**
- * Some useful constant definitions
+ * Adds unit tests for the general API.
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param array $value array of test files
+ * @param array $params empty
+ *
+ * @elgg_plugin_hook unit_tests system
+ * @return array
+ * @access private
+ */
+function elgg_api_test($hook, $type, $value, $params) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/entity_getter_functions.php';
+ $value[] = $CONFIG->path . 'engine/tests/api/helpers.php';
+ $value[] = $CONFIG->path . 'engine/tests/regression/trac_bugs.php';
+ return $value;
+}
+
+/**#@+
+ * Controls access levels on ElggEntity entities, metadata, and annotations.
+ *
+ * @warning ACCESS_DEFAULT is a place holder for the input/access view. Do not
+ * use it when saving an entity.
+ *
+ * @var int
*/
define('ACCESS_DEFAULT', -1);
define('ACCESS_PRIVATE', 0);
define('ACCESS_LOGGED_IN', 1);
define('ACCESS_PUBLIC', 2);
define('ACCESS_FRIENDS', -2);
+/**#@-*/
/**
+ * Constant to request the value of a parameter be ignored in elgg_get_*() functions
+ *
+ * @see elgg_get_entities()
+ * @var NULL
* @since 1.7
*/
define('ELGG_ENTITIES_ANY_VALUE', NULL);
+
+/**
+ * Constant to request the value of a parameter be nothing in elgg_get_*() functions.
+ *
+ * @see elgg_get_entities()
+ * @var int 0
+ * @since 1.7
+ */
define('ELGG_ENTITIES_NO_VALUE', 0);
/**
- * @since 1.7.2
+ * Used in calls to forward() to specify the browser should be redirected to the
+ * referring page.
+ *
+ * @see forward
+ * @var int -1
*/
define('REFERRER', -1);
+
+/**
+ * Alternate spelling for REFERRER. Included because of some bad documentation
+ * in the original HTTP spec.
+ *
+ * @see forward()
+ * @link http://en.wikipedia.org/wiki/HTTP_referrer#Origin_of_the_term_referer
+ * @var int -1
+ */
define('REFERER', -1);
-register_elgg_event_handler('init', 'system', 'elgg_init');
-register_elgg_event_handler('boot', 'system', 'elgg_boot', 1000);
-register_plugin_hook('unit_test', 'system', 'elgg_api_test');
+elgg_register_event_handler('init', 'system', 'elgg_init');
+elgg_register_event_handler('boot', 'system', '_elgg_engine_boot', 1);
+elgg_register_plugin_hook_handler('unit_test', 'system', 'elgg_api_test');
-register_elgg_event_handler('init', 'system', 'add_custom_menu_items', 1000);
-register_elgg_event_handler('init', 'system', 'elgg_walled_garden', 1000);
+elgg_register_event_handler('init', 'system', 'add_custom_menu_items', 1000);
+elgg_register_event_handler('init', 'system', 'elgg_walled_garden', 1000);
diff --git a/engine/lib/entities.php b/engine/lib/entities.php
index 0f718d162..4fcf1c657 100644
--- a/engine/lib/entities.php
+++ b/engine/lib/entities.php
@@ -1,1270 +1,142 @@
<?php
/**
- * Elgg entities.
- * Functions to manage all elgg entities (sites, collections, objects and users).
+ * Procedural code for creating, loading, and modifying ElggEntity objects.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage DataModel.Entities
+ * @link http://docs.elgg.org/DataModel/Entities
*/
-/// 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.
+ * Cache entities in memory once loaded.
*
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Core
+ * @global array $ENTITY_CACHE
+ * @access private
*/
-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;
-
- /**
- * 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;
-
-
- /**
- * Volatile data structure for this object, allows for storage of data
- * in-memory that isn't sync'd back to the metadata table.
- */
- protected $volatile;
-
- /**
- * 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();
- }
- if (!is_array($this->volatile)) {
- $this->volatile = 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['last_action'] = '';
- $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;
- }
-
- /**
- * Clone an entity
- *
- * Resets the guid so that the entity can be saved as a distinct entity from
- * the original. Creation time will be set when this new entity is saved.
- * The owner and container guids come from the original entity. The clone
- * method copies metadata but does not copy over annotations, or private settings.
- *
- * Note: metadata will have its owner and access id set when the entity is saved
- * and it will be the same as that of the entity.
- */
- public function __clone() {
-
- $orig_entity = get_entity($this->guid);
- if (!$orig_entity) {
- elgg_log("Failed to clone entity with GUID $this->guid", "ERROR");
- return;
- }
-
- $metadata_array = get_metadata_for_entity($this->guid);
-
- $this->attributes['guid'] = "";
-
- $this->attributes['subtype'] = $orig_entity->getSubtype();
-
- // copy metadata over to new entity - slightly convoluted due to
- // handling of metadata arrays
- if (is_array($metadata_array)) {
- // create list of metadata names
- $metadata_names = array();
- foreach ($metadata_array as $metadata) {
- $metadata_names[] = $metadata['name'];
- }
- // arrays are stored with multiple enties per name
- $metadata_names = array_unique($metadata_names);
-
- // move the metadata over
- foreach ($metadata_names as $name) {
- $this->set($name, $orig_entity->$name);
- }
- }
- }
-
- /**
- * 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.
- *
- * subtype is returned as an id rather than the subtype string. Use getSubtype()
- * to get the subtype string.
- *
- * @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);
-
- // getMetaData returns NULL if $name is not found
- return $meta;
- }
-
- /**
- * 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.
- *
- * @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;
- }
-
- $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 ($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) {
- return $this->$name !== NULL;
- }
-
- /**
- * 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 Name of the metadata
- * @param mixed $value Value of the metadata
- * @param string $value_type Types supported: integer and string. Will auto-identify if not set
- * @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 {
- unset($this->temp_metadata[$name]);
- if ((int) $this->guid > 0) {
- return create_metadata($this->getGUID(), $name, $value, $value_type, $this->getOwner(), $this->getAccessID(), $multiple);
- } 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;
- }
- }
- }
-
- /**
- * Clear metadata.
- */
- public function clearMetaData($name = "") {
- if (empty($name)) {
- return clear_metadata($this->getGUID());
- } else {
- return remove_metadata($this->getGUID(),$name);
- }
- }
-
-
- /**
- * Get a piece of volatile (non-persisted) data on this entity
- */
- public function getVolatileData($name) {
- if (!is_array($this->volatile)) {
- $this->volatile = array();
- }
-
- if (array_key_exists($name, $this->volatile)) {
- return $this->volatile[$name];
- } else {
- return NULL;
- }
- }
-
-
- /**
- * Set a piece of volatile (non-persisted) data on this entity
- */
- public function setVolatileData($name, $value) {
- if (!is_array($this->volatile)) {
- $this->volatile = array();
- }
-
- $this->volatile[$name] = $value;
- }
-
-
- /**
- * 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.
- * @return bool
- */
- public function addRelationship($guid, $relationship) {
- return add_entity_relationship($this->getGUID(), $relationship, $guid);
- }
-
- /**
- * Remove a relationship
- *
- * @param int $guid
- * @param str $relationship
- * @return bool
- */
- public function removeRelationship($guid, $relationship) {
- return remove_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;
- }
- 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];
- }
- }
-
- /**
- * 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 elgg_get_entities_from_relationship(array(
- 'relationship' => $relationship,
- 'relationship_guid' => $this->getGUID(),
- 'inverse_relationship' => $inverse,
- 'limit' => $limit,
- 'offset' => $offset
- ));
- }
-
- /**
- * Gets the number of of entities from a specific relationship type
- *
- * @param string $relationship Relationship type (eg "friends")
- * @param bool $inverse_relationship
- * @return int|false The number of entities or false on failure
- */
- function countEntitiesFromRelationship($relationship, $inverse_relationship = FALSE) {
- return elgg_get_entities_from_relationship(array(
- 'relationship' => $relationship,
- 'relationship_guid' => $this->getGUID(),
- 'inverse_relationship' => $inverse_relationship,
- 'count' => 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 container.
- *
- * @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]);
- }
- }
-
- // set the subtype to id now rather than a string
- $this->attributes['subtype'] = get_subtype_id($this->attributes['type'], $this->attributes['subtype']);
-
- // 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']++;
- }
+global $ENTITY_CACHE;
+$ENTITY_CACHE = array();
- // 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',
- 'time_updated',
- 'container_guid',
- 'owner_guid',
- 'site_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;
- }
-
- /**
- * Returns tags for this entity.
- *
- * @param array $tag_names Optionally restrict by tag metadata names.
- * @return array
- */
- public function getTags($tag_names = NULL) {
- global $CONFIG;
-
- if ($tag_names && !is_array($tag_names)) {
- $tag_names = array($tag_names);
- }
-
- $valid_tags = elgg_get_registered_tag_metadata_names();
- $entity_tags = array();
-
- foreach ($valid_tags as $tag_name) {
- if (is_array($tag_names) && !in_array($tag_name, $tag_names)) {
- continue;
- }
-
- if ($tags = $this->$tag_name) {
- // if a single tag, metadata returns a string.
- // if multiple tags, metadata returns an array.
- if (is_array($tags)) {
- $entity_tags = array_merge($entity_tags, $tags);
- } else {
- $entity_tags[] = $tags;
- }
- }
- }
-
- return $entity_tags;
- }
-
- // 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;
- }
- }
+/**
+ * GUIDs of entities banned from the entity cache (during this request)
+ *
+ * @global array $ENTITY_CACHE_DISABLED_GUIDS
+ * @access private
+ */
+global $ENTITY_CACHE_DISABLED_GUIDS;
+$ENTITY_CACHE_DISABLED_GUIDS = array();
- function offsetGet($key) {
- if ( array_key_exists($key, $this->attributes) ) {
- return $this->attributes[$key];
- }
- }
+/**
+ * Cache subtypes and related class names.
+ *
+ * @global array|null $SUBTYPE_CACHE array once populated from DB, initially null
+ * @access private
+ */
+global $SUBTYPE_CACHE;
+$SUBTYPE_CACHE = null;
- function offsetUnset($key) {
- if ( array_key_exists($key, $this->attributes) ) {
- $this->attributes[$key] = ""; // Full unsetting is dangerious for our objects
- }
- }
+/**
+ * Remove this entity from the entity cache and make sure it is not re-added
+ *
+ * @param int $guid The entity guid
+ *
+ * @access private
+ * @todo this is a workaround until #5604 can be implemented
+ */
+function _elgg_disable_caching_for_entity($guid) {
+ global $ENTITY_CACHE_DISABLED_GUIDS;
- function offsetExists($offset) {
- return array_key_exists($offset, $this->attributes);
- }
+ _elgg_invalidate_cache_for_entity($guid);
+ $ENTITY_CACHE_DISABLED_GUIDS[$guid] = true;
}
/**
- * Initialise the entity cache.
+ * Allow this entity to be stored in the entity cache
+ *
+ * @param int $guid The entity guid
+ *
+ * @access private
*/
-function initialise_entity_cache() {
- global $ENTITY_CACHE;
+function _elgg_enable_caching_for_entity($guid) {
+ global $ENTITY_CACHE_DISABLED_GUIDS;
- if (!$ENTITY_CACHE) {
- //select_default_memcache('entity_cache'); // TODO: Replace with memcache?
- $ENTITY_CACHE = array();
- }
+ unset($ENTITY_CACHE_DISABLED_GUIDS[$guid]);
}
/**
- * Invalidate this class' entry in the cache.
+ * Invalidate this class's entry in the cache.
*
- * @param int $guid The guid
+ * @param int $guid The entity guid
+ *
+ * @return void
+ * @access private
*/
-function invalidate_cache_for_entity($guid) {
+function _elgg_invalidate_cache_for_entity($guid) {
global $ENTITY_CACHE;
$guid = (int)$guid;
unset($ENTITY_CACHE[$guid]);
- //$ENTITY_CACHE->delete($guid);
+
+ elgg_get_metadata_cache()->clear($guid);
}
/**
* Cache an entity.
*
+ * Stores an entity in $ENTITY_CACHE;
+ *
* @param ElggEntity $entity Entity to cache
+ *
+ * @return void
+ * @see _elgg_retrieve_cached_entity()
+ * @see _elgg_invalidate_cache_for_entity()
+ * @access private
+ * @todo Use an ElggCache object
*/
-function cache_entity(ElggEntity $entity) {
- global $ENTITY_CACHE;
+function _elgg_cache_entity(ElggEntity $entity) {
+ global $ENTITY_CACHE, $ENTITY_CACHE_DISABLED_GUIDS;
+
+ // Don't cache non-plugin entities while access control is off, otherwise they could be
+ // exposed to users who shouldn't see them when control is re-enabled.
+ if (!($entity instanceof ElggPlugin) && elgg_get_ignore_access()) {
+ return;
+ }
+
+ $guid = $entity->getGUID();
+ if (isset($ENTITY_CACHE_DISABLED_GUIDS[$guid])) {
+ return;
+ }
+
+ // Don't store too many or we'll have memory problems
+ // @todo Pick a less arbitrary limit
+ if (count($ENTITY_CACHE) > 256) {
+ $random_guid = array_rand($ENTITY_CACHE);
- $ENTITY_CACHE[$entity->guid] = $entity;
+ unset($ENTITY_CACHE[$random_guid]);
+
+ // Purge separate metadata cache. Original idea was to do in entity destructor, but that would
+ // have caused a bunch of unnecessary purges at every shutdown. Doing it this way we have no way
+ // to know that the expunged entity will be GCed (might be another reference living), but that's
+ // OK; the metadata will reload if necessary.
+ elgg_get_metadata_cache()->clear($random_guid);
+ }
+
+ $ENTITY_CACHE[$guid] = $entity;
}
/**
* Retrieve a entity from the cache.
*
* @param int $guid The guid
+ *
+ * @return ElggEntity|bool false if entity not cached, or not fully loaded
+ * @see _elgg_cache_entity()
+ * @see _elgg_invalidate_cache_for_entity()
+ * @access private
*/
-function retrieve_cached_entity($guid) {
+function _elgg_retrieve_cached_entity($guid) {
global $ENTITY_CACHE;
- $guid = (int)$guid;
-
if (isset($ENTITY_CACHE[$guid])) {
if ($ENTITY_CACHE[$guid]->isFullyLoaded()) {
return $ENTITY_CACHE[$guid];
@@ -1275,191 +147,243 @@ function retrieve_cached_entity($guid) {
}
/**
- * As retrieve_cached_entity, but returns the result as a stdClass (compatible with load functions that
- * expect a database row.)
+ * Return the id for a given subtype.
*
- * @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.
+ * ElggEntity objects have a type and a subtype. Subtypes
+ * are defined upon creation and cannot be changed.
*
- * TODO: Move to a nicer place?
+ * Plugin authors generally don't need to use this function
+ * unless writing their own SQL queries. Use {@link ElggEntity::getSubtype()}
+ * to return the string subtype.
*
- * @param string $type
- * @param string $subtype
+ * @warning {@link ElggEntity::subtype} returns the ID. You probably want
+ * {@link ElggEntity::getSubtype()} instead!
+ *
+ * @internal Subtypes are stored in the entity_subtypes table. There is a foreign
+ * key in the entities table.
+ *
+ * @param string $type Type
+ * @param string $subtype Subtype
+ *
+ * @return int Subtype ID
+ * @link http://docs.elgg.org/DataModel/Entities/Subtypes
+ * @see get_subtype_from_id()
+ * @access private
*/
function get_subtype_id($type, $subtype) {
- global $CONFIG, $SUBTYPE_CACHE;
-
- $type = sanitise_string($type);
- $subtype = sanitise_string($subtype);
+ global $SUBTYPE_CACHE;
- if ($subtype=="") {
- //return $subtype;
- return FALSE;
+ if (!$subtype) {
+ return false;
}
- // 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();
- }
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
- $SUBTYPE_CACHE[$result->id] = $result;
+ // use the cache before hitting database
+ $result = _elgg_retrieve_cached_subtype($type, $subtype);
+ if ($result !== null) {
return $result->id;
}
- return FALSE;
+ return false;
}
/**
- * For a given subtype ID, return its identifier text.
+ * Return string name for a given subtype ID.
*
- * TODO: Move to a nicer place?
+ * @param int $subtype_id Subtype ID
*
- * @param int $subtype_id
+ * @return string|false Subtype name, false if subtype not found
+ * @link http://docs.elgg.org/DataModel/Entities/Subtypes
+ * @see get_subtype_from_id()
+ * @access private
*/
function get_subtype_from_id($subtype_id) {
- global $CONFIG, $SUBTYPE_CACHE;
-
- $subtype_id = (int)$subtype_id;
+ global $SUBTYPE_CACHE;
if (!$subtype_id) {
return false;
}
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
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();
- }
+ return false;
+}
+
+/**
+ * Retrieve subtype from the cache.
+ *
+ * @param string $type
+ * @param string $subtype
+ * @return stdClass|null
+ *
+ * @access private
+ */
+function _elgg_retrieve_cached_subtype($type, $subtype) {
+ global $SUBTYPE_CACHE;
- $SUBTYPE_CACHE[$subtype_id] = $result;
- return $result->subtype;
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
}
- return false;
+ foreach ($SUBTYPE_CACHE as $obj) {
+ if ($obj->type === $type && $obj->subtype === $subtype) {
+ return $obj;
+ }
+ }
+ return null;
}
/**
- * This function tests to see if a subtype has a registered class handler.
+ * Fetch all suptypes from DB to local cache.
*
- * @param string $type The type
- * @param string $subtype The subtype
- * @return a class name or null
+ * @access private
*/
-function get_subtype_class($type, $subtype) {
+function _elgg_populate_subtype_cache() {
global $CONFIG, $SUBTYPE_CACHE;
+
+ $results = get_data("SELECT * FROM {$CONFIG->dbprefix}entity_subtypes");
+
+ $SUBTYPE_CACHE = array();
+ foreach ($results as $row) {
+ $SUBTYPE_CACHE[$row->id] = $row;
+ }
+}
- $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 the class name for a registered type and subtype.
+ *
+ * Entities can be registered to always be loaded as a certain class
+ * with add_subtype() or update_subtype(). This function returns the class
+ * name if found and NULL if not.
+ *
+ * @param string $type The type
+ * @param string $subtype The subtype
+ *
+ * @return string|null a class name or null
+ * @see get_subtype_from_id()
+ * @see get_subtype_class_from_id()
+ * @access private
+ */
+function get_subtype_class($type, $subtype) {
+ global $SUBTYPE_CACHE;
- $SUBTYPE_CACHE[$result->id] = $result;
- return $result->class;
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
+ // use the cache before going to the database
+ $obj = _elgg_retrieve_cached_subtype($type, $subtype);
+ if ($obj) {
+ return $obj->class;
}
- return NULL;
+ return null;
}
/**
- * This function tests to see if a subtype has a registered class handler by its id.
+ * Returns the class name for a subtype id.
+ *
+ * @param int $subtype_id The subtype id
*
- * @param int $subtype_id The subtype
- * @return a class name or null
+ * @return string|null
+ * @see get_subtype_class()
+ * @see get_subtype_from_id()
+ * @access private
*/
function get_subtype_class_from_id($subtype_id) {
- global $CONFIG, $SUBTYPE_CACHE;
-
- $subtype_id = (int)$subtype_id;
+ global $SUBTYPE_CACHE;
if (!$subtype_id) {
- return false;
+ return null;
}
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
+ }
+
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();
- }
- $SUBTYPE_CACHE[$subtype_id] = $result;
- return $result->class;
- }
-
- return NULL;
+ return null;
}
/**
- * This function will register a new subtype, returning its ID as required.
+ * Register ElggEntities with a certain type and subtype to be loaded as a specific class.
+ *
+ * By default entities are loaded as one of the 4 parent objects: site, user, object, or group.
+ * If you subclass any of these you can register the classname with add_subtype() so
+ * it will be loaded as that class automatically when retrieved from the database with
+ * {@link get_entity()}.
*
- * @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)
+ * @warning This function cannot be used to change the class for a type-subtype pair.
+ * Use update_subtype() for that.
+ *
+ * @param string $type The type you're subtyping (site, user, object, or group)
+ * @param string $subtype The subtype
+ * @param string $class Optional class name for the object
+ *
+ * @return int
+ * @link http://docs.elgg.org/Tutorials/Subclasses
+ * @link http://docs.elgg.org/DataModel/Entities
+ * @see update_subtype()
+ * @see remove_subtype()
+ * @see get_entity()
*/
function add_subtype($type, $subtype, $class = "") {
- global $CONFIG;
- $type = sanitise_string($type);
- $subtype = sanitise_string($subtype);
- $class = sanitise_string($class);
+ global $CONFIG, $SUBTYPE_CACHE;
- // Short circuit if no subtype is given
- if ($subtype == "") {
+ 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')");
+ if (!$id) {
+ // In cache we store non-SQL-escaped strings because that's what's returned by query
+ $cache_obj = (object) array(
+ 'type' => $type,
+ 'subtype' => $subtype,
+ 'class' => $class,
+ );
+
+ $type = sanitise_string($type);
+ $subtype = sanitise_string($subtype);
+ $class = sanitise_string($class);
+
+ $id = insert_data("INSERT INTO {$CONFIG->dbprefix}entity_subtypes"
+ . " (type, subtype, class) VALUES ('$type', '$subtype', '$class')");
+
+ // add entry to cache
+ $cache_obj->id = $id;
+ $SUBTYPE_CACHE[$id] = $cache_obj;
}
return $id;
}
/**
- * Removes a registered subtype
+ * Removes a registered ElggEntity type, subtype, and classname.
*
- * @param string $type
- * @param string $subtype
+ * @warning You do not want to use this function. If you want to unregister
+ * a class for a subtype, use update_subtype(). Using this function will
+ * permanently orphan all the objects created with the specified subtype.
+ *
+ * @param string $type Type
+ * @param string $subtype Subtype
+ *
+ * @return bool
+ * @see add_subtype()
+ * @see update_subtype()
*/
function remove_subtype($type, $subtype) {
global $CONFIG;
@@ -1467,41 +391,68 @@ function remove_subtype($type, $subtype) {
$type = sanitise_string($type);
$subtype = sanitise_string($subtype);
- return delete_data("DELETE FROM {$CONFIG->dbprefix}entity_subtypes WHERE type = '$type' AND subtype = '$subtype'");
+ return delete_data("DELETE FROM {$CONFIG->dbprefix}entity_subtypes"
+ . " WHERE type = '$type' AND subtype = '$subtype'");
}
/**
- * Update the registered information
+ * Update a registered ElggEntity type, subtype, and class name
*
- * @param string $type
- * @param string $subtype
- * @param string $class
+ * @param string $type Type
+ * @param string $subtype Subtype
+ * @param string $class Class name to use when loading this entity
+ *
+ * @return bool
*/
function update_subtype($type, $subtype, $class = '') {
- global $CONFIG;
+ global $CONFIG, $SUBTYPE_CACHE;
- if (!$id = get_subtype_id($type, $subtype)) {
- return FALSE;
+ $id = get_subtype_id($type, $subtype);
+ if (!$id) {
+ return false;
+ }
+
+ if ($SUBTYPE_CACHE === null) {
+ _elgg_populate_subtype_cache();
}
+
+ $unescaped_class = $class;
+
$type = sanitise_string($type);
$subtype = sanitise_string($subtype);
-
- return update_data("UPDATE {$CONFIG->dbprefix}entity_subtypes
+ $class = sanitise_string($class);
+
+ $success = update_data("UPDATE {$CONFIG->dbprefix}entity_subtypes
SET type = '$type', subtype = '$subtype', class = '$class'
WHERE id = $id
");
-}
+ if ($success && isset($SUBTYPE_CACHE[$id])) {
+ $SUBTYPE_CACHE[$id]->class = $unescaped_class;
+ }
+
+ return $success;
+}
/**
- * Update an existing entity.
+ * Update an entity in the database.
+ *
+ * There are 4 basic entity types: site, user, object, and group.
+ * All entities are split between two tables: the entities table and their type table.
+ *
+ * @warning Plugin authors should never call this directly. Use ->save() instead.
*
- * @param int $guid
- * @param int $owner_guid
- * @param int $access_id
- * @param int $container_guid
+ * @param int $guid The guid of the entity to update
+ * @param int $owner_guid The new owner guid
+ * @param int $access_id The new access id
+ * @param int $container_guid The new container guid
+ * @param int $time_created The time creation timestamp
+ *
+ * @return bool
+ * @throws InvalidParameterException
+ * @access private
*/
-function update_entity($guid, $owner_guid, $access_id, $container_guid = null) {
+function update_entity($guid, $owner_guid, $access_id, $container_guid = null, $time_created = null) {
global $CONFIG, $ENTITY_CACHE;
$guid = (int)$guid;
@@ -1515,12 +466,25 @@ function update_entity($guid, $owner_guid, $access_id, $container_guid = null) {
$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 ($time_created == null) {
+ $time_created = $entity->time_created;
+ } else {
+ $time_created = (int) $time_created;
+ }
+
+ if ($access_id == ACCESS_DEFAULT) {
+ throw new InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.h');
+ }
+
+ if ($entity && $entity->canEdit()) {
+ if (elgg_trigger_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_created='$time_created',
+ time_updated='$time' WHERE guid=$guid");
if ($entity instanceof ElggObject) {
- update_river_access_by_object($guid,$access_id);
+ update_river_access_by_object($guid, $access_id);
}
// If memcache is available then delete this entry from the cache
@@ -1529,11 +493,11 @@ function update_entity($guid, $owner_guid, $access_id, $container_guid = null) {
$newentity_cache = new ElggMemcache('new_entity_cache');
}
if ($newentity_cache) {
- $new_entity = $newentity_cache->delete($guid);
+ $newentity_cache->delete($guid);
}
// Handle cases where there was no error BUT no rows were updated!
- if ($ret===false) {
+ if ($ret === false) {
return false;
}
@@ -1543,27 +507,38 @@ function update_entity($guid, $owner_guid, $access_id, $container_guid = null) {
}
/**
- * Determine whether a given user is able to write to a given container.
+ * Determine if a given user can write to an entity container.
+ *
+ * An entity can be a container for any other entity by setting the
+ * container_guid. container_guid can differ from owner_guid.
*
- * @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.
+ * A plugin hook container_permissions_check:$entity_type is emitted to allow granular
+ * access controls in plugins.
+ *
+ * @param int $user_guid The user guid, or 0 for logged in user
+ * @param int $container_guid The container, or 0 for the current page owner.
+ * @param string $type The type of entity we're looking to write
+ * @param string $subtype The subtype of the entity we're looking to write
+ *
+ * @return bool
+ * @link http://docs.elgg.org/DataModel/Containers
*/
-function can_write_to_container($user_guid = 0, $container_guid = 0, $entity_type = 'all') {
- global $CONFIG;
-
+function can_write_to_container($user_guid = 0, $container_guid = 0, $type = 'all', $subtype = 'all') {
$user_guid = (int)$user_guid;
$user = get_entity($user_guid);
if (!$user) {
- $user = get_loggedin_user();
+ $user = elgg_get_logged_in_user_entity();
}
$container_guid = (int)$container_guid;
if (!$container_guid) {
- $container_guid = page_owner();
+ $container_guid = elgg_get_page_owner_guid();
}
+ $return = false;
+
if (!$container_guid) {
- $return = TRUE;
+ $return = true;
}
$container = get_entity($container_guid);
@@ -1571,41 +546,62 @@ function can_write_to_container($user_guid = 0, $container_guid = 0, $entity_typ
if ($container) {
// If the user can edit the container, they can also write to it
if ($container->canEdit($user_guid)) {
- $return = TRUE;
+ $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;
+ // If still not approved, see if the user is a member of the group
+ // @todo this should be moved to the groups plugin/library
+ if (!$return && $user && $container instanceof ElggGroup) {
+ /* @var ElggGroup $container */
+ if ($container->isMember($user)) {
+ $return = true;
}
}
}
// See if anyone else has anything to say
- return trigger_plugin_hook('container_permissions_check', $entity_type,
- array('container' => $container, 'user' => $user), $return);
+ return elgg_trigger_plugin_hook(
+ 'container_permissions_check',
+ $type,
+ array(
+ 'container' => $container,
+ 'user' => $user,
+ 'subtype' => $subtype
+ ),
+ $return);
}
/**
- * 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
+ * Create a new entry in the entities table.
+ *
+ * Saves the base information in the entities table for the entity. Saving
+ * the type information is handled in the calling class method.
+ *
+ * @warning Plugin authors should never call this directly. Always use entity objects.
+ *
+ * @warning Entities must have an entry in both the entities table and their type table
+ * or they will throw an exception when loaded.
+ *
+ * @param string $type The type of the entity (site, user, object, group).
+ * @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. 0 for current.
+ * @param int $container_guid The container GUID
+ *
+ * @return int|false The new entity's GUID, or false on failure
+ * @throws InvalidParameterException
+ * @link http://docs.elgg.org/DataModel/Entities
+ * @access private
*/
-function create_entity($type, $subtype, $owner_guid, $access_id, $site_guid = 0, $container_guid = 0) {
+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);
+ $subtype_id = 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;
@@ -1614,31 +610,46 @@ function create_entity($type, $subtype, $owner_guid, $access_id, $site_guid = 0,
if ($container_guid == 0) {
$container_guid = $owner_guid;
}
+ $access_id = (int)$access_id;
+ if ($access_id == ACCESS_DEFAULT) {
+ throw new InvalidParameterException('ACCESS_DEFAULT is not a valid access level. See its documentation in elgglib.h');
+ }
- $user = get_loggedin_user();
- if (!can_write_to_container($user->guid, $owner_guid, $type)) {
+ $user_guid = elgg_get_logged_in_user_guid();
+ if (!can_write_to_container($user_guid, $owner_guid, $type, $subtype)) {
return false;
}
if ($owner_guid != $container_guid) {
- if (!can_write_to_container($user->guid, $container_guid, $type)) {
+ if (!can_write_to_container($user_guid, $container_guid, $type, $subtype)) {
return false;
}
}
- if ($type=="") {
+ 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, last_action) values
- ('$type',$subtype, $owner_guid, $site_guid, $container_guid, $access_id, $time, $time, $time)");
+ (type, subtype, owner_guid, site_guid, container_guid,
+ access_id, time_created, time_updated, last_action)
+ values
+ ('$type',$subtype_id, $owner_guid, $site_guid, $container_guid,
+ $access_id, $time, $time, $time)");
}
/**
- * Retrieve the entity details for a specific GUID, returning it as a stdClass db row.
+ * Returns a database row from the entities table.
*
- * You will only get an object if a) it exists, b) you have access to it.
+ * @tip Use get_entity() to return the fully loaded entity.
+ *
+ * @warning This will only return results if a) it exists, b) you have access to it.
+ * see {@link get_access_sql_suffix()}.
*
* @param int $guid The GUID of the object to extract
+ *
+ * @return stdClass|false
+ * @link http://docs.elgg.org/DataModel/Entities
+ * @see entity_row_to_elggstar()
+ * @access private
*/
function get_entity_as_row($guid) {
global $CONFIG;
@@ -1655,6 +666,19 @@ function get_entity_as_row($guid) {
/**
* Create an Elgg* object from a given entity row.
+ *
+ * Handles loading all tables into the correct class.
+ *
+ * @param stdClass $row The row of the entry in the entities table.
+ *
+ * @return ElggEntity|false
+ * @link http://docs.elgg.org/DataModel/Entities
+ * @see get_entity_as_row()
+ * @see add_subtype()
+ * @see get_entity()
+ * @access private
+ *
+ * @throws ClassException|InstallationException
*/
function entity_row_to_elggstar($row) {
if (!($row instanceof stdClass)) {
@@ -1679,31 +703,39 @@ function entity_row_to_elggstar($row) {
return $new_entity;
}
+ // load class for entity if one is registered
$classname = get_subtype_class_from_id($row->subtype);
- if ($classname!="") {
+ 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'));
+ $msg = elgg_echo('ClassException:ClassnameNotClass', array($classname, 'ElggEntity'));
+ throw new ClassException($msg);
}
- }
- else {
- error_log(sprintf(elgg_echo('ClassNotFoundException:MissingClass'), $classname));
+ } else {
+ error_log(elgg_echo('ClassNotFoundException:MissingClass', array($classname)));
}
}
- else {
+
+ if (!$new_entity) {
+ //@todo Make this into a function
switch ($row->type) {
case 'object' :
- $new_entity = new ElggObject($row); break;
+ $new_entity = new ElggObject($row);
+ break;
case 'user' :
- $new_entity = new ElggUser($row); break;
+ $new_entity = new ElggUser($row);
+ break;
case 'group' :
- $new_entity = new ElggGroup($row); break;
+ $new_entity = new ElggGroup($row);
+ break;
case 'site' :
- $new_entity = new ElggSite($row); break;
+ $new_entity = new ElggSite($row);
+ break;
default:
- throw new InstallationException(sprintf(elgg_echo('InstallationException:TypeNotSupported'), $row->type));
+ $msg = elgg_echo('InstallationException:TypeNotSupported', array($row->type));
+ throw new InstallationException($msg);
}
}
@@ -1716,51 +748,134 @@ function entity_row_to_elggstar($row) {
}
/**
- * Return the entity for a given guid as the correct object.
+ * Loads and returns an entity object from a guid.
+ *
* @param int $guid The GUID of the entity
- * @return a child of ElggEntity appropriate for the type.
+ *
+ * @return ElggEntity The correct Elgg or custom object based upon entity type and subtype
+ * @link http://docs.elgg.org/DataModel/Entities
*/
function get_entity($guid) {
- static $newentity_cache;
- $new_entity = false;
- if ((!$newentity_cache) && (is_memcache_available())) {
- $newentity_cache = new ElggMemcache('new_entity_cache');
+ // This should not be a static local var. Notice that cache writing occurs in a completely
+ // different instance outside this function.
+ // @todo We need a single Memcache instance with a shared pool of namespace wrappers. This function would pull an instance from the pool.
+ static $shared_cache;
+
+ // We could also use: if (!(int) $guid) { return FALSE },
+ // but that evaluates to a false positive for $guid = TRUE.
+ // This is a bit slower, but more thorough.
+ if (!is_numeric($guid) || $guid === 0 || $guid === '0') {
+ return false;
+ }
+
+ // Check local cache first
+ $new_entity = _elgg_retrieve_cached_entity($guid);
+ if ($new_entity) {
+ return $new_entity;
}
- if ($newentity_cache) {
- $new_entity = $newentity_cache->load($guid);
+ // Check shared memory cache, if available
+ if (null === $shared_cache) {
+ if (is_memcache_available()) {
+ $shared_cache = new ElggMemcache('new_entity_cache');
+ } else {
+ $shared_cache = false;
+ }
}
- if ($new_entity) {
- return $new_entity;
+ // until ACLs in memcache, DB query is required to determine access
+ $entity_row = get_entity_as_row($guid);
+ if (!$entity_row) {
+ return false;
+ }
+
+ if ($shared_cache) {
+ $cached_entity = $shared_cache->load($guid);
+ // @todo store ACLs in memcache https://github.com/elgg/elgg/issues/3018#issuecomment-13662617
+ if ($cached_entity) {
+ // @todo use ACL and cached entity access_id to determine if user can see it
+ return $cached_entity;
+ }
+ }
+
+ // don't let incomplete entities cause fatal exceptions
+ try {
+ $new_entity = entity_row_to_elggstar($entity_row);
+ } catch (IncompleteEntityException $e) {
+ return false;
}
- return entity_row_to_elggstar(get_entity_as_row($guid));
+ if ($new_entity) {
+ _elgg_cache_entity($new_entity);
+ }
+ return $new_entity;
}
+/**
+ * Does an entity exist?
+ *
+ * This function checks for the existence of an entity independent of access
+ * permissions. It is useful for situations when a user cannot access an entity
+ * and it must be determined whether entity has been deleted or the access level
+ * has changed.
+ *
+ * @param int $guid The GUID of the entity
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_entity_exists($guid) {
+ global $CONFIG;
+
+ $guid = sanitize_int($guid);
+
+ $query = "SELECT count(*) as total FROM {$CONFIG->dbprefix}entities WHERE guid = $guid";
+ $result = get_data_row($query);
+ if ($result->total == 0) {
+ return false;
+ } else {
+ return true;
+ }
+}
/**
- * Get all entities. NB: Plural arguments can be written as
- * singular if only specifying a single element. (e.g., 'type' => 'object'
- * vs 'types' => array('object')).
+ * Returns an array of entities with optional filtering.
+ *
+ * Entities are the basic unit of storage in Elgg. This function
+ * provides the simplest way to get an array of entities. There
+ * are many options available that can be passed to filter
+ * what sorts of entities are returned.
+ *
+ * @tip To output formatted strings of entities, use {@link elgg_list_entities()} and
+ * its cousins.
+ *
+ * @tip Plural arguments can be written as singular if only specifying a
+ * single element. ('type' => 'object' vs 'types' => array('object')).
*
* @param array $options Array in format:
*
- * types => NULL|STR entity type (SQL: type IN ('type1', 'type2') Joined with subtypes by AND...see below)
+ * types => NULL|STR entity type (type IN ('type1', 'type2')
+ * Joined with subtypes by AND. See below)
*
* subtypes => NULL|STR entity subtype (SQL: subtype IN ('subtype1', 'subtype2))
+ * Use ELGG_ENTITIES_NO_VALUE for no subtype.
+ *
+ * type_subtype_pairs => NULL|ARR (array('type' => 'subtype'))
+ * (type = '$type' AND subtype = '$subtype') pairs
*
- * type_subtype_pairs => NULL|ARR (array('type' => 'subtype')) (SQL: type = '$type' AND subtype = '$subtype') pairs
+ * guids => NULL|ARR Array of entity guids
*
- * owner_guids => NULL|INT entity guid
+ * owner_guids => NULL|ARR Array of owner guids
*
- * container_guids => NULL|INT container_guid
+ * container_guids => NULL|ARR Array of container_guids
*
- * site_guids => NULL (current_site)|INT site_guid
+ * site_guids => NULL (current_site)|ARR Array of site_guid
*
* order_by => NULL (time_created desc)|STR SQL order by clause
*
- * limit => NULL (10)|INT SQL limit clause
+ * reverse_order_by => BOOL Reverse the default order by clause
+ *
+ * limit => NULL (10)|INT SQL limit clause (0 means no limit)
*
* offset => NULL (0)|INT SQL offset clause
*
@@ -1778,8 +893,16 @@ function get_entity($guid) {
*
* joins => array() Additional joins
*
- * @return if count, int
- * if not count, array or false if no entities
+ * callback => string A callback function to pass each row through
+ *
+ * @return mixed If count, int. If not count, array. false on errors.
+ * @since 1.7.0
+ * @see elgg_get_entities_from_metadata()
+ * @see elgg_get_entities_from_relationship()
+ * @see elgg_get_entities_from_access_id()
+ * @see elgg_get_entities_from_annotations()
+ * @see elgg_list_entities()
+ * @link http://docs.elgg.org/DataModel/Entities/Getters
*/
function elgg_get_entities(array $options = array()) {
global $CONFIG;
@@ -1789,6 +912,7 @@ function elgg_get_entities(array $options = array()) {
'subtypes' => ELGG_ENTITIES_ANY_VALUE,
'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
+ 'guids' => ELGG_ENTITIES_ANY_VALUE,
'owner_guids' => ELGG_ENTITIES_ANY_VALUE,
'container_guids' => ELGG_ENTITIES_ANY_VALUE,
'site_guids' => $CONFIG->site_guid,
@@ -1798,6 +922,7 @@ function elgg_get_entities(array $options = array()) {
'created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
'created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
+ 'reverse_order_by' => false,
'order_by' => 'e.time_created desc',
'group_by' => ELGG_ENTITIES_ANY_VALUE,
'limit' => 10,
@@ -1805,21 +930,27 @@ function elgg_get_entities(array $options = array()) {
'count' => FALSE,
'selects' => array(),
'wheres' => array(),
- 'joins' => array()
+ 'joins' => array(),
+
+ 'callback' => 'entity_row_to_elggstar',
+
+ '__ElggBatch' => null,
);
$options = array_merge($defaults, $options);
- // can't use helper function with type_subtype_pair because it's already an array...just need to merge it
+ // can't use helper function with type_subtype_pair because
+ // it's already an array...just need to merge it
if (isset($options['type_subtype_pair'])) {
if (isset($options['type_subtype_pairs'])) {
- $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'], $options['type_subtype_pair']);
+ $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'],
+ $options['type_subtype_pair']);
} else {
$options['type_subtype_pairs'] = $options['type_subtype_pair'];
}
}
- $singulars = array('type', 'subtype', 'owner_guid', 'container_guid', 'site_guid');
+ $singulars = array('type', 'subtype', 'guid', 'owner_guid', 'container_guid', 'site_guid');
$options = elgg_normalise_plural_options_array($options, $singulars);
// evaluate where clauses
@@ -1829,16 +960,17 @@ function elgg_get_entities(array $options = array()) {
$wheres = $options['wheres'];
- $wheres[] = elgg_get_entity_type_subtype_where_sql('e', $options['types'], $options['subtypes'], $options['type_subtype_pairs']);
- $wheres[] = elgg_get_entity_site_where_sql('e', $options['site_guids']);
- $wheres[] = elgg_get_entity_owner_where_sql('e', $options['owner_guids']);
- $wheres[] = elgg_get_entity_container_where_sql('e', $options['container_guids']);
+ $wheres[] = elgg_get_entity_type_subtype_where_sql('e', $options['types'],
+ $options['subtypes'], $options['type_subtype_pairs']);
+
+ $wheres[] = elgg_get_guid_based_where_sql('e.guid', $options['guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']);
+
$wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
$options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
- // remove identical where clauses
- $wheres = array_unique($wheres);
-
// see if any functions failed
// remove empty strings on successful functions
foreach ($wheres as $i => $where) {
@@ -1849,6 +981,9 @@ function elgg_get_entities(array $options = array()) {
}
}
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
+
// evaluate join clauses
if (!is_array($options['joins'])) {
$options['joins'] = array($options['joins']);
@@ -1869,7 +1004,7 @@ function elgg_get_entities(array $options = array()) {
if ($options['selects']) {
$selects = '';
foreach ($options['selects'] as $select) {
- $selects = ", $select";
+ $selects .= ", $select";
}
} else {
$selects = '';
@@ -1895,24 +1030,53 @@ function elgg_get_entities(array $options = array()) {
// Add access controls
$query .= get_access_sql_suffix('e');
+
+ // reverse order by
+ if ($options['reverse_order_by']) {
+ $options['order_by'] = elgg_sql_reverse_order_by_clause($options['order_by']);
+ }
+
if (!$options['count']) {
- if ($options['group_by'] = sanitise_string($options['group_by'])) {
+ if ($options['group_by']) {
$query .= " GROUP BY {$options['group_by']}";
}
- if ($options['order_by'] = sanitise_string($options['order_by'])) {
+ if ($options['order_by']) {
$query .= " ORDER BY {$options['order_by']}";
}
if ($options['limit']) {
- $limit = sanitise_int($options['limit']);
- $offset = sanitise_int($options['offset']);
+ $limit = sanitise_int($options['limit'], false);
+ $offset = sanitise_int($options['offset'], false);
$query .= " LIMIT $offset, $limit";
}
- $dt = get_data($query, "entity_row_to_elggstar");
+ if ($options['callback'] === 'entity_row_to_elggstar') {
+ $dt = _elgg_fetch_entities_from_sql($query, $options['__ElggBatch']);
+ } else {
+ $dt = get_data($query, $options['callback']);
+ }
+
+ if ($dt) {
+ // populate entity and metadata caches
+ $guids = array();
+ foreach ($dt as $item) {
+ // A custom callback could result in items that aren't ElggEntity's, so check for them
+ if ($item instanceof ElggEntity) {
+ _elgg_cache_entity($item);
+ // plugins usually have only settings
+ if (!$item instanceof ElggPlugin) {
+ $guids[] = $item->guid;
+ }
+ }
+ }
+ // @todo Without this, recursive delete fails. See #4568
+ reset($dt);
- //@todo normalize this to array()
+ if ($guids) {
+ elgg_get_metadata_cache()->populateFromEntities($guids);
+ }
+ }
return $dt;
} else {
$total = get_data_row($query);
@@ -1921,100 +1085,114 @@ function elgg_get_entities(array $options = array()) {
}
/**
- * @deprecated 1.7. Use elgg_get_entities().
- * @param $type
- * @param $subtype
- * @param $owner_guid
- * @param $order_by
- * @param $limit
- * @param $offset
- * @param $count
- * @param $site_guid
- * @param $container_guid
- * @param $timelower
- * @param $timeupper
- * @return unknown_type
+ * Return entities from an SQL query generated by elgg_get_entities.
+ *
+ * @param string $sql
+ * @param ElggBatch $batch
+ * @return ElggEntity[]
+ *
+ * @access private
+ * @throws LogicException
*/
-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) {
- elgg_deprecated_notice('get_entities() was deprecated by elgg_get_entities().', 1.7);
-
- // rewrite owner_guid to container_guid to emulate old functionality
- if ($owner_guid != "") {
- if (is_null($container_guid)) {
- $container_guid = $owner_guid;
- $owner_guid = NULL;
- }
- }
+function _elgg_fetch_entities_from_sql($sql, ElggBatch $batch = null) {
+ static $plugin_subtype;
+ if (null === $plugin_subtype) {
+ $plugin_subtype = get_subtype_id('object', 'plugin');
+ }
+
+ // Keys are types, values are columns that, if present, suggest that the secondary
+ // table is already JOINed
+ $types_to_optimize = array(
+ 'object' => 'title',
+ 'user' => 'password',
+ 'group' => 'name',
+ );
- $options = array();
- if ($type) {
- if (is_array($type)) {
- $options['types'] = $type;
- } else {
- $options['type'] = $type;
- }
+ $rows = get_data($sql);
+
+ // guids to look up in each type
+ $lookup_types = array();
+ // maps GUIDs to the $rows key
+ $guid_to_key = array();
+
+ if (isset($rows[0]->type, $rows[0]->subtype)
+ && $rows[0]->type === 'object'
+ && $rows[0]->subtype == $plugin_subtype) {
+ // Likely the entire resultset is plugins, which have already been optimized
+ // to JOIN the secondary table. In this case we allow retrieving from cache,
+ // but abandon the extra queries.
+ $types_to_optimize = array();
}
- if ($subtype) {
- if (is_array($subtype)) {
- $options['subtypes'] = $subtype;
- } else {
- $options['subtype'] = $subtype;
+ // First pass: use cache where possible, gather GUIDs that we're optimizing
+ foreach ($rows as $i => $row) {
+ if (empty($row->guid) || empty($row->type)) {
+ throw new LogicException('Entity row missing guid or type');
+ }
+ if ($entity = _elgg_retrieve_cached_entity($row->guid)) {
+ $rows[$i] = $entity;
+ continue;
+ }
+ if (isset($types_to_optimize[$row->type])) {
+ // check if row already looks JOINed.
+ if (isset($row->{$types_to_optimize[$row->type]})) {
+ // Row probably already contains JOINed secondary table. Don't make another query just
+ // to pull data that's already there
+ continue;
+ }
+ $lookup_types[$row->type][] = $row->guid;
+ $guid_to_key[$row->guid] = $i;
+ }
+ }
+ // Do secondary queries and merge rows
+ if ($lookup_types) {
+ $dbprefix = elgg_get_config('dbprefix');
+
+ foreach ($lookup_types as $type => $guids) {
+ $set = "(" . implode(',', $guids) . ")";
+ $sql = "SELECT * FROM {$dbprefix}{$type}s_entity WHERE guid IN $set";
+ $secondary_rows = get_data($sql);
+ if ($secondary_rows) {
+ foreach ($secondary_rows as $secondary_row) {
+ $key = $guid_to_key[$secondary_row->guid];
+ // cast to arrays to merge then cast back
+ $rows[$key] = (object)array_merge((array)$rows[$key], (array)$secondary_row);
+ }
+ }
}
}
-
- if ($owner_guid) {
- if (is_array($owner_guid)) {
- $options['owner_guids'] = $owner_guid;
+ // Second pass to finish conversion
+ foreach ($rows as $i => $row) {
+ if ($row instanceof ElggEntity) {
+ continue;
} else {
- $options['owner_guid'] = $owner_guid;
+ try {
+ $rows[$i] = entity_row_to_elggstar($row);
+ } catch (IncompleteEntityException $e) {
+ // don't let incomplete entities throw fatal errors
+ unset($rows[$i]);
+
+ // report incompletes to the batch process that spawned this query
+ if ($batch) {
+ $batch->reportIncompleteEntity($row);
+ }
+ }
}
}
-
- if ($order_by) {
- $options['order_by'] = $order_by;
- }
-
- // need to pass 0 for all option
- $options['limit'] = $limit;
-
- if ($offset) {
- $options['offset'] = $offset;
- }
-
- if ($count) {
- $options['count'] = $count;
- }
-
- if ($site_guid) {
- $options['site_guids'] = $site_guid;
- }
-
- if ($container_guid) {
- $options['container_guids'] = $container_guid;
- }
-
- if ($timeupper) {
- $options['created_time_upper'] = $timeupper;
- }
-
- if ($timelower) {
- $options['created_time_lower'] = $timelower;
- }
-
- $r = elgg_get_entities($options);
- return $r;
+ return $rows;
}
/**
- * Returns type and subtype SQL appropriate for inclusion in an IN clause.
+ * Returns SQL where clause for type and subtype on main entity table
+ *
+ * @param string $table Entity table prefix as defined in SELECT...FROM entities $table
+ * @param NULL|array $types Array of types or NULL if none.
+ * @param NULL|array $subtypes Array of subtypes or NULL if none
+ * @param NULL|array $pairs Array of pairs of types and subtypes
*
- * @param string $table entity table prefix.
- * @param NULL|$types
- * @param NULL|array $subtypes
- * @param NULL|array $pairs
* @return FALSE|string
+ * @since 1.7.0
+ * @access private
*/
function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pairs) {
// subtype depends upon type.
@@ -2028,8 +1206,8 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
return '';
}
- // these are the only valid types for entities in elgg as defined in the DB.
- $valid_types = array('object', 'user', 'group', 'site');
+ // these are the only valid types for entities in elgg
+ $valid_types = elgg_get_config('entity_types');
// pairs override
$wheres = array();
@@ -2055,7 +1233,7 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
foreach ($types as $type) {
if (!in_array($type, $valid_types)) {
$valid_types_count--;
- unset ($types[array_search($type, $types)]);
+ unset($types[array_search($type, $types)]);
} else {
// do the checking (and decrementing) in the subtype section.
$valid_subtypes_count += count($subtypes);
@@ -2073,13 +1251,24 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
$subtype_ids = array();
if ($subtypes) {
foreach ($subtypes as $subtype) {
- // check that the subtype is valid (with ELGG_ENTITIES_NO_VALUE being a valid subtype)
- if (ELGG_ENTITIES_NO_VALUE === $subtype || $subtype_id = get_subtype_id($type, $subtype)) {
- $subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $subtype) ? ELGG_ENTITIES_NO_VALUE : $subtype_id;
- } else {
- $valid_subtypes_count--;
- elgg_log("Type-subtype $type:$subtype' does not exist!", 'WARNING');
+ // check that the subtype is valid
+ if (!$subtype && ELGG_ENTITIES_NO_VALUE === $subtype) {
+ // subtype value is 0
+ $subtype_ids[] = ELGG_ENTITIES_NO_VALUE;
+ } elseif (!$subtype) {
+ // subtype is ignored.
+ // this handles ELGG_ENTITIES_ANY_VALUE, '', and anything falsy that isn't 0
continue;
+ } else {
+ $subtype_id = get_subtype_id($type, $subtype);
+
+ if ($subtype_id) {
+ $subtype_ids[] = $subtype_id;
+ } else {
+ $valid_subtypes_count--;
+ elgg_log("Type-subtype '$type:$subtype' does not exist!", 'NOTICE');
+ continue;
+ }
}
}
@@ -2107,7 +1296,7 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
foreach ($pairs as $paired_type => $paired_subtypes) {
if (!in_array($paired_type, $valid_types)) {
$valid_pairs_count--;
- unset ($pairs[array_search($paired_type, $pairs)]);
+ unset($pairs[array_search($paired_type, $pairs)]);
} else {
if ($paired_subtypes && !is_array($paired_subtypes)) {
$pairs[$paired_type] = array($paired_subtypes);
@@ -2125,11 +1314,14 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
if (is_array($paired_subtypes)) {
$paired_subtype_ids = array();
foreach ($paired_subtypes as $paired_subtype) {
- if (ELGG_ENTITIES_NO_VALUE === $paired_subtype || ($paired_subtype_id = get_subtype_id($paired_type, $paired_subtype))) {
- $paired_subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $paired_subtype) ? ELGG_ENTITIES_NO_VALUE : $paired_subtype_id;
+ if (ELGG_ENTITIES_NO_VALUE === $paired_subtype
+ || ($paired_subtype_id = get_subtype_id($paired_type, $paired_subtype))) {
+
+ $paired_subtype_ids[] = (ELGG_ENTITIES_NO_VALUE === $paired_subtype) ?
+ ELGG_ENTITIES_NO_VALUE : $paired_subtype_id;
} else {
$valid_pairs_subtypes_count--;
- elgg_log("Type-subtype $paired_type:$paired_subtype' does not exist!", 'WARNING');
+ elgg_log("Type-subtype '$paired_type:$paired_subtype' does not exist!", 'NOTICE');
// return false if we're all invalid subtypes in the only valid type
continue;
}
@@ -2142,7 +1334,8 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
if ($paired_subtype_ids_str = implode(',', $paired_subtype_ids)) {
- $wheres[] = "({$table}.type = '$paired_type' AND {$table}.subtype IN ($paired_subtype_ids_str))";
+ $wheres[] = "({$table}.type = '$paired_type'"
+ . " AND {$table}.subtype IN ($paired_subtype_ids_str))";
}
} else {
$wheres[] = "({$table}.type = '$paired_type')";
@@ -2159,78 +1352,47 @@ function elgg_get_entity_type_subtype_where_sql($table, $types, $subtypes, $pair
return '';
}
-
-
/**
- * Returns SQL for owner and containers.
+ * Returns SQL where clause for owner and containers.
*
- * @todo Probably DRY up once things are settled.
- * @param str $table
- * @param NULL|array $owner_guids
- * @return FALSE|str
+ * @param string $column Column name the guids should be checked against. Usually
+ * best to provide in table.column format.
+ * @param NULL|array $guids Array of GUIDs.
+ *
+ * @return false|string
+ * @since 1.8.0
+ * @access private
*/
-function elgg_get_entity_owner_where_sql($table, $owner_guids) {
+function elgg_get_guid_based_where_sql($column, $guids) {
// short circuit if nothing requested
- // 0 is a valid owner_guid.
- if (!$owner_guids && $owner_guids !== 0) {
+ // 0 is a valid guid
+ if (!$guids && $guids !== 0) {
return '';
}
// normalize and sanitise owners
- if (!is_array($owner_guids)) {
- $owner_guids = array($owner_guids);
- }
-
- $owner_guids_sanitised = array();
- foreach ($owner_guids as $owner_guid) {
- if (($owner_guid != sanitise_int($owner_guid))) {
- return FALSE;
- }
- $owner_guids_sanitised[] = $owner_guid;
- }
-
- $where = '';
-
- // implode(',', 0) returns 0.
- if (($owner_str = implode(',', $owner_guids_sanitised)) && ($owner_str !== FALSE) && ($owner_str !== '')) {
- $where = "({$table}.owner_guid IN ($owner_str))";
- }
-
- return $where;
-}
-
-/**
- * Returns SQL for containers.
- *
- * @param string $table entity table prefix
- * @param NULL|array $container_guids
- * @return FALSE|string
- */
-function elgg_get_entity_container_where_sql($table, $container_guids) {
- // short circuit if nothing is requested.
- // 0 is a valid container_guid.
- if (!$container_guids && $container_guids !== 0) {
- return '';
+ if (!is_array($guids)) {
+ $guids = array($guids);
}
- // normalize and sanitise containers
- if (!is_array($container_guids)) {
- $container_guids = array($container_guids);
- }
+ $guids_sanitized = array();
+ foreach ($guids as $guid) {
+ if ($guid !== ELGG_ENTITIES_NO_VALUE) {
+ $guid = sanitise_int($guid);
- $container_guids_sanitised = array();
- foreach ($container_guids as $container_guid) {
- if (($container_guid != sanitise_int($container_guid))) {
- return FALSE;
+ if (!$guid) {
+ return false;
+ }
}
- $container_guids_sanitised[] = $container_guid;
+ $guids_sanitized[] = $guid;
}
$where = '';
+ $guid_str = implode(',', $guids_sanitized);
// implode(',', 0) returns 0.
- if (FALSE !== $container_str = implode(',', $container_guids_sanitised)) {
- $where = "({$table}.container_guid IN ($container_str))";
+ if ($guid_str !== FALSE && $guid_str !== '') {
+ $where = "($column IN ($guid_str))";
}
return $where;
@@ -2239,16 +1401,19 @@ function elgg_get_entity_container_where_sql($table, $container_guids) {
/**
* Returns SQL where clause for entity time limits.
*
- * @param string $table Prefix for entity table name.
- * @param NULL|int $time_created_upper
- * @param NULL|int $time_created_lower
- * @param NULL|int $time_updated_upper
- * @param NULL|int $time_updated_lower
+ * @param string $table Entity table prefix as defined in
+ * SELECT...FROM entities $table
+ * @param NULL|int $time_created_upper Time created upper limit
+ * @param NULL|int $time_created_lower Time created lower limit
+ * @param NULL|int $time_updated_upper Time updated upper limit
+ * @param NULL|int $time_updated_lower Time updated lower limit
*
- * @return FALSE|str FALSE on fail, string on success.
+ * @return FALSE|string FALSE on fail, string on success.
+ * @since 1.7.0
+ * @access private
*/
-function elgg_get_entity_time_where_sql($table, $time_created_upper = NULL, $time_created_lower = NULL,
- $time_updated_upper = NULL, $time_updated_lower = NULL) {
+function elgg_get_entity_time_where_sql($table, $time_created_upper = NULL,
+$time_created_lower = NULL, $time_updated_upper = NULL, $time_updated_lower = NULL) {
$wheres = array();
@@ -2278,144 +1443,84 @@ function elgg_get_entity_time_where_sql($table, $time_created_upper = NULL, $tim
}
/**
- * Gets SQL for site entities
- *
- * @param string $table entity table name
- * @param NULL|array $site_guids
- * @return FALSE|string
- */
-function elgg_get_entity_site_where_sql($table, $site_guids) {
- // short circuit if nothing requested
- if (!$site_guids) {
- return '';
- }
-
- if (!is_array($site_guids)) {
- $site_guids = array($site_guids);
- }
-
- $site_guids_sanitised = array();
- foreach ($site_guids as $site_guid) {
- if (!$site_guid || ($site_guid != sanitise_int($site_guid))) {
- return FALSE;
- }
- $site_guids_sanitised[] = $site_guid;
- }
-
- if ($site_guids_str = implode(',', $site_guids_sanitised)) {
- return "({$table}.site_guid IN ($site_guids_str))";
- }
-
- return '';
-}
-
-/**
- * Returns a viewable list of entities
+ * Returns a string of parsed entities.
*
- * @see elgg_view_entity_list
+ * Displays list of entities with formatting specified
+ * by the entity view.
*
- * @param array $options Any elgg_get_entity() options plus:
+ * @tip Pagination is handled automatically.
*
- * full_view => BOOL Display full view entities
+ * @internal This also provides the views for elgg_view_annotation().
*
- * view_type_toggle => BOOL Display gallery / list switch
+ * @param array $options Any options from $getter options plus:
+ * full_view => BOOL Display full view entities
+ * list_type => STR 'list' or 'gallery'
+ * list_type_toggle => BOOL Display gallery / list switch
+ * pagination => BOOL Display pagination links
*
- * pagination => BOOL Display pagination links
+ * @param mixed $getter The entity getter function to use to fetch the entities
+ * @param mixed $viewer The function to use to view the entity list.
*
- * @return str
+ * @return string
+ * @since 1.7
+ * @see elgg_get_entities()
+ * @see elgg_view_entity_list()
+ * @link http://docs.elgg.org/Entities/Output
*/
-function elgg_list_entities($options) {
+function elgg_list_entities(array $options = array(), $getter = 'elgg_get_entities',
+ $viewer = 'elgg_view_entity_list') {
+
+ global $autofeed;
+ $autofeed = true;
+
+ $offset_key = isset($options['offset_key']) ? $options['offset_key'] : 'offset';
+
$defaults = array(
- 'offset' => (int) max(get_input('offset', 0), 0),
+ 'offset' => (int) max(get_input($offset_key, 0), 0),
'limit' => (int) max(get_input('limit', 10), 0),
'full_view' => TRUE,
- 'view_type_toggle' => FALSE,
- 'pagination' => TRUE
+ 'list_type_toggle' => FALSE,
+ 'pagination' => TRUE,
);
- $options = array_merge($defaults, $options);
-
- $count = elgg_get_entities(array_merge(array('count' => TRUE), $options));
- $entities = elgg_get_entities($options);
-
- return elgg_view_entity_list($entities, $count, $options['offset'],
- $options['limit'], $options['full_view'], $options['view_type_toggle'], $options['pagination']);
-}
-
-/**
- * @deprecated 1.7. Use elgg_list_entities().
- * @param $type
- * @param $subtype
- * @param $owner_guid
- * @param $limit
- * @param $fullview
- * @param $viewtypetoggle
- * @param $pagination
- * @return unknown_type
- */
-function list_entities($type= "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $pagination = true) {
- elgg_deprecated_notice('list_entities() was deprecated by elgg_list_entities()!', 1.7);
- $options = array();
-
- // rewrite owner_guid to container_guid to emulate old functionality
- if ($owner_guid) {
- $options['container_guids'] = $owner_guid;
- }
-
- if ($type) {
- $options['types'] = $type;
- }
+ $options = array_merge($defaults, $options);
- if ($subtype) {
- $options['subtypes'] = $subtype;
+ //backwards compatibility
+ if (isset($options['view_type_toggle'])) {
+ $options['list_type_toggle'] = $options['view_type_toggle'];
}
- if ($limit) {
- $options['limit'] = $limit;
- }
+ $options['count'] = TRUE;
+ $count = $getter($options);
- if ($offset = sanitise_int(get_input('offset', null))) {
- $options['offset'] = $offset;
- }
+ $options['count'] = FALSE;
+ $entities = $getter($options);
- $options['full_view'] = $fullview;
- $options['view_type_toggle'] = $viewtypetoggle;
- $options['pagination'] = $pagination;
+ $options['count'] = $count;
- return elgg_list_entities($options);
+ return $viewer($entities, $options);
}
/**
- * 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)
- * @param true|false $viewtypetoggle Whether or not to allow gallery view (default: true)
- * @param true|false $pagination Whether to display pagination (default: true)
- * @return string A viewable list of entities
+ * Returns a list of months in which entities were updated or created.
+ *
+ * @tip Use this to generate a list of archives by month for when entities were added or updated.
+ *
+ * @todo document how to pass in array for $subtype
+ *
+ * @warning Months are returned in the form YYYYMM.
+ *
+ * @param string $type The type of entity
+ * @param string $subtype The subtype of entity
+ * @param int $container_guid The container GUID that the entities belong to
+ * @param int $site_guid The site GUID
+ * @param string $order_by Order_by SQL order by clause
+ *
+ * @return array|false Either an array months as YYYYMM, or false on failure
*/
-function list_entities_groups($subtype = "", $owner_guid = 0, $container_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = true, $pagination = 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, $viewtypetoggle, $pagination);
-}
+function get_entity_dates($type = '', $subtype = '', $container_guid = 0, $site_guid = 0,
+$order_by = 'time_created') {
-/**
- * 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
- * @param str order_by SQL order by clause
- * @return array|false Either an array of timestamps, or false on failure
- */
-function get_entity_dates($type = '', $subtype = '', $container_guid = 0, $site_guid = 0, $order_by = 'time_created') {
global $CONFIG;
$site_guid = (int) $site_guid;
@@ -2432,16 +1537,19 @@ function get_entity_dates($type = '', $subtype = '', $container_guid = 0, $site_
if (is_array($subtype)) {
$tempwhere = "";
if (sizeof($subtype)) {
- foreach($subtype as $typekey => $subtypearray) {
- foreach($subtypearray as $subtypeval) {
+ foreach ($subtype as $typekey => $subtypearray) {
+ foreach ($subtypearray as $subtypeval) {
$typekey = sanitise_string($typekey);
if (!empty($subtypeval)) {
- if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval))
+ if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) {
return false;
+ }
} else {
$subtypeval = 0;
}
- if (!empty($tempwhere)) $tempwhere .= " or ";
+ if (!empty($tempwhere)) {
+ $tempwhere .= " or ";
+ }
$tempwhere .= "(type = '{$typekey}' and subtype = {$subtypeval})";
}
}
@@ -2461,10 +1569,10 @@ function get_entity_dates($type = '', $subtype = '', $container_guid = 0, $site_
if ($container_guid !== 0) {
if (is_array($container_guid)) {
- foreach($container_guid as $key => $val) {
+ foreach ($container_guid as $key => $val) {
$container_guid[$key] = (int) $val;
}
- $where[] = "container_guid in (" . implode(",",$container_guid) . ")";
+ $where[] = "container_guid in (" . implode(",", $container_guid) . ")";
} else {
$container_guid = (int) $container_guid;
$where[] = "container_guid = {$container_guid}";
@@ -2487,7 +1595,7 @@ function get_entity_dates($type = '', $subtype = '', $container_guid = 0, $site_
$sql .= "1=1 ORDER BY $order_by";
if ($result = get_data($sql)) {
$endresult = array();
- foreach($result as $res) {
+ foreach ($result as $res) {
$endresult[] = $res->yearmonth;
}
return $endresult;
@@ -2496,10 +1604,26 @@ function get_entity_dates($type = '', $subtype = '', $container_guid = 0, $site_
}
/**
- * Disable an entity but not delete it.
+ * Disable an entity.
*
- * @param int $guid The guid
- * @param string $reason Optional reason
+ * Disabled entities do not show up in list or elgg_get_entity()
+ * calls, but still exist in the database.
+ *
+ * Entities are disabled by setting disabled = yes in the
+ * entities table.
+ *
+ * You can ignore the disabled field by using {@link access_show_hidden_entities()}.
+ *
+ * @note Use ElggEntity::disable() instead.
+ *
+ * @param int $guid The guid
+ * @param string $reason Optional reason
+ * @param bool $recursive Recursively disable all entities owned or contained by $guid?
+ *
+ * @return bool
+ * @see access_show_hidden_entities()
+ * @link http://docs.elgg.org/Entities
+ * @access private
*/
function disable_entity($guid, $reason = "", $recursive = true) {
global $CONFIG;
@@ -2508,35 +1632,41 @@ function disable_entity($guid, $reason = "", $recursive = true) {
$reason = sanitise_string($reason);
if ($entity = get_entity($guid)) {
- if (trigger_elgg_event('disable',$entity->type,$entity)) {
+ if (elgg_trigger_event('disable', $entity->type, $entity)) {
if ($entity->canEdit()) {
if ($reason) {
- create_metadata($guid, 'disable_reason', $reason,'', 0, ACCESS_PUBLIC);
+ 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');
+ $hidden = access_get_show_hidden_status();
+ access_show_hidden_entities(true);
+ $ia = elgg_set_ignore_access(true);
+
+ $sub_entities = get_data("SELECT * FROM {$CONFIG->dbprefix}entities
+ WHERE (
+ container_guid = $guid
+ OR owner_guid = $guid
+ OR site_guid = $guid
+ ) AND enabled='yes'", 'entity_row_to_elggstar');
if ($sub_entities) {
foreach ($sub_entities as $e) {
+ add_entity_relationship($e->guid, 'disabled_with', $entity->guid);
$e->disable($reason);
}
}
-
- $__RECURSIVE_DELETE_TOKEN = null;
+ access_show_hidden_entities($hidden);
+ elgg_set_ignore_access($ia);
}
+ $entity->disableMetadata();
+ $entity->disableAnnotations();
+ _elgg_invalidate_cache_for_entity($guid);
+
$res = update_data("UPDATE {$CONFIG->dbprefix}entities
- set enabled='no'
- where guid={$guid}");
+ SET enabled = 'no'
+ WHERE guid = $guid");
return $res;
}
@@ -2546,86 +1676,155 @@ function disable_entity($guid, $reason = "", $recursive = true) {
}
/**
- * Enable an entity again.
+ * Enable an entity.
+ *
+ * @warning In order to enable an entity, you must first use
+ * {@link access_show_hidden_entities()}.
*
- * @param int $guid
+ * @param int $guid GUID of entity to enable
+ * @param bool $recursive Recursively enable all entities disabled with the entity?
+ *
+ * @return bool
*/
-function enable_entity($guid) {
+function enable_entity($guid, $recursive = true) {
global $CONFIG;
$guid = (int)$guid;
// Override access only visible entities
- $access_status = access_get_show_hidden_status();
+ $old_access_status = access_get_show_hidden_status();
access_show_hidden_entities(true);
+ $result = false;
if ($entity = get_entity($guid)) {
- if (trigger_elgg_event('enable',$entity->type,$entity)) {
+ if (elgg_trigger_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');
+ SET enabled = 'yes'
+ WHERE guid = $guid");
+
+ $entity->deleteMetadata('disable_reason');
+ $entity->enableMetadata();
+ $entity->enableAnnotations();
- return $result;
+ if ($recursive) {
+ $disabled_with_it = elgg_get_entities_from_relationship(array(
+ 'relationship' => 'disabled_with',
+ 'relationship_guid' => $entity->guid,
+ 'inverse_relationship' => true,
+ 'limit' => 0,
+ ));
+
+ foreach ($disabled_with_it as $e) {
+ $e->enable();
+ remove_entity_relationship($e->guid, 'disabled_with', $entity->guid);
+ }
+ }
}
}
}
- access_show_hidden_entities($access_status);
- return false;
+ access_show_hidden_entities($old_access_status);
+ return $result;
}
/**
- * Delete a given entity.
+ * Delete an entity.
+ *
+ * Removes an entity and its metadata, annotations, relationships, river entries,
+ * and private data.
+ *
+ * Optionally can remove entities contained and owned by $guid.
+ *
+ * @tip Use ElggEntity::delete() instead.
*
- * @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.
+ * @warning If deleting recursively, this bypasses ownership of items contained by
+ * the entity. That means that if the container_guid = $guid, the item will be deleted
+ * regardless of who owns it.
+ *
+ * @param int $guid The guid of the entity to delete
+ * @param bool $recursive If true (default) then all entities which are
+ * owned or contained by $guid will also be deleted.
+ *
+ * @return bool
+ * @access private
*/
function delete_entity($guid, $recursive = true) {
global $CONFIG, $ENTITY_CACHE;
$guid = (int)$guid;
if ($entity = get_entity($guid)) {
- if (trigger_elgg_event('delete', $entity->type, $entity)) {
+ if (elgg_trigger_event('delete', $entity->type, $entity)) {
if ($entity->canEdit()) {
// delete cache
if (isset($ENTITY_CACHE[$guid])) {
- invalidate_cache_for_entity($guid);
+ _elgg_invalidate_cache_for_entity($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');
+ }
+ if ($newentity_cache) {
+ $newentity_cache->delete($guid);
}
// Delete contained owned and otherwise releated objects (depth first)
if ($recursive) {
- // Temporary token overriding access controls TODO: Do this better.
+ // 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 = md5(elgg_get_logged_in_user_guid());
+
+ $entity_disable_override = access_get_show_hidden_status();
+ access_show_hidden_entities(true);
+ $ia = elgg_set_ignore_access(true);
+
+ // @todo there was logic in the original code that ignored
+ // entities with owner or container guids of themselves.
+ // this should probably be prevented in ElggEntity instead of checked for here
+ $options = array(
+ 'wheres' => array(
+ "((container_guid = $guid OR owner_guid = $guid OR site_guid = $guid)"
+ . " AND guid != $guid)"
+ ),
+ 'limit' => 0
+ );
+
+ $batch = new ElggBatch('elgg_get_entities', $options);
+ $batch->setIncrementOffset(false);
+
+ foreach ($batch as $e) {
+ $e->delete(true);
}
+ access_show_hidden_entities($entity_disable_override);
$__RECURSIVE_DELETE_TOKEN = null;
+ elgg_set_ignore_access($ia);
}
+ $entity_disable_override = access_get_show_hidden_status();
+ access_show_hidden_entities(true);
+ $ia = elgg_set_ignore_access(true);
+
// Now delete the entity itself
- $entity->clearMetadata();
- $entity->clearAnnotations();
- $entity->clearRelationships();
- remove_from_river_by_subject($guid);
- remove_from_river_by_object($guid);
+ $entity->deleteMetadata();
+ $entity->deleteOwnedMetadata();
+ $entity->deleteAnnotations();
+ $entity->deleteOwnedAnnotations();
+ $entity->deleteRelationships();
+
+ access_show_hidden_entities($entity_disable_override);
+ elgg_set_ignore_access($ia);
+
+ elgg_delete_river(array('subject_guid' => $guid));
+ elgg_delete_river(array('object_guid' => $guid));
remove_all_private_settings($guid);
+
$res = delete_data("DELETE from {$CONFIG->dbprefix}entities where guid={$guid}");
if ($res) {
$sub_table = "";
@@ -2651,7 +1850,7 @@ function delete_entity($guid, $recursive = true) {
}
}
- return $res;
+ return (bool)$res;
}
}
}
@@ -2660,28 +1859,18 @@ function delete_entity($guid, $recursive = true) {
}
/**
- * 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.
- *
- * @deprecated 1.7. This is a dangerous function as it defaults to deleting everything.
- * @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) {
- elgg_deprecated_notice('delete_entities() was deprecated because no one should use it.', 1.7);
- 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
+ * Exports attributes generated on the fly (volatile) about an entity.
+ *
+ * @param string $hook volatile
+ * @param string $entity_type metadata
+ * @param string $returnvalue Return value from previous hook
+ * @param array $params The parameters, passed 'guid' and 'varname'
+ *
+ * @return ElggMetadata|null
+ * @elgg_plugin_hook_handler volatile metadata
+ * @todo investigate more.
+ * @access private
+ * @todo document
*/
function volatile_data_export_plugin_hook($hook, $entity_type, $returnvalue, $params) {
$guid = (int)$params['guid'];
@@ -2710,7 +1899,20 @@ function volatile_data_export_plugin_hook($hook, $entity_type, $returnvalue, $pa
}
/**
- * Handler called by trigger_plugin_hook on the "export" event.
+ * Exports all attributes of an entity.
+ *
+ * @warning Only exports fields in the entity and entity type tables.
+ *
+ * @param string $hook export
+ * @param string $entity_type all
+ * @param mixed $returnvalue Previous hook return value
+ * @param array $params Parameters
+ *
+ * @elgg_event_handler export all
+ * @return mixed
+ * @access private
+ *
+ * @throws InvalidParameterException|InvalidClassException
*/
function export_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
// Sanity check values
@@ -2727,7 +1929,8 @@ function export_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
// Get the entity
$entity = get_entity($guid);
if (!($entity instanceof ElggEntity)) {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class()));
+ $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class()));
+ throw new InvalidClassException($msg);
}
$export = $entity->export();
@@ -2744,10 +1947,16 @@ function export_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
}
/**
- * Utility function used by import_entity_plugin_hook() to process an ODDEntity into an unsaved ElggEntity.
+ * 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.
+ * @todo Remove this.
+ * @access private
+ *
+ * @throws ClassException|InstallationException|ImportException
*/
function oddentity_to_elggentity(ODDEntity $element) {
$class = $element->getAttribute('class');
@@ -2759,18 +1968,18 @@ function oddentity_to_elggentity(ODDEntity $element) {
if (!$tmp) {
// Construct new class with owner from session
$classname = get_subtype_class($class, $subclass);
- if ($classname!="") {
+ if ($classname) {
if (class_exists($classname)) {
$tmp = new $classname();
if (!($tmp instanceof ElggEntity)) {
- throw new ClassException(sprintf(elgg_echo('ClassException:ClassnameNotClass', $classname, get_class())));
+ $msg = elgg_echo('ClassException:ClassnameNotClass', array($classname, get_class()));
+ throw new ClassException($msg);
}
+ } else {
+ error_log(elgg_echo('ClassNotFoundException:MissingClass', array($classname)));
}
- else
- error_log(sprintf(elgg_echo('ClassNotFoundException:MissingClass'), $classname));
- }
- else {
+ } else {
switch ($class) {
case 'object' :
$tmp = new ElggObject($row);
@@ -2785,14 +1994,16 @@ function oddentity_to_elggentity(ODDEntity $element) {
$tmp = new ElggSite($row);
break;
default:
- throw new InstallationException(sprintf(elgg_echo('InstallationException:TypeNotSupported'), $class));
+ $msg = elgg_echo('InstallationException:TypeNotSupported', array($class));
+ throw new InstallationException($msg);
}
}
}
if ($tmp) {
if (!$tmp->import($element)) {
- throw new ImportException(sprintf(elgg_echo('ImportException:ImportFailed'), $element->getAttribute('uuid')));
+ $msg = elgg_echo('ImportException:ImportFailed', array($element->getAttribute('uuid')));
+ throw new ImportException($msg);
}
return $tmp;
@@ -2803,13 +2014,27 @@ function oddentity_to_elggentity(ODDEntity $element) {
/**
* 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.
+ *
+ * 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.
+ *
+ * @param string $hook import
+ * @param string $entity_type all
+ * @param mixed $returnvalue Value from previous hook
+ * @param mixed $params Array of params
+ *
+ * @return mixed
+ * @elgg_plugin_hook_handler import all
+ * @todo document
+ * @access private
+ *
+ * @throws ImportException
*/
function import_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
$element = $params['element'];
- $tmp = NULL;
+ $tmp = null;
if ($element instanceof ODDEntity) {
$tmp = oddentity_to_elggentity($element);
@@ -2817,7 +2042,8 @@ function import_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
if ($tmp) {
// Make sure its saved
if (!$tmp->save()) {
- throw new ImportException(sprintf(elgg_echo('ImportException:ProblemSaving'), $element->getAttribute('uuid')));
+ $msg = elgg_echo('ImportException:ProblemSaving', array($element->getAttribute('uuid')));
+ throw new ImportException($msg);
}
// Belts and braces
@@ -2834,32 +2060,34 @@ function import_entity_plugin_hook($hook, $entity_type, $returnvalue, $params) {
}
/**
- * Determines whether or not the specified user can edit the specified entity.
+ * Returns if $user_guid is able to edit $entity_guid.
+ *
+ * @tip Can be overridden by by registering for the permissions_check
+ * plugin hook.
*
- * This is extendible by registering a plugin hook taking in the parameters 'entity' and 'user',
- * which are the entity and user entities respectively
+ * @warning If a $user_guid is not passed it will default to the logged in user.
*
- * @see register_plugin_hook
+ * @tip Use ElggEntity::canEdit() instead.
*
* @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.
+ * @param int $user_guid The GUID of the user
+ *
+ * @return bool
+ * @link http://docs.elgg.org/Entities/AccessControl
*/
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();
+ $user = elgg_get_logged_in_user_entity();
}
+ $return = false;
if ($entity = get_entity($entity_guid)) {
- $return = false;
// Test user if possible - should default to false unless a plugin hook says otherwise
if ($user) {
- if ($entity->getOwner() == $user->getGUID()) {
+ if ($entity->getOwnerGUID() == $user->getGUID()) {
$return = true;
}
if ($entity->container_guid == $user->getGUID()) {
@@ -2874,120 +2102,62 @@ function can_edit_entity($entity_guid, $user_guid = 0) {
}
}
}
+ }
- return trigger_plugin_hook('permissions_check', $entity->type,
+ return elgg_trigger_plugin_hook('permissions_check', $entity->type,
array('entity' => $entity, 'user' => $user), $return);
-
- } else {
- return false;
- }
}
/**
- * Determines whether or not the specified user can edit metadata on the specified entity.
+ * Returns if $user_guid can edit the metadata on $entity_guid.
*
- * This is extendible by registering a plugin hook taking in the parameters 'entity' and 'user',
- * which are the entity and user entities respectively
+ * @tip Can be overridden by by registering for the permissions_check:metadata
+ * plugin hook.
*
- * @see register_plugin_hook
+ * @warning If a $user_guid isn't specified, the currently logged in user is used.
*
- * @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.
+ * @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 bool
+ * @see elgg_register_plugin_hook_handler()
*/
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) {
+ if ($metadata && ($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);
+ if ($user_guid) {
+ $user = get_entity($user_guid);
+ } else {
+ $user = elgg_get_logged_in_user_entity();
+ }
+
+ $params = array('entity' => $entity, 'user' => $user, 'metadata' => $metadata);
+ $return = elgg_trigger_plugin_hook('permissions_check:metadata', $entity->type, $params, $return);
return $return;
} else {
return false;
}
}
-
/**
- * Get the icon for an entity
+ * Returns the URL 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";
- }
-
- return $url;
-}
-
-/**
- * Gets the URL for an entity, given a particular GUID
+ * @tip Can be overridden with {@link register_entity_url_handler()}.
*
* @param int $entity_guid The GUID of the entity
+ *
* @return string The URL of the entity
+ * @see register_entity_url_handler()
*/
function get_entity_url($entity_guid) {
global $CONFIG;
@@ -2996,27 +2166,27 @@ function get_entity_url($entity_guid) {
$url = "";
if (isset($CONFIG->entity_url_handler[$entity->getType()][$entity->getSubType()])) {
- $function = $CONFIG->entity_url_handler[$entity->getType()][$entity->getSubType()];
+ $function = $CONFIG->entity_url_handler[$entity->getType()][$entity->getSubType()];
if (is_callable($function)) {
- $url = $function($entity);
+ $url = call_user_func($function, $entity);
}
} elseif (isset($CONFIG->entity_url_handler[$entity->getType()]['all'])) {
- $function = $CONFIG->entity_url_handler[$entity->getType()]['all'];
+ $function = $CONFIG->entity_url_handler[$entity->getType()]['all'];
if (is_callable($function)) {
- $url = $function($entity);
+ $url = call_user_func($function, $entity);
}
} elseif (isset($CONFIG->entity_url_handler['all']['all'])) {
- $function = $CONFIG->entity_url_handler['all']['all'];
+ $function = $CONFIG->entity_url_handler['all']['all'];
if (is_callable($function)) {
- $url = $function($entity);
+ $url = call_user_func($function, $entity);
}
}
if ($url == "") {
- $url = $CONFIG->url . "pg/view/" . $entity_guid;
+ $url = "view/" . $entity_guid;
}
- return $url;
+ return elgg_normalize_url($url);
}
return false;
@@ -3025,15 +2195,19 @@ function get_entity_url($entity_guid) {
/**
* 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_type The entity type
* @param string $entity_subtype The entity subtype
- * @return true|false Depending on success
+ * @param string $function_name The function to register
+ *
+ * @return bool Depending on success
+ * @see get_entity_url()
+ * @see ElggEntity::getURL()
+ * @since 1.8.0
*/
-function register_entity_url_handler($function_name, $entity_type = "all", $entity_subtype = "all") {
+function elgg_register_entity_url_handler($entity_type, $entity_subtype, $function_name) {
global $CONFIG;
- if (!is_callable($function_name)) {
+ if (!is_callable($function_name, true)) {
return false;
}
@@ -3051,88 +2225,101 @@ function register_entity_url_handler($function_name, $entity_type = "all", $enti
}
/**
- * 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
+ * Registers an entity type and subtype as a public-facing entity that should
+ * be shown in search and by {@link elgg_list_registered_entities()}.
+ *
+ * @warning Entities that aren't registered here will not show up in search.
+ *
+ * @tip Add a language string item:type:subtype to make sure the items are display properly.
+ *
+ * @param string $type The type of entity (object, site, user, group)
+ * @param string $subtype The subtype to register (may be blank)
+ *
+ * @return bool Depending on success
+ * @see get_registered_entity_types()
+ * @link http://docs.elgg.org/Search
+ * @link http://docs.elgg.org/Tutorials/Search
*/
-function default_entity_icon_hook($hook, $entity_type, $returnvalue, $params) {
+function elgg_register_entity_type($type, $subtype = null) {
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";
+ $type = strtolower($type);
+ if (!in_array($type, $CONFIG->entity_types)) {
+ return FALSE;
+ }
- if (!@file_exists($CONFIG->path . $url)) {
- $url = "views/$viewtype/graphics/icons/$type/default/$size.png";
- }
+ if (!isset($CONFIG->registered_entities)) {
+ $CONFIG->registered_entities = array();
+ }
- if(!@file_exists($CONFIG->path . $url)) {
- $url = "views/$viewtype/graphics/icons/default/$size.png";
- }
+ if (!isset($CONFIG->registered_entities[$type])) {
+ $CONFIG->registered_entities[$type] = array();
+ }
- if (@file_exists($CONFIG->path . $url)) {
- return $CONFIG->url . $url;
- }
+ if ($subtype) {
+ $CONFIG->registered_entities[$type][] = $subtype;
}
+
+ return TRUE;
}
/**
- * 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.
+ * Unregisters an entity type and subtype as a public-facing entity.
+ *
+ * @warning With a blank subtype, it unregisters that entity type including
+ * all subtypes. This must be called after all subtypes have been registered.
*
- * @param string $type The type of entity (object, site, user, group)
+ * @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
+ *
+ * @return bool Depending on success
+ * @see elgg_register_entity_type()
*/
-function register_entity_type($type, $subtype) {
+function unregister_entity_type($type, $subtype) {
global $CONFIG;
$type = strtolower($type);
- if (!in_array($type, array('object','site','group','user'))) {
- return false;
+ if (!in_array($type, $CONFIG->entity_types)) {
+ return FALSE;
}
if (!isset($CONFIG->registered_entities)) {
- $CONFIG->registered_entities = array();
+ return FALSE;
}
if (!isset($CONFIG->registered_entities[$type])) {
- $CONFIG->registered_entities[$type] = array();
+ return FALSE;
}
if ($subtype) {
- $CONFIG->registered_entities[$type][] = $subtype;
+ if (in_array($subtype, $CONFIG->registered_entities[$type])) {
+ $key = array_search($subtype, $CONFIG->registered_entities[$type]);
+ unset($CONFIG->registered_entities[$type][$key]);
+ } else {
+ return FALSE;
+ }
+ } else {
+ unset($CONFIG->registered_entities[$type]);
}
- return true;
+ 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
+ * @see elgg_register_entity_type()
*/
-function get_registered_entity_types($type = '') {
+function get_registered_entity_types($type = null) {
global $CONFIG;
if (!isset($CONFIG->registered_entities)) {
return false;
}
- if (!empty($type)) {
+ if ($type) {
$type = strtolower($type);
}
if (!empty($type) && empty($CONFIG->registered_entities[$type])) {
@@ -3147,75 +2334,51 @@ function get_registered_entity_types($type = '') {
}
/**
- * Determines whether or not the specified entity type and subtype have been registered in the system
+ * Returns if the entity type and subtype have been registered with {@see elgg_register_entity_type()}.
*
- * @param string $type The type of entity (object, site, user, group)
+ * @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
+ *
+ * @return bool Depending on whether or not the type has been registered
*/
-function is_registered_entity_type($type, $subtype) {
+function is_registered_entity_type($type, $subtype = null) {
global $CONFIG;
if (!isset($CONFIG->registered_entities)) {
return false;
}
+
$type = strtolower($type);
- if (empty($CONFIG->registered_entities[$type])) {
+
+ // @todo registering a subtype implicitly registers the type.
+ // see #2684
+ if (!isset($CONFIG->registered_entities[$type])) {
return false;
}
- if (in_array($subtype, $CONFIG->registered_entities[$type])) {
- return true;
- }
+ if ($subtype && !in_array($subtype, $CONFIG->registered_entities[$type])) {
+ return false;
+ }
+ return true;
}
/**
* Page handler for generic entities view system
*
* @param array $page Page elements from pain page handler
+ *
+ * @return bool
+ * @elgg_page_handler view
+ * @access private
*/
function entities_page_handler($page) {
if (isset($page[0])) {
global $CONFIG;
- set_input('guid',$page[0]);
- include($CONFIG->path . "entities/index.php");
- }
-}
-
-/**
- * @deprecated 1.7. Use elgg_list_registered_entities().
- * @param $owner_guid
- * @param $limit
- * @param $fullview
- * @param $viewtypetoggle
- * @param $allowedtypes
- * @return unknown_type
- */
-function list_registered_entities($owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $allowedtypes = true) {
- elgg_deprecated_notice('list_registered_entities() was deprecated by elgg_list_registered_entities().', 1.7);
-
- $options = array();
-
- // don't want to send anything if not being used.
- if ($owner_guid) {
- $options['owner_guid'] = $owner_guid;
- }
-
- if ($limit) {
- $options['limit'] = $limit;
- }
-
- if ($allowedtypes) {
- $options['allowed_types'] = $allowedtypes;
+ set_input('guid', $page[0]);
+ include($CONFIG->path . "pages/entities/index.php");
+ return true;
}
-
- // need to send because might be BOOL
- $options['full_view'] = $fullview;
- $options['view_type_toggle'] = $viewtypetoggle;
-
- $options['offset'] = get_input('offset', 0);
-
- return elgg_list_registered_entities($options);
+ return false;
}
/**
@@ -3227,473 +2390,93 @@ function list_registered_entities($owner_guid = 0, $limit = 10, $fullview = true
*
* full_view => BOOL Display full view entities
*
- * view_type_toggle => BOOL Display gallery / list switch
+ * list_type_toggle => BOOL Display gallery / list switch
*
* allowed_types => TRUE|ARRAY True to show all types or an array of valid types.
*
* pagination => BOOL Display pagination links
*
* @return string A viewable list of entities
+ * @since 1.7.0
*/
-function elgg_list_registered_entities($options) {
+function elgg_list_registered_entities(array $options = array()) {
+ global $autofeed;
+ $autofeed = true;
+
$defaults = array(
'full_view' => TRUE,
'allowed_types' => TRUE,
- 'view_type_toggle' => FALSE,
+ 'list_type_toggle' => FALSE,
'pagination' => TRUE,
- 'offset' => 0
+ 'offset' => 0,
+ 'types' => array(),
+ 'type_subtype_pairs' => array()
);
$options = array_merge($defaults, $options);
- $typearray = array();
-
- if ($object_types = get_registered_entity_types()) {
- foreach($object_types as $object_type => $subtype_array) {
- if (in_array($object_type, $options['allowed_types']) || $options['allowed_types'] === TRUE) {
- $typearray[$object_type] = array();
-
- if (is_array($subtype_array) && count($subtype_array)) {
- foreach ($subtype_array as $subtype) {
- $typearray[$object_type][] = $subtype;
- }
- }
- }
- }
- }
-
- $options['type_subtype_pairs'] = $typearray;
-
- $count = elgg_get_entities(array_merge(array('count' => TRUE), $options));
- $entities = elgg_get_entities($options);
-
- return elgg_view_entity_list($entities, $count, $options['offset'],
- $options['limit'], $options['full_view'], $options['view_type_toggle'], $options['pagination']);
-}
-
-/**
- * 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;
+ //backwards compatibility
+ if (isset($options['view_type_toggle'])) {
+ $options['list_type_toggle'] = $options['view_type_toggle'];
}
- $where = array();
+ $types = get_registered_entity_types();
- if (is_array($type)) {
- $tempwhere = "";
- if (sizeof($type)) {
- foreach($type 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;
- }
- if (!empty($tempwhere)) $tempwhere .= " or ";
- $tempwhere .= "(e.type = '{$typekey}' and e.subtype = {$subtypeval})";
+ foreach ($types as $type => $subtype_array) {
+ if (in_array($type, $options['allowed_types']) || $options['allowed_types'] === TRUE) {
+ // you must explicitly register types to show up in here and in search for objects
+ if ($type == 'object') {
+ if (is_array($subtype_array) && count($subtype_array)) {
+ $options['type_subtype_pairs'][$type] = $subtype_array;
}
- }
- }
- 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 ($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);
- if (!empty($subtypeval)) {
- if (!$subtypeval = (int) get_subtype_id($typekey, $subtypeval)) {
- return false;
- }
- } else {
- $subtypeval = 0;
- }
- if (!empty($tempwhere)) $tempwhere .= " or ";
- $tempwhere .= "(e.type = '{$typekey}' and e.subtype = {$subtypeval})";
+ } else {
+ if (is_array($subtype_array) && count($subtype_array)) {
+ $options['type_subtype_pairs'][$type] = $subtype_array;
+ } else {
+ $options['type_subtype_pairs'][$type] = ELGG_ENTITIES_ANY_VALUE;
}
}
}
- 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 ($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++;
- }
- }
-
- 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 ";
- }
-
- // 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;
+ if (!empty($options['type_subtype_pairs'])) {
+ $count = elgg_get_entities(array_merge(array('count' => TRUE), $options));
+ $entities = elgg_get_entities($options);
} else {
- $total = get_data_row($query);
- return $total->total;
+ $count = 0;
+ $entities = array();
}
-}
-
-/**
- * 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;
- }
- return false;
+ $options['count'] = $count;
+ return elgg_view_entity_list($entities, $options);
}
/**
- * 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;
-}
-
-/**
- * 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}");
-}
-
-/**
- * Deletes all private settings for an entity.
+ * Checks if $entity is an ElggEntity and optionally for type and subtype.
*
- * @param int $entity_guid The Entity GUID
- * @return true|false depending on success
+ * @tip Use this function in actions and views to check that you are dealing
+ * with the correct type of entity.
*
- */
-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.
+ * @param mixed $entity Entity
+ * @param string $type Entity type
+ * @param string $subtype Entity subtype
+ * @param string $class Class name
*
* @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;
- }
-
- // consult next function
- return NULL;
-}
-
-/**
- * Checks if $entity is an ElggEntity and optionally for type and subtype.
- *
- * @param $entity
- * @param $type
- * @param $subtype
- * @return Bool
- * @since 1.8
+ * @since 1.8.0
*/
function elgg_instanceof($entity, $type = NULL, $subtype = NULL, $class = NULL) {
$return = ($entity instanceof ElggEntity);
if ($type) {
+ /* @var ElggEntity $entity */
$return = $return && ($entity->getType() == $type);
}
if ($subtype) {
$return = $return && ($entity->getSubtype() == $subtype);
}
-
+
if ($class) {
$return = $return && ($entity instanceof $class);
}
@@ -3701,25 +2484,32 @@ function elgg_instanceof($entity, $type = NULL, $subtype = NULL, $class = NULL)
return $return;
}
-
/**
- * Update last_action on the given entity.
+ * Update the last_action column in the entities table for $guid.
+ *
+ * @warning This is different to time_updated. Time_updated is automatically set,
+ * while last_action is only set when explicitly called.
*
- * @param int $guid Entity annotation|relationship action carried out on
+ * @param int $guid Entity annotation|relationship action carried out on
* @param int $posted Timestamp of last action
- **/
-function update_entity_last_action($guid, $posted = NULL){
+ *
+ * @return bool
+ * @access private
+ */
+function update_entity_last_action($guid, $posted = NULL) {
global $CONFIG;
$guid = (int)$guid;
+ $posted = (int)$posted;
if (!$posted) {
$posted = time();
}
- if ($guid){
+ if ($guid) {
//now add to the river updated table
- $query = update_data("UPDATE {$CONFIG->dbprefix}entities SET last_action = {$posted} WHERE guid = {$guid}");
- if ($query) {
+ $query = "UPDATE {$CONFIG->dbprefix}entities SET last_action = {$posted} WHERE guid = {$guid}";
+ $result = update_data($query);
+ if ($result) {
return TRUE;
} else {
return FALSE;
@@ -3732,24 +2522,38 @@ function update_entity_last_action($guid, $posted = NULL){
/**
* 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
+ * @return void
+ * @elgg_plugin_hook_handler gc system
+ * @access private
*/
-function entities_gc($hook, $user, $returnvalue, $tag) {
+function entities_gc() {
global $CONFIG;
- $tables = array ('sites_entity', 'objects_entity', 'groups_entity', 'users_entity');
+ $tables = array(
+ 'site' => 'sites_entity',
+ 'object' => 'objects_entity',
+ 'group' => 'groups_entity',
+ 'user' => 'users_entity'
+ );
- foreach ($tables as $table) {
- delete_data("DELETE from {$CONFIG->dbprefix}{$table}
- where guid NOT IN (SELECT guid from {$CONFIG->dbprefix}entities)");
+ foreach ($tables as $type => $table) {
+ delete_data("DELETE FROM {$CONFIG->dbprefix}{$table}
+ WHERE guid NOT IN (SELECT guid FROM {$CONFIG->dbprefix}entities)");
+ delete_data("DELETE FROM {$CONFIG->dbprefix}entities
+ WHERE type = '$type' AND guid NOT IN (SELECT guid FROM {$CONFIG->dbprefix}{$table})");
}
}
/**
- * Runs unit tests for the entities object.
+ * Runs unit tests for the entity objects.
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
*/
function entities_test($hook, $type, $value, $params) {
global $CONFIG;
@@ -3758,33 +2562,29 @@ function entities_test($hook, $type, $value, $params) {
}
/**
- * Entities init function; establishes the page handler
+ * Entities init function; establishes the default entity page handler
*
+ * @return void
+ * @elgg_event_handler init system
+ * @access private
*/
function entities_init() {
- register_page_handler('view','entities_page_handler');
+ elgg_register_page_handler('view', 'entities_page_handler');
- register_plugin_hook('unit_test', 'system', 'entities_test');
+ elgg_register_plugin_hook_handler('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');
+ elgg_register_plugin_hook_handler('gc', 'system', 'entities_gc');
}
/** Register the import hook */
-register_plugin_hook("import", "all", "import_entity_plugin_hook", 0);
+elgg_register_plugin_hook_handler("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);
+elgg_register_plugin_hook_handler("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);
+elgg_register_plugin_hook_handler('volatile', 'metadata', 'volatile_data_export_plugin_hook');
/** Register init system event **/
-register_elgg_event_handler('init','system','entities_init');
+elgg_register_event_handler('init', 'system', 'entities_init');
+
diff --git a/engine/lib/exceptions.php b/engine/lib/exceptions.php
deleted file mode 100644
index ccf017062..000000000
--- a/engine/lib/exceptions.php
+++ /dev/null
@@ -1,161 +0,0 @@
-<?php
-/**
- * Exceptions.
- * Define some globally useful exception classes.
- *
- * @package Elgg
- * @subpackage Exceptions
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
- */
-
-// Top level //////////////////////////////////////////////////////////////////////////////
-
-/**
- * IOException
- * An IO Exception, throw when an IO Exception occurs. Subclass for specific IO Exceptions.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class IOException extends Exception {}
-
-/**
- * ClassException
- * A class Exception, throw when there is a class error.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class ClassException extends Exception {}
-
-/**
- * ConfigurationException
- * There is a configuration error
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class ConfigurationException extends Exception {}
-
-/**
- * SecurityException
- * An Security Exception, throw when a Security Exception occurs. Subclass for specific Security Execeptions (access problems etc)
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class SecurityException extends Exception {}
-
-/**
- * ClassNotFoundException
- * An database exception, throw when a database exception happens, subclass if more detail is needed.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class DatabaseException extends Exception {}
-
-/**
- * APIException
- * The API Exception class, thrown by the API layer when an API call has an issue.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class APIException extends Exception {}
-
-/**
- * CallException
- * An exception thrown when there is a problem calling something.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class CallException extends Exception {}
-
-/**
- * Data format exception
- * An exception thrown when there is a problem in the format of some data.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class DataFormatException extends Exception {}
-
-// Class exceptions ///////////////////////////////////////////////////////////////////////
-
-/**
- * InvalidClassException
- * An invalid class Exception, throw when a class is invalid.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class InvalidClassException extends ClassException {}
-
-/**
- * ClassNotFoundException
- * An Class not found Exception, throw when an class can not be found occurs.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class ClassNotFoundException extends ClassException {}
-
-// Configuration exceptions ///////////////////////////////////////////////////////////////
-
-/**
- * InstallationException
- * Thrown when there is a major problem with the installation.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class InstallationException extends ConfigurationException {}
-
-// Call exceptions ////////////////////////////////////////////////////////////////////////
-
-/**
- * NotImplementedException
- * Thrown when a method or function has not been implemented, primarily used in development... you should
- * not see these!
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class NotImplementedException extends CallException {}
-
-/**
- * InvalidParameterException
- * A parameter is invalid.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class InvalidParameterException extends CallException {}
-
-// Installation exception /////////////////////////////////////////////////////////////////
-
-/**
- * RegistrationException
- * Could not register a new user for whatever reason.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Exceptions
- */
-class RegistrationException extends InstallationException {} \ No newline at end of file
diff --git a/engine/lib/export.php b/engine/lib/export.php
index c541b583b..ecc894e63 100644
--- a/engine/lib/export.php
+++ b/engine/lib/export.php
@@ -2,71 +2,16 @@
/**
* Elgg Data import export functionality.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage DataModel.Export
*/
/**
- * Define an interface for all ODD exportable objects.
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- */
-interface Exportable {
- /**
- * This must take the contents of the object and convert it to exportable ODD
- * @return object or array of objects.
- */
- public function export();
-
- /**
- * Return a list of all fields that can be exported.
- * This should be used as the basis for the values returned by export()
- */
- public function getExportableValues();
-}
-
-/**
- * Define an interface for all ODD importable objects.
- * @author Curverider Ltd
- */
-interface Importable {
- /**
- * Accepts an array of data to import, this data is parsed from the XML produced by export.
- * The function should return the constructed object data, or NULL.
- *
- * @param ODD $data
- * @return bool
- * @throws ImportException if there was a critical error importing data.
- */
- public function import(ODD $data);
-}
-
-/**
- * Export exception
- *
- * @package Elgg
- * @subpackage Exceptions
- *
- */
-class ExportException extends DataFormatException {}
-
-/**
- * Import exception
- *
- * @package Elgg
- * @subpackage Exceptions
- */
-class ImportException extends DataFormatException {}
-
-/**
* Get a UUID from a given object.
*
- * @param $object The object either an ElggEntity, ElggRelationship or ElggExtender
- * @return the UUID or false
+ * @param mixed $object The object either an ElggEntity, ElggRelationship or ElggExtender
+ *
+ * @return string|false the UUID or false
*/
function get_uuid_from_object($object) {
if ($object instanceof ElggEntity) {
@@ -74,9 +19,9 @@ function get_uuid_from_object($object) {
} else if ($object instanceof ElggExtender) {
$type = $object->type;
if ($type == 'volatile') {
- $uuid = guid_to_uuid($object->entity_guid). $type . "/{$object->name}/";
+ $uuid = guid_to_uuid($object->entity_guid) . $type . "/{$object->name}/";
} else {
- $uuid = guid_to_uuid($object->entity_guid). $type . "/{$object->id}/";
+ $uuid = guid_to_uuid($object->entity_guid) . $type . "/{$object->id}/";
}
return $uuid;
@@ -91,22 +36,22 @@ function get_uuid_from_object($object) {
* Generate a UUID from a given GUID.
*
* @param int $guid The GUID of an object.
+ *
+ * @return string
*/
function guid_to_uuid($guid) {
- global $CONFIG;
-
- return $CONFIG->wwwroot . "export/opendd/$guid/";
+ return elgg_get_site_url() . "export/opendd/$guid/";
}
/**
* Test to see if a given uuid is for this domain, returning true if so.
- * @param $uuid
+ *
+ * @param string $uuid A unique ID
+ *
* @return bool
*/
function is_uuid_this_domain($uuid) {
- global $CONFIG;
-
- if (strpos($uuid, $CONFIG->wwwroot) === 0) {
+ if (strpos($uuid, elgg_get_site_url()) === 0) {
return true;
}
@@ -116,12 +61,15 @@ function is_uuid_this_domain($uuid) {
/**
* This function attempts to retrieve a previously imported entity via its UUID.
*
- * @param $uuid
+ * @param string $uuid A unique ID
+ *
+ * @return ElggEntity|false
*/
function get_entity_from_uuid($uuid) {
$uuid = sanitise_string($uuid);
- $entities = elgg_get_entities_from_metadata(array('metadata_name' => 'import_uuid', 'metadata_value' => $uuid));
+ $options = array('metadata_name' => 'import_uuid', 'metadata_value' => $uuid);
+ $entities = elgg_get_entities_from_metadata($options);
if ($entities) {
return $entities[0];
@@ -133,14 +81,17 @@ function get_entity_from_uuid($uuid) {
/**
* Tag a previously created guid with the uuid it was imported on.
*
- * @param int $guid
- * @param string $uuid
+ * @param int $guid A GUID
+ * @param string $uuid A Unique ID
+ *
+ * @return bool
*/
function add_uuid_to_guid($guid, $uuid) {
$guid = (int)$guid;
$uuid = sanitise_string($uuid);
- return create_metadata($guid, "import_uuid", $uuid);
+ $result = create_metadata($guid, "import_uuid", $uuid);
+ return (bool)$result;
}
@@ -154,40 +105,50 @@ $IMPORTED_OBJECT_COUNTER = 0;
* If nobody processes the top level element, the sub level elements are processed.
*
* @param ODD $odd The odd element to process
+ *
+ * @return bool
+ * @access private
*/
-function __process_element(ODD $odd) {
+function _process_element(ODD $odd) {
global $IMPORTED_DATA, $IMPORTED_OBJECT_COUNTER;
// See if anyone handles this element, return true if it is.
+ $to_be_serialised = null;
if ($odd) {
- $handled = trigger_plugin_hook("import", "all", array("element" => $odd), $to_be_serialised);
- }
+ $handled = elgg_trigger_plugin_hook("import", "all", array("element" => $odd), $to_be_serialised);
- // If not, then see if any of its sub elements are handled
- if ($handled) {
- // Increment validation counter
- $IMPORTED_OBJECT_COUNTER ++;
- // Return the constructed object
- $IMPORTED_DATA[] = $handled;
+ // If not, then see if any of its sub elements are handled
+ if ($handled) {
+ // Increment validation counter
+ $IMPORTED_OBJECT_COUNTER ++;
+ // Return the constructed object
+ $IMPORTED_DATA[] = $handled;
- return true;
+ return true;
+ }
}
return false;
}
+/**
+ * Exports an entity as an array
+ *
+ * @param int $guid Entity GUID
+ *
+ * @return array
+ * @throws ExportException
+ * @access private
+ */
function exportAsArray($guid) {
$guid = (int)$guid;
- // Initialise the array
- $to_be_serialised = array();
-
// Trigger a hook to
- $to_be_serialised = trigger_plugin_hook("export", "all", array("guid" => $guid), $to_be_serialised);
+ $to_be_serialised = elgg_trigger_plugin_hook("export", "all", array("guid" => $guid), array());
// Sanity check
- if ((!is_array($to_be_serialised)) || (count($to_be_serialised)==0)) {
- throw new ExportException(sprintf(elgg_echo('ExportException:NoSuchEntity'), $guid));
+ if ((!is_array($to_be_serialised)) || (count($to_be_serialised) == 0)) {
+ throw new ExportException(elgg_echo('ExportException:NoSuchEntity', array($guid)));
}
return $to_be_serialised;
@@ -201,10 +162,11 @@ function exportAsArray($guid) {
* This function makes use of the "serialise" plugin hook, which is passed an array to which plugins
* should add data to be serialised to.
*
- * @see ElggEntity for an example of its usage.
* @param int $guid The GUID.
- * @param ODDWrapperFactory $wrapper Optional wrapper permitting the export process to embed ODD in other document formats.
- * @return xml
+ *
+ * @return string XML
+ * @see ElggEntity for an example of its usage.
+ * @access private
*/
function export($guid) {
$odd = new ODDDocument(exportAsArray($guid));
@@ -216,9 +178,11 @@ function export($guid) {
* Import an XML serialisation of an object.
* This will make a best attempt at importing a given xml doc.
*
- * @param string $xml
+ * @param string $xml XML string
+ *
* @return bool
- * @throws Exception if there was a problem importing the data.
+ * @throws ImportException if there was a problem importing the data.
+ * @access private
*/
function import($xml) {
global $IMPORTED_DATA, $IMPORTED_OBJECT_COUNTER;
@@ -232,10 +196,10 @@ function import($xml) {
}
foreach ($document as $element) {
- __process_element($element);
+ _process_element($element);
}
- if ($IMPORTED_OBJECT_COUNTER!= count($IMPORTED_DATA)) {
+ if ($IMPORTED_OBJECT_COUNTER != count($IMPORTED_DATA)) {
throw new ImportException(elgg_echo('ImportException:NotAllImported'));
}
@@ -245,12 +209,15 @@ function import($xml) {
/**
* Register the OpenDD import action
+ *
+ * @return void
+ * @access private
*/
function export_init() {
global $CONFIG;
- register_action("import/opendd", false);
+ elgg_register_action("import/opendd");
}
// Register a startup event
-register_elgg_event_handler('init', 'system', 'export_init', 100);
+elgg_register_event_handler('init', 'system', 'export_init', 100);
diff --git a/engine/lib/extender.php b/engine/lib/extender.php
index cbcdd6eb7..8323bd3ce 100644
--- a/engine/lib/extender.php
+++ b/engine/lib/extender.php
@@ -3,274 +3,23 @@
* Elgg Entity Extender.
* This file contains ways of extending an Elgg entity in custom ways.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage DataModel.Extender
*/
/**
- * ElggExtender
- *
- * @author Curverider Ltd
- * @package Elgg
- * @subpackage Core
- */
-abstract class ElggExtender implements
- Exportable,
- Loggable, // Can events related to this object class be logged
- Iterator, // Override foreach behaviour
- ArrayAccess // Override for array access
-{
- /**
- * This contains the site's main properties (id, etc)
- * @var array
- */
- protected $attributes;
-
- /**
- * Get an attribute
- *
- * @param string $name
- * @return mixed
- */
- protected function get($name) {
- if (isset($this->attributes[$name])) {
- // Sanitise value if necessary
- if ($name=='value') {
- switch ($this->attributes['value_type']) {
- case 'integer' :
- return (int)$this->attributes['value'];
-
- //case 'tag' :
- //case 'file' :
- case 'text' :
- return ($this->attributes['value']);
-
- default :
- throw new InstallationException(sprintf(elgg_echo('InstallationException:TypeNotSupported'), $this->attributes['value_type']));
- }
- }
-
- return $this->attributes[$name];
- }
- return null;
- }
-
- /**
- * Set an attribute
- *
- * @param string $name
- * @param mixed $value
- * @param string $value_type
- * @return boolean
- */
- protected function set($name, $value, $value_type = "") {
- $this->attributes[$name] = $value;
- if ($name == 'value') {
- $this->attributes['value_type'] = detect_extender_valuetype($value, $value_type);
- }
-
- return true;
- }
-
- /**
- * Return the owner of this annotation.
- *
- * @return mixed
- */
- public function getOwner() {
- return $this->owner_guid;
- }
-
- /**
- * Return the owner entity
- *
- * @return mixed
- */
- public function getOwnerEntity() {
- return get_user($this->owner_guid);
- }
-
- /**
- * Returns the entity this is attached to
- *
- * @return ElggEntity The enttiy
- */
- public function getEntity() {
- return get_entity($this->entity_guid);
- }
-
- /**
- * Save this data to the appropriate database table.
- */
- abstract public function save();
-
- /**
- * Delete this data.
- */
- abstract public function delete();
-
- /**
- * Determines whether or not the specified user can edit this
- *
- * @param int $user_guid The GUID of the user (defaults to currently logged in user)
- * @return true|false
- */
- public function canEdit($user_guid = 0) {
- return can_edit_extender($this->id,$this->type,$user_guid);
- }
-
- /**
- * Return a url for this extender.
- *
- * @return string
- */
- public abstract function getURL();
-
- // EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * Return an array of fields which can be exported.
- */
- public function getExportableValues() {
- return array(
- 'id',
- 'entity_guid',
- 'name',
- 'value',
- 'value_type',
- 'owner_guid',
- 'type',
- );
- }
-
- /**
- * Export this object
- *
- * @return array
- */
- public function export() {
- $uuid = get_uuid_from_object($this);
-
- $meta = new ODDMetadata($uuid, guid_to_uuid($this->entity_guid), $this->attributes['name'], $this->attributes['value'], $this->attributes['type'], guid_to_uuid($this->owner_guid));
- $meta->setAttribute('published', date("r", $this->time_created));
-
- return $meta;
- }
-
- // 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->id;
- }
-
- /**
- * Return the class name of the object.
- */
- public function getClassName() {
- return get_class($this);
- }
-
- /**
- * Return the GUID of the owner of this object.
- */
- public function getObjectOwnerGUID() {
- return $this->owner_guid;
- }
-
- /**
- * Return a type of the object - eg. object, group, user, relationship, metadata, annotation etc
- */
- public function getType() {
- return $this->type;
- }
-
- /**
- * Return a subtype. For metadata & annotations this is the 'name' and
- * for relationship this is the relationship type.
- */
- public function getSubtype() {
- return $this->name;
- }
-
-
- // 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) ) {
- // Full unsetting is dangerious for our objects
- $this->attributes[$key] = "";
- }
- }
-
- function offsetExists($offset) {
- return array_key_exists($offset, $this->attributes);
- }
-}
-
-/**
* Detect the value_type for a given value.
* Currently this is very crude.
*
- * TODO: Make better!
+ * @todo Make better!
*
- * @param mixed $value
+ * @param mixed $value The value
* @param string $value_type If specified, overrides the detection.
+ *
* @return string
*/
function detect_extender_valuetype($value, $value_type = "") {
- if ($value_type!="") {
+ if ($value_type != "" && ($value_type == 'integer' || $value_type == 'text')) {
return $value_type;
}
@@ -287,12 +36,15 @@ function detect_extender_valuetype($value, $value_type = "") {
}
/**
- * Utility function used by import_extender_plugin_hook() to process an ODDMetaData and add it to an entity.
- * This function does not hit ->save() on the entity (this lets you construct in memory)
+ * Utility function used by import_extender_plugin_hook() to process
+ * an ODDMetaData and add it to an entity. This function does not
+ * hit ->save() on the entity (this lets you construct in memory)
*
- * @param ElggEntity The entity to add the data to.
+ * @param ElggEntity $entity The entity to add the data to.
* @param ODDMetaData $element The OpenDD element
+ *
* @return bool
+ * @access private
*/
function oddmetadata_to_elggextender(ElggEntity $entity, ODDMetaData $element) {
// Get the type of extender (metadata, type, attribute etc)
@@ -325,6 +77,17 @@ function oddmetadata_to_elggextender(ElggEntity $entity, ODDMetaData $element) {
/**
* Handler called by trigger_plugin_hook on the "import" event.
+ *
+ * @param string $hook volatile
+ * @param string $entity_type metadata
+ * @param string $returnvalue Return value from previous hook
+ * @param array $params The parameters
+ *
+ * @return null
+ * @elgg_plugin_hook_handler volatile metadata
+ * @todo investigate more.
+ * @throws ImportException
+ * @access private
*/
function import_extender_plugin_hook($hook, $entity_type, $returnvalue, $params) {
$element = $params['element'];
@@ -332,18 +95,21 @@ function import_extender_plugin_hook($hook, $entity_type, $returnvalue, $params)
$tmp = NULL;
if ($element instanceof ODDMetaData) {
+ /* @var ODDMetaData $element */
// Recall entity
$entity_uuid = $element->getAttribute('entity_uuid');
$entity = get_entity_from_uuid($entity_uuid);
if (!$entity) {
- throw new ImportException(sprintf(elgg_echo('ImportException:GUIDNotFound'), $entity_uuid));
+ throw new ImportException(elgg_echo('ImportException:GUIDNotFound', array($entity_uuid)));
}
oddmetadata_to_elggextender($entity, $element);
// Save
if (!$entity->save()) {
- throw new ImportException(sprintf(elgg_echo('ImportException:ProblemUpdatingMeta'), $attr_name, $entity_uuid));
+ $attr_name = $element->getAttribute('name');
+ $msg = elgg_echo('ImportException:ProblemUpdatingMeta', array($attr_name, $entity_uuid));
+ throw new ImportException($msg);
}
return true;
@@ -353,61 +119,72 @@ function import_extender_plugin_hook($hook, $entity_type, $returnvalue, $params)
/**
* Determines whether or not the specified user can edit the specified piece of extender
*
- * @param int $extender_id The ID of the piece of extender
- * @param string $type 'metadata' or 'annotation'
- * @param int $user_guid The GUID of the user
- * @return true|false
+ * @param int $extender_id The ID of the piece of extender
+ * @param string $type 'metadata' or 'annotation'
+ * @param int $user_guid The GUID of the user
+ *
+ * @return bool
*/
function can_edit_extender($extender_id, $type, $user_guid = 0) {
- if (!isloggedin()) {
- return false;
+ // @todo Since Elgg 1.0, Elgg has returned false from can_edit_extender()
+ // if no user was logged in. This breaks the access override. This is a
+ // temporary work around. This function needs to be rewritten in Elgg 1.9
+ if (!elgg_check_access_overrides($user_guid)) {
+ if (!elgg_is_logged_in()) {
+ return false;
+ }
}
$user_guid = (int)$user_guid;
- $user = get_entity($user_guid);
+ $user = get_user($user_guid);
if (!$user) {
- $user = get_loggedin_user();
+ $user = elgg_get_logged_in_user_entity();
+ $user_guid = elgg_get_logged_in_user_guid();
}
- $functionname = "get_{$type}";
+ $functionname = "elgg_get_{$type}_from_id";
if (is_callable($functionname)) {
- $extender = $functionname($extender_id);
+ $extender = call_user_func($functionname, $extender_id);
} else {
return false;
}
- if (!is_a($extender,"ElggExtender")) {
+ if (!($extender instanceof ElggExtender)) {
return false;
}
+ /* @var ElggExtender $extender */
// If the owner is the specified user, great! They can edit.
- if ($extender->getOwner() == $user->getGUID()) {
+ if ($extender->getOwnerGUID() == $user_guid) {
return true;
}
// If the user can edit the entity this is attached to, great! They can edit.
- if (can_edit_entity($extender->entity_guid,$user->getGUID())) {
+ if (can_edit_entity($extender->entity_guid, $user_guid)) {
return true;
}
- // Trigger plugin hooks
- return trigger_plugin_hook('permissions_check',$type,array('entity' => $entity, 'user' => $user),false);
+ // Trigger plugin hook - note that $user may be null
+ $params = array('entity' => $extender->getEntity(), 'user' => $user);
+ return elgg_trigger_plugin_hook('permissions_check', $type, $params, false);
}
/**
* Sets the URL handler for a particular extender type and name.
- * It is recommended that you do not call this directly, instead use one of the wrapper functions in the
- * subtype files.
+ * It is recommended that you do not call this directly, instead use
+ * one of the wrapper functions such as elgg_register_annotation_url_handler().
*
- * @param string $function_name The function to register
- * @param string $extender_type Extender type
+ * @param string $extender_type Extender type ('annotation', 'metadata')
* @param string $extender_name The name of the extender
- * @return true|false Depending on success
+ * @param string $function_name The function to register
+ *
+ * @return bool
*/
-function register_extender_url_handler($function_name, $extender_type = "all", $extender_name = "all") {
+function elgg_register_extender_url_handler($extender_type, $extender_name, $function_name) {
+
global $CONFIG;
- if (!is_callable($function_name)) {
+ if (!is_callable($function_name, true)) {
return false;
}
@@ -426,7 +203,9 @@ function register_extender_url_handler($function_name, $extender_type = "all", $
* Get the URL of a given elgg extender.
* Used by get_annotation_url and get_metadata_url.
*
- * @param ElggExtender $extender
+ * @param ElggExtender $extender An extender object
+ *
+ * @return string
*/
function get_extender_url(ElggExtender $extender) {
global $CONFIG;
@@ -452,18 +231,19 @@ function get_extender_url(ElggExtender $extender) {
}
if (is_callable($function)) {
- $url = $function($extender);
+ $url = call_user_func($function, $extender);
}
if ($url == "") {
$nameid = $extender->id;
if ($type == 'volatile') {
- $nameid== $extender->name;
+ $nameid = $extender->name;
}
- $url = $CONFIG->wwwroot . "export/$view/$guid/$type/$nameid/";
+ $url = "export/$view/$guid/$type/$nameid/";
}
- return $url;
+
+ return elgg_normalize_url($url);
}
/** Register the hook */
-register_plugin_hook("import", "all", "import_extender_plugin_hook", 2); \ No newline at end of file
+elgg_register_plugin_hook_handler("import", "all", "import_extender_plugin_hook", 2);
diff --git a/engine/lib/filestore.php b/engine/lib/filestore.php
index d131154c6..a3c7ba439 100644
--- a/engine/lib/filestore.php
+++ b/engine/lib/filestore.php
@@ -1,723 +1,30 @@
<?php
/**
* Elgg filestore.
- * This file contains classes, interfaces and functions for saving and retrieving data to various file
- * stores.
+ * This file contains classes, interfaces and functions for
+ * saving and retrieving data to various file stores.
*
- * @package Elgg
- * @subpackage API
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage DataModel.FileStorage
*/
-include_once("objects.php");
-
-/**
- * @class ElggFilestore
- * This class defines the interface for all elgg data repositories.
- * @author Curverider Ltd
- */
-abstract class ElggFilestore {
- /**
- * Attempt to open the file $file for storage or writing.
- *
- * @param ElggFile $file
- * @param string $mode "read", "write", "append"
- * @return mixed A handle to the opened file or false on error.
- */
- abstract public function open(ElggFile $file, $mode);
-
- /**
- * Write data to a given file handle.
- *
- * @param mixed $f The file handle - exactly what this is depends on the file system
- * @param string $data The binary string of data to write
- * @return int Number of bytes written.
- */
- abstract public function write($f, $data);
-
- /**
- * Read data from a filestore.
- *
- * @param mixed $f The file handle
- * @param int $length Length in bytes to read.
- * @param int $offset The optional offset.
- * @return mixed String of data or false on error.
- */
- abstract public function read($f, $length, $offset = 0);
-
- /**
- * Seek a given position within a file handle.
- *
- * @param mixed $f The file handle.
- * @param int $position The position.
- */
- abstract public function seek($f, $position);
-
- /**
- * Return a whether the end of a file has been reached.
- *
- * @param mixed $f The file handle.
- * @return boolean
- */
- abstract public function eof($f);
-
- /**
- * Return the current position in an open file.
- *
- * @param mixed $f The file handle.
- * @return int
- */
- abstract public function tell($f);
-
- /**
- * Close a given file handle.
- *
- * @param mixed $f
- */
- abstract public function close($f);
-
- /**
- * Delete the file associated with a given file handle.
- *
- * @param ElggFile $file
- */
- abstract public function delete(ElggFile $file);
-
- /**
- * Return the size in bytes for a given file.
- *
- * @param ElggFile $file
- */
- abstract public function getFileSize(ElggFile $file);
-
- /**
- * Return the filename of a given file as stored on the filestore.
- *
- * @param ElggFile $file
- */
- abstract public function getFilenameOnFilestore(ElggFile $file);
-
- /**
- * Get the filestore's creation parameters as an associative array.
- * Used for serialisation and for storing the creation details along side a file object.
- *
- * @return array
- */
- abstract public function getParameters();
-
- /**
- * Set the parameters from the associative array produced by $this->getParameters().
- */
- abstract public function setParameters(array $parameters);
-
- /**
- * Get the contents of the whole file.
- *
- * @param mixed $file The file handle.
- * @return mixed The file contents.
- */
- abstract public function grabFile(ElggFile $file);
-
- /**
- * Return whether a file physically exists or not.
- *
- * @param ElggFile $file
- */
- abstract public function exists(ElggFile $file);
-}
-
-/**
- * @class ElggDiskFilestore
- * This class uses disk storage to save data.
- * @author Curverider Ltd
- */
-class ElggDiskFilestore extends ElggFilestore {
- /**
- * Directory root.
- */
- private $dir_root;
-
- /**
- * Default depth of file directory matrix
- */
- private $matrix_depth = 5;
-
- /**
- * Construct a disk filestore using the given directory root.
- *
- * @param string $directory_root Root directory, must end in "/"
- */
- public function __construct($directory_root = "") {
- global $CONFIG;
-
- if ($directory_root) {
- $this->dir_root = $directory_root;
- } else {
- $this->dir_root = $CONFIG->dataroot;
- }
- }
-
- public function open(ElggFile $file, $mode) {
- $fullname = $this->getFilenameOnFilestore($file);
-
- // Split into path and name
- $ls = strrpos($fullname,"/");
- if ($ls===false) {
- $ls = 0;
- }
-
- $path = substr($fullname, 0, $ls);
- $name = substr($fullname, $ls);
-
- // Try and create the directory
- try {
- $this->make_directory_root($path);
- } catch (Exception $e) {
-
- }
-
- if (($mode!='write') && (!file_exists($fullname))) {
- return false;
- }
-
- switch ($mode) {
- case "read" :
- $mode = "rb";
- break;
- case "write" :
- $mode = "w+b";
- break;
- case "append" :
- $mode = "a+b";
- break;
- default:
- throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:UnrecognisedFileMode'), $mode));
- }
-
- return fopen($fullname, $mode);
-
- }
-
- public function write($f, $data) {
- return fwrite($f, $data);
- }
-
- public function read($f, $length, $offset = 0) {
- if ($offset) {
- $this->seek($f, $offset);
- }
-
- return fread($f, $length);
- }
-
- public function close($f) {
- return fclose($f);
- }
-
- public function delete(ElggFile $file) {
- $filename = $this->getFilenameOnFilestore($file);
- if (file_exists($filename)) {
- return unlink($filename);
- } else {
- return true;
- }
- }
-
- public function seek($f, $position) {
- return fseek($f, $position);
- }
-
- public function tell($f) {
- return ftell($f);
- }
-
- public function eof($f) {
- return feof($f);
- }
-
- public function getFileSize(ElggFile $file) {
- return filesize($this->getFilenameOnFilestore($file));
- }
-
- public function getFilenameOnFilestore(ElggFile $file) {
- $owner = $file->getOwnerEntity();
- if (!$owner) {
- $owner = get_loggedin_user();
- }
-
- if ((!$owner) || (!$owner->username)) {
- throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:MissingOwner'), $file->getFilename(), $file->guid));
- }
-
- return $this->dir_root . $this->make_file_matrix($owner->guid) . $file->getFilename();
- }
-
- public function grabFile(ElggFile $file) {
- return file_get_contents($file->getFilenameOnFilestore());
- }
-
- public function exists(ElggFile $file) {
- return file_exists($this->getFilenameOnFilestore($file));
- }
-
- public function getSize($prefix,$container_guid) {
- if ($container_guid) {
- return get_dir_size($this->dir_root.$this->make_file_matrix($container_guid).$prefix);
- } else {
- return false;
- }
- }
-
- /**
- * Make the directory root.
- *
- * @param string $dirroot
- */
- protected function make_directory_root($dirroot) {
- if (!file_exists($dirroot)) {
- if (!@mkdir($dirroot, 0700, true)) {
- throw new IOException(sprintf(elgg_echo('IOException:CouldNotMake'), $dirroot));
- }
- }
-
- return true;
- }
-
- /**
- * Multibyte string tokeniser.
- *
- * Splits a string into an array. Will fail safely if mbstring is not installed (although this may still
- * not handle .
- *
- * @param string $string String
- * @param string $charset The charset, defaults to UTF8
- * @return array
- */
- private function mb_str_split($string, $charset = 'UTF8') {
- if (is_callable('mb_substr')) {
- $length = mb_strlen($string);
- $array = array();
-
- while ($length) {
- $array[] = mb_substr($string, 0, 1, $charset);
- $string = mb_substr($string, 1, $length, $charset);
-
- $length = mb_strlen($string);
- }
-
- return $array;
- } else {
- return str_split($string);
- }
-
- return false;
- }
-
- /**
- * Construct the filename matrix.
- *
- * @param int | string $identifier
- * @return str
- */
- protected function make_file_matrix($identifier) {
- if (is_numeric($identifier)) {
- return $this->user_file_matrix($identifier);
- }
-
- return $this->deprecated_file_matrix($identifier);
- }
-
- /**
- * Construct the filename matrix with user info
- *
- * This method will generate a matrix using the entity's creation time and
- * unique guid. This is intended only to determine a user's data directory.
- *
- * @param int $guid
- * @return str
- */
- protected function user_file_matrix($guid) {
- // lookup the entity
- $user = get_entity($guid);
- if ($user->type != 'user')
- {
- // only to be used for user directories
- return FALSE;
- }
-
- if (!$user->time_created) {
- // fall back to deprecated method
- return $this->deprecated_file_matrix($user->username);
- }
-
- $time_created = date('Y/m/d', $user->time_created);
- return "$time_created/$user->guid/";
- }
-
- /**
- * Construct the filename matrix using a string
- *
- * Particularly, this is used with a username to generate the file storage
- * location.
- *
- * @deprecated for user directories: use user_file_matrix() instead.
- *
- * @param str $filename
- * @return str
- */
- protected function deprecated_file_matrix($filename) {
- // throw a warning for using deprecated method
- $error = 'Deprecated use of ElggDiskFilestore::make_file_matrix. ';
- $error .= 'Username passed instead of guid.';
- elgg_log($error, WARNING);
-
- $user = new ElggUser($filename);
- return $this->user_file_matrix($user->guid);
- }
-
- public function getParameters() {
- return array("dir_root" => $this->dir_root);
- }
-
- public function setParameters(array $parameters) {
- if (isset($parameters['dir_root'])) {
- $this->dir_root = $parameters['dir_root'];
- return true;
- }
-
- return false;
- }
-}
-
-/**
- * @class ElggFile
- * This class represents a physical file.
- *
- * Usage:
- * Create a new ElggFile object and specify a filename, and optionally a FileStore (if one isn't specified
- * then the default is assumed.
- *
- * Open the file using the appropriate mode, and you will be able to read and write to the file.
- *
- * Optionally, you can also call the file's save() method, this will turn the file into an entity in the
- * system and permit you to do things like attach tags to the file etc. This is not done automatically since
- * there are many occasions where you may want access to file data on datastores using the ElggFile interface
- * but do not want to create an Entity reference to it in the system (temporary files for example).
- *
- * @author Curverider Ltd
- */
-class ElggFile extends ElggObject {
- /** Filestore */
- private $filestore;
-
- /** File handle used to identify this file in a filestore. Created by open. */
- private $handle;
-
- protected function initialise_attributes() {
- parent::initialise_attributes();
-
- $this->attributes['subtype'] = "file";
- }
-
- public function __construct($guid = null) {
- parent::__construct($guid);
-
- // Set default filestore
- $this->filestore = $this->getFilestore();
- }
-
- /**
- * Set the filename of this file.
- *
- * @param string $name The filename.
- */
- public function setFilename($name) {
- $this->filename = $name;
- }
-
- /**
- * Return the filename.
- */
- public function getFilename() {
- return $this->filename;
- }
-
- /**
- * Return the filename of this file as it is/will be stored on the filestore, which may be different
- * to the filename.
- */
- public function getFilenameOnFilestore() {
- return $this->filestore->getFilenameOnFilestore($this);
- }
-
- /*
- * Return the size of the filestore associated with this file
- *
- */
- public function getFilestoreSize($prefix='',$container_guid=0) {
- if (!$container_guid) {
- $container_guid = $this->container_guid;
- }
- $fs = $this->getFilestore();
- return $fs->getSize($prefix,$container_guid);
- }
-
- /**
- * Get the mime type of the file.
- */
- public function getMimeType() {
- if ($this->mimetype) {
- return $this->mimetype;
- }
-
- // TODO : Guess mimetype if not here
- }
-
- /**
- * Set the mime type of the file.
- *
- * @param $mimetype The mimetype
- */
- public function setMimeType($mimetype) {
- return $this->mimetype = $mimetype;
- }
-
- /**
- * Set the optional file description.
- *
- * @param string $description The description.
- */
- public function setDescription($description) {
- $this->description = $description;
- }
-
- /**
- * Open the file with the given mode
- *
- * @param string $mode Either read/write/append
- */
- public function open($mode) {
- if (!$this->getFilename()) {
- throw new IOException(elgg_echo('IOException:MissingFileName'));
- }
-
- // See if file has already been saved
- // seek on datastore, parameters and name?
-
- // Sanity check
- if (
- ($mode!="read") &&
- ($mode!="write") &&
- ($mode!="append")
- ) {
- throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:UnrecognisedFileMode'), $mode));
- }
-
- // Get the filestore
- $fs = $this->getFilestore();
-
- // Ensure that we save the file details to object store
- //$this->save();
-
- // Open the file handle
- $this->handle = $fs->open($this, $mode);
-
- return $this->handle;
- }
-
- /**
- * Write some data.
- *
- * @param string $data The data
- */
- public function write($data) {
- $fs = $this->getFilestore();
-
- return $fs->write($this->handle, $data);
- }
-
- /**
- * Read some data.
- *
- * @param int $length Amount to read.
- * @param int $offset The offset to start from.
- */
- public function read($length, $offset = 0) {
- $fs = $this->getFilestore();
-
- return $fs->read($this->handle, $length, $offset);
- }
-
- /**
- * Gets the full contents of this file.
- *
- * @return mixed The file contents.
- */
- public function grabFile() {
- $fs = $this->getFilestore();
- return $fs->grabFile($this);
- }
-
- /**
- * Close the file and commit changes
- */
- public function close() {
- $fs = $this->getFilestore();
-
- if ($fs->close($this->handle)) {
- $this->handle = NULL;
-
- return true;
- }
-
- return false;
- }
-
- /**
- * Delete this file.
- */
- public function delete() {
- $fs = $this->getFilestore();
- if ($fs->delete($this)) {
- return parent::delete();
- }
- }
-
- /**
- * Seek a position in the file.
- *
- * @param int $position
- */
- public function seek($position) {
- $fs = $this->getFilestore();
-
- return $fs->seek($this->handle, $position);
- }
-
- /**
- * Return the current position of the file.
- *
- * @return int The file position
- */
- public function tell() {
- $fs = $this->getFilestore();
-
- return $fs->tell($this->handle);
- }
-
- /**
- * Return the size of the file in bytes.
- */
- public function size() {
- return $this->filestore->getFileSize($this);
- }
-
- /**
- * Return a boolean value whether the file handle is at the end of the file
- */
- public function eof() {
- $fs = $this->getFilestore();
-
- return $fs->eof($this->handle);
- }
-
- public function exists() {
- $fs = $this->getFilestore();
-
- return $fs->exists($this);
- }
-
- /**
- * Set a filestore.
- *
- * @param ElggFilestore $filestore The file store.
- */
- public function setFilestore(ElggFilestore $filestore) {
- $this->filestore = $filestore;
- }
-
- /**
- * Return a filestore suitable for saving this file.
- * This filestore is either a pre-registered filestore, a filestore loaded from metatags saved
- * along side this file, or the system default.
- */
- protected function getFilestore() {
- // Short circuit if already set.
- if ($this->filestore) {
- return $this->filestore;
- }
-
- // If filestore meta set then retrieve filestore TODO: Better way of doing this?
- $metas = get_metadata_for_entity($this->guid);
- $parameters = array();
- if (is_array($metas)) {
- foreach ($metas as $meta) {
- if (strpos($meta->name, "filestore::")!==false) {
- // Filestore parameter tag
- $comp = explode("::", $meta->name);
- $name = $comp[1];
-
- $parameters[$name] = $meta->value;
- }
- }
- }
-
- // If parameters loaded then create new filestore
- if (count($parameters)!=0) {
- // Create new filestore object
- if ((!isset($parameters['filestore'])) || (!class_exists($parameters['filestore']))) {
- throw new ClassNotFoundException(elgg_echo('ClassNotFoundException:NotFoundNotSavedWithFile'));
- }
-
- $this->filestore = new $parameters['filestore']();
-
- // Set parameters
- $this->filestore->setParameters($parameters);
- }
-
-
- // if still nothing then set filestore to default
- if (!$this->filestore) {
- $this->filestore = get_default_filestore();
- }
-
- return $this->filestore;
- }
-
- public function save() {
- if (!parent::save()) {
- return false;
- }
-
- // Save datastore metadata
- $params = $this->filestore->getParameters();
- foreach ($params as $k => $v) {
- $this->setMetaData("filestore::$k", $v);
- }
-
- // Now make a note of the filestore class
- $this->setMetaData("filestore::filestore", get_class($this->filestore));
-
- return true;
- }
-}
-
/**
* Get the size of the specified directory.
*
- * @param string $dir The full path of the directory
+ * @param string $dir The full path of the directory
+ * @param int $totalsize Add to current dir size
+ *
* @return int The size of the directory.
*/
-function get_dir_size($dir, $totalsize = 0){
+function get_dir_size($dir, $totalsize = 0) {
$handle = @opendir($dir);
- while ($file = @readdir ($handle)){
+ while ($file = @readdir($handle)) {
if (eregi("^\.{1,2}$", $file)) {
continue;
}
- if(is_dir($dir . $file)) {
+ if (is_dir($dir . $file)) {
$totalsize = get_dir_size($dir . $file . "/", $totalsize);
- } else{
+ } else {
$totalsize += filesize($dir . $file);
}
}
@@ -731,6 +38,7 @@ function get_dir_size($dir, $totalsize = 0){
* (Returns false if there was an issue.)
*
* @param string $input_name The name of the file input field on the submission form
+ *
* @return mixed|false The contents of the file, or false on failure.
*/
function get_uploaded_file($input_name) {
@@ -746,15 +54,22 @@ function get_uploaded_file($input_name) {
* (Returns false if the uploaded file was not an image)
*
* @param string $input_name The name of the file input field on the submission form
- * @param int $maxwidth The maximum width of the resized image
- * @param int $maxheight The maximum height of the resized image
- * @param true|false $square If set to true, will take the smallest of maxwidth and maxheight and use it to set the dimensions on all size; the image will be cropped.
+ * @param int $maxwidth The maximum width of the resized image
+ * @param int $maxheight The maximum height of the resized image
+ * @param bool $square If set to true, will take the smallest
+ * of maxwidth and maxheight and use it to set the
+ * dimensions on all size; the image will be cropped.
+ * @param bool $upscale Resize images smaller than $maxwidth x $maxheight?
+ *
* @return false|mixed The contents of the resized image, or false on failure
*/
-function get_resized_image_from_uploaded_file($input_name, $maxwidth, $maxheight, $square = false) {
+function get_resized_image_from_uploaded_file($input_name, $maxwidth, $maxheight,
+$square = false, $upscale = false) {
+
// If our file exists ...
if (isset($_FILES[$input_name]) && $_FILES[$input_name]['error'] == 0) {
- return get_resized_image_from_existing_file($_FILES[$input_name]['tmp_name'], $maxwidth, $maxheight, $square);
+ return get_resized_image_from_existing_file($_FILES[$input_name]['tmp_name'], $maxwidth,
+ $maxheight, $square, 0, 0, 0, 0, $upscale);
}
return false;
@@ -765,32 +80,33 @@ function get_resized_image_from_uploaded_file($input_name, $maxwidth, $maxheight
* (Returns false if the file was not an image)
*
* @param string $input_name The name of the file on the disk
- * @param int $maxwidth The desired width of the resized image
- * @param int $maxheight The desired height of the resized image
- * @param true|false $square If set to true, takes the smallest of maxwidth and
- * maxheight and use it to set the dimensions on the new image. If no
- * crop parameters are set, the largest square that fits in the image
- * centered will be used for the resize. If square, the crop must be a
- * square region.
- * @param int $x1 x coordinate for top, left corner
- * @param int $y1 y coordinate for top, left corner
- * @param int $x2 x coordinate for bottom, right corner
- * @param int $y2 y coordinate for bottom, right corner
- * @param bool $upscale Resize images smaller than $maxwidth x $maxheight?
+ * @param int $maxwidth The desired width of the resized image
+ * @param int $maxheight The desired height of the resized image
+ * @param bool $square If set to true, takes the smallest of maxwidth and
+ * maxheight and use it to set the dimensions on the new image.
+ * If no crop parameters are set, the largest square that fits
+ * in the image centered will be used for the resize. If square,
+ * the crop must be a square region.
+ * @param int $x1 x coordinate for top, left corner
+ * @param int $y1 y coordinate for top, left corner
+ * @param int $x2 x coordinate for bottom, right corner
+ * @param int $y2 y coordinate for bottom, right corner
+ * @param bool $upscale Resize images smaller than $maxwidth x $maxheight?
+ *
* @return false|mixed The contents of the resized image, or false on failure
*/
-function get_resized_image_from_existing_file($input_name, $maxwidth, $maxheight, $square = FALSE, $x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0, $upscale = FALSE) {
+function get_resized_image_from_existing_file($input_name, $maxwidth, $maxheight, $square = FALSE,
+$x1 = 0, $y1 = 0, $x2 = 0, $y2 = 0, $upscale = FALSE) {
+
// Get the size information from the image
$imgsizearray = getimagesize($input_name);
if ($imgsizearray == FALSE) {
return FALSE;
}
- // Get width and height
$width = $imgsizearray[0];
$height = $imgsizearray[1];
- // make sure we can read the image
$accepted_formats = array(
'image/jpeg' => 'jpeg',
'image/pjpeg' => 'jpeg',
@@ -805,6 +121,94 @@ function get_resized_image_from_existing_file($input_name, $maxwidth, $maxheight
return FALSE;
}
+ // get the parameters for resizing the image
+ $options = array(
+ 'maxwidth' => $maxwidth,
+ 'maxheight' => $maxheight,
+ 'square' => $square,
+ 'upscale' => $upscale,
+ 'x1' => $x1,
+ 'y1' => $y1,
+ 'x2' => $x2,
+ 'y2' => $y2,
+ );
+ $params = get_image_resize_parameters($width, $height, $options);
+ if ($params == FALSE) {
+ return FALSE;
+ }
+
+ // load original image
+ $original_image = $load_function($input_name);
+ if (!$original_image) {
+ return FALSE;
+ }
+
+ // allocate the new image
+ $new_image = imagecreatetruecolor($params['newwidth'], $params['newheight']);
+ if (!$new_image) {
+ return FALSE;
+ }
+
+ // color transparencies white (default is black)
+ imagefilledrectangle(
+ $new_image, 0, 0, $params['newwidth'], $params['newheight'],
+ imagecolorallocate($new_image, 255, 255, 255)
+ );
+
+ $rtn_code = imagecopyresampled( $new_image,
+ $original_image,
+ 0,
+ 0,
+ $params['xoffset'],
+ $params['yoffset'],
+ $params['newwidth'],
+ $params['newheight'],
+ $params['selectionwidth'],
+ $params['selectionheight']);
+ if (!$rtn_code) {
+ return FALSE;
+ }
+
+ // grab a compressed jpeg version of the image
+ ob_start();
+ imagejpeg($new_image, NULL, 90);
+ $jpeg = ob_get_clean();
+
+ imagedestroy($new_image);
+ imagedestroy($original_image);
+
+ return $jpeg;
+}
+
+/**
+ * Calculate the parameters for resizing an image
+ *
+ * @param int $width Width of the original image
+ * @param int $height Height of the original image
+ * @param array $options See $defaults for the options
+ *
+ * @return array or FALSE
+ * @since 1.7.2
+ */
+function get_image_resize_parameters($width, $height, $options) {
+
+ $defaults = array(
+ 'maxwidth' => 100,
+ 'maxheight' => 100,
+
+ 'square' => FALSE,
+ 'upscale' => FALSE,
+
+ 'x1' => 0,
+ 'y1' => 0,
+ 'x2' => 0,
+ 'y2' => 0,
+ );
+
+ $options = array_merge($defaults, $options);
+
+ extract($options);
+
// crop image first?
$crop = TRUE;
if ($x1 == 0 && $y1 == 0 && $x2 == 0 && $y2 == 0) {
@@ -813,12 +217,12 @@ function get_resized_image_from_existing_file($input_name, $maxwidth, $maxheight
// how large a section of the image has been selected
if ($crop) {
- $region_width = $x2 - $x1;
- $region_height = $y2 - $y1;
+ $selection_width = $x2 - $x1;
+ $selection_height = $y2 - $y1;
} else {
// everything selected if no crop parameters
- $region_width = $width;
- $region_height = $height;
+ $selection_width = $width;
+ $selection_height = $height;
}
// determine cropping offsets
@@ -826,7 +230,7 @@ function get_resized_image_from_existing_file($input_name, $maxwidth, $maxheight
// asking for a square image back
// detect case where someone is passing crop parameters that are not for a square
- if ($crop == TRUE && $region_width != $region_height) {
+ if ($crop == TRUE && $selection_width != $selection_height) {
return FALSE;
}
@@ -834,7 +238,7 @@ function get_resized_image_from_existing_file($input_name, $maxwidth, $maxheight
$new_width = $new_height = min($maxwidth, $maxheight);
// find largest square that fits within the selected region
- $region_width = $region_height = min($region_width, $region_height);
+ $selection_width = $selection_height = min($selection_width, $selection_height);
// set offsets for crop
if ($crop) {
@@ -844,20 +248,19 @@ function get_resized_image_from_existing_file($input_name, $maxwidth, $maxheight
$height = $width;
} else {
// place square region in the center
- $widthoffset = floor(($width - $region_width) / 2);
- $heightoffset = floor(($height - $region_height) / 2);
+ $widthoffset = floor(($width - $selection_width) / 2);
+ $heightoffset = floor(($height - $selection_height) / 2);
}
} else {
// non-square new image
-
$new_width = $maxwidth;
- $new_height = $maxwidth;
+ $new_height = $maxheight;
// maintain aspect ratio of original image/crop
- if (($region_height / (float)$new_height) > ($region_width / (float)$new_width)) {
- $new_width = floor($new_height * $region_width / (float)$region_height);
+ if (($selection_height / (float)$new_height) > ($selection_width / (float)$new_width)) {
+ $new_width = floor($new_height * $selection_width / (float)$selection_height);
} else {
- $new_height = floor($new_width * $region_height / (float)$region_width);
+ $new_height = floor($new_width * $selection_height / (float)$selection_width);
}
// by default, use entire image
@@ -870,75 +273,41 @@ function get_resized_image_from_existing_file($input_name, $maxwidth, $maxheight
}
}
- // check for upscaling
- // @todo This ignores squares, coordinates, and cropping. It's probably not the best idea.
- // Size checking should be done in action code, but for backward compatibility
- // this duplicates the previous behavior.
- if (!$upscale && ($height < $new_height || $width < $new_width)) {
- // zero out offsets
- $widthoffset = $heightoffset = 0;
-
- // determine if we can scale it down at all
- // (ie, if only one dimension is too small)
- // if not, just use original size.
- if ($height < $new_height && $width < $new_width) {
- $ratio = 1;
- } elseif ($height < $new_height) {
- $ratio = $new_width / $width;
- } elseif ($width < $new_width) {
- $ratio = $new_height / $height;
+ if (!$upscale && ($selection_height < $new_height || $selection_width < $new_width)) {
+ // we cannot upscale and selected area is too small so we decrease size of returned image
+ if ($square) {
+ $new_height = $selection_height;
+ $new_width = $selection_width;
+ } else {
+ if ($selection_height < $new_height && $selection_width < $new_width) {
+ $new_height = $selection_height;
+ $new_width = $selection_width;
+ }
}
- $region_height = $height;
- $region_width = $width;
- $new_height = floor($height * $ratio);
- $new_width = floor($width * $ratio);
}
- // load original image
- $orig_image = $load_function($input_name);
- if (!$orig_image) {
- return FALSE;
- }
-
- // allocate the new image
- $newimage = imagecreatetruecolor($new_width, $new_height);
- if (!$newimage) {
- return FALSE;
- }
-
- // create the new image
- $rtn_code = imagecopyresampled( $newimage,
- $orig_image,
- 0,
- 0,
- $widthoffset,
- $heightoffset,
- $new_width,
- $new_height,
- $region_width,
- $region_height );
- if (!$rtn_code) {
- return FALSE;
- }
-
- // grab contents for return
- ob_start();
- imagejpeg($newimage, null, 90);
- $jpeg = ob_get_clean();
-
- imagedestroy($newimage);
- imagedestroy($orig_image);
+ $params = array(
+ 'newwidth' => $new_width,
+ 'newheight' => $new_height,
+ 'selectionwidth' => $selection_width,
+ 'selectionheight' => $selection_height,
+ 'xoffset' => $widthoffset,
+ 'yoffset' => $heightoffset,
+ );
- return $jpeg;
+ return $params;
}
-
-// putting these here for now
+/**
+ * Delete an ElggFile file
+ *
+ * @param int $guid ElggFile GUID
+ *
+ * @return bool
+ */
function file_delete($guid) {
if ($file = get_entity($guid)) {
if ($file->canEdit()) {
- $container = get_entity($file->container_guid);
-
$thumbnail = $file->thumbnail;
$smallthumb = $file->smallthumb;
$largethumb = $file->largethumb;
@@ -972,6 +341,7 @@ function file_delete($guid) {
* Returns an overall file type from the mimetype
*
* @param string $mimetype The MIME type
+ *
* @return string The overall type
*/
function file_get_general_file_type($mimetype) {
@@ -985,397 +355,35 @@ function file_get_general_file_type($mimetype) {
break;
}
- if (substr_count($mimetype,'text/')) {
+ if (substr_count($mimetype, 'text/')) {
return "document";
}
- if (substr_count($mimetype,'audio/')) {
+ if (substr_count($mimetype, 'audio/')) {
return "audio";
}
- if (substr_count($mimetype,'image/')) {
+ if (substr_count($mimetype, 'image/')) {
return "image";
}
- if (substr_count($mimetype,'video/')) {
+ if (substr_count($mimetype, 'video/')) {
return "video";
}
- if (substr_count($mimetype,'opendocument')) {
+ if (substr_count($mimetype, 'opendocument')) {
return "document";
}
return "general";
}
-function file_handle_upload($prefix,$subtype,$plugin) {
- $desc = get_input("description");
- $tags = get_input("tags");
- $tags = explode(",", $tags);
- $folder = get_input("folder_text");
- if (!$folder) {
- $folder = get_input("folder_select");
- }
- $access_id = (int) get_input("access_id");
- $container_guid = (int) get_input('container_guid', 0);
- if (!$container_guid) {
- $container_guid == get_loggedin_userid();
- }
-
- // Extract file from, save to default filestore (for now)
-
- // see if a plugin has set a quota for this user
- $file_quota = trigger_plugin_hook("$plugin:quotacheck",'user',array('container_guid'=>$container_guid));
- if (!$file_quota) {
- // no, see if there is a generic quota set
- $file_quota = get_plugin_setting('quota', $plugin);
- }
- if ($file_quota) {
- // convert to megabytes
- $file_quota = $file_quota*1000*1024;
- }
-
- // handle uploaded files
- $number_of_files = get_input('number_of_files',0);
- $quota_exceeded = false;
- $bad_mime_type = false;
-
- for ($i = 0; $i < $number_of_files; $i++) {
- $title = get_input("title_".$i);
- $uploaded = $_FILES["upload_".$i];
- if (!$uploaded || !$uploaded['name']) {
- // no such file, so skip it
- continue;
- }
- if ($plugin == "photo") {
- // do a mime type test
- if (in_array($uploaded['type'],array('image/jpeg','image/gif','image/png','image/jpg','image/jpe','image/pjpeg','image/x-png'))) {
- $file = new PhotoPluginFile();
- } else {
- $bad_mime_type = true;
- break;
- }
- } else {
- $file = new FilePluginFile();
- }
- $dir_size = $file->getFilestoreSize($prefix,$container_guid);
- $filestorename = strtolower(time().$uploaded['name']);
- $file->setFilename($prefix.$filestorename);
- $file->setMimeType($uploaded['type']);
-
- $file->originalfilename = $uploaded['name'];
-
- $file->subtype = $subtype;
-
- $file->access_id = $access_id;
-
- $uf = get_uploaded_file('upload_'.$i);
-
- if ($file_quota) {
- $file_size = strlen($uf);
- if (($dir_size + $file_size) > $file_quota) {
- $quota_exceeded = true;
- }
- }
-
- if (!$quota_exceeded) {
- // all clear, so try to save the data
-
- $file->open("write");
- $file->write($uf);
- $file->close();
-
- $file->title = $title;
- $file->description = $desc;
- if ($container_guid) {
- $file->container_guid = $container_guid;
- }
-
- // Save tags
- $file->tags = $tags;
-
- $file->simpletype = file_get_general_file_type($uploaded['type']);
- $file->folder = $folder;
-
- $result = $file->save();
-
- if ($result) {
-
- // Generate thumbnail (if image)
- if (substr_count($file->getMimeType(),'image/')) {
- $thumbnail = get_resized_image_from_existing_file($file->getFilenameOnFilestore(),60,60, true);
- $thumbsmall = get_resized_image_from_existing_file($file->getFilenameOnFilestore(),153,153, true);
- $thumblarge = get_resized_image_from_existing_file($file->getFilenameOnFilestore(),600,600, false);
- if ($thumbnail) {
- $thumb = new ElggFile();
- $thumb->setMimeType($uploaded['type']);
-
- $thumb->setFilename($prefix."thumb".$filestorename);
- $thumb->open("write");
- $thumb->write($thumbnail);
- $thumb->close();
-
- $file->thumbnail = $prefix."thumb".$filestorename;
-
- $thumb->setFilename($prefix."smallthumb".$filestorename);
- $thumb->open("write");
- $thumb->write($thumbsmall);
- $thumb->close();
- $file->smallthumb = $prefix."smallthumb".$filestorename;
-
- $thumb->setFilename($prefix."largethumb".$filestorename);
- $thumb->open("write");
- $thumb->write($thumblarge);
- $thumb->close();
- $file->largethumb = $prefix."largethumb".$filestorename;
- }
- }
-
- // add to this user's file folders
- file_add_to_folders($folder,$container_guid,$plugin);
-
- add_to_river("river/object/$plugin/create",'create',$_SESSION['user']->guid,$file->guid);
- } else {
- break;
- }
- } else {
- break;
- }
- }
-
- if ($quota_exceeded) {
- echo elgg_echo("$plugin:quotaexceeded");
- } else if ($bad_mime_type) {
- echo elgg_echo("$plugin:badmimetype");
- } else if ($result) {
- if ($number_of_files > 1) {
- echo elgg_echo("$plugin:saved_multi");
- } else {
- echo elgg_echo("$plugin:saved");
- }
- } else {
- if ($number_of_files > 1) {
- echo elgg_echo("$plugin:uploadfailed_multi");
- } else {
- echo elgg_echo("$plugin:uploadfailed");
- }
- }
-}
-
-function file_add_to_folders($folder,$container_guid,$plugin) {
- if ($container_guid && ($container = get_entity($container_guid))) {
- $folder_field_name = 'elgg_'.$plugin.'_folders';
- $folders = $container->$folder_field_name;
- if ($folders) {
- if (is_array($folders)) {
- if (!in_array($folder,$folders)) {
- $folders[] = $folder;
- $container->$folder_field_name = $folders;
- }
- } else {
- if ($folders != $folder) {
- $container->$folder_field_name = array($folders,$folder);
- }
- }
- } else {
- $container->$folder_field_name = $folder;
- }
- }
-}
-
-function file_handle_save($forward,$plugin) {
- // Get variables
- $title = get_input("title");
- $desc = get_input("description");
- $tags = get_input("tags");
- $folder = get_input("folder_text");
- if (!$folder) {
- $folder = get_input("folder_select");
- }
- $access_id = (int) get_input("access_id");
-
- $guid = (int) get_input('file_guid');
-
- if (!$file = get_entity($guid)) {
- register_error(elgg_echo("$plugin:uploadfailed"));
- forward($forward . $_SESSION['user']->username);
- exit;
- }
-
- $result = false;
-
- $container_guid = $file->container_guid;
- $container = get_entity($container_guid);
-
- if ($file->canEdit()) {
- $file->access_id = $access_id;
- $file->title = $title;
- $file->description = $desc;
- $file->folder = $folder;
- // add to this user's file folders
- file_add_to_folders($folder,$container_guid,$plugin);
-
- // Save tags
- $tags = explode(",", $tags);
- $file->tags = $tags;
-
- $result = $file->save();
- }
-
- if ($result) {
- system_message(elgg_echo("$plugin:saved"));
- } else {
- register_error(elgg_echo("$plugin:uploadfailed"));
- }
- forward($forward . $container->username);
-}
-
/**
- * Manage a file download.
+ * Delete a directory and all its contents
*
- * @param unknown_type $plugin
- * @param unknown_type $file_guid If not specified then file_guid will be found in input.
- */
-function file_manage_download($plugin, $file_guid = "") {
- // Get the guid
- $file_guid = (int)$file_guid;
-
- if (!$file_guid) {
- $file_guid = (int)get_input("file_guid");
- }
-
- // Get the file
- $file = get_entity($file_guid);
-
- if ($file) {
- $mime = $file->getMimeType();
- if (!$mime) {
- $mime = "application/octet-stream";
- }
-
- $filename = $file->originalfilename;
-
- header("Content-type: $mime");
- if (strpos($mime, "image/")!==false) {
- header("Content-Disposition: inline; filename=\"$filename\"");
- } else {
- header("Content-Disposition: attachment; filename=\"$filename\"");
- }
-
- echo $file->grabFile();
- exit;
- } else {
- register_error(elgg_echo("$plugin:downloadfailed"));
- }
-}
-
-/**
- * Manage the download of a file icon.
+ * @param string $directory Directory to delete
*
- * @param unknown_type $plugin
- * @param unknown_type $file_guid The guid, if not specified this is obtained from the input.
- */
-function file_manage_icon_download($plugin, $file_guid = "") {
- // Get the guid
- $file_guid = (int)$file_guid;
-
- if (!$file_guid) {
- $file_guid = (int)get_input("file_guid");
- }
-
- // Get the file
- $file = get_entity($file_guid);
-
- if ($file) {
- $mime = $file->getMimeType();
- if (!$mime) {
- $mime = "application/octet-stream";
- }
-
- $filename = $file->thumbnail;
-
- header("Content-type: $mime");
- if (strpos($mime, "image/")!==false) {
- header("Content-Disposition: inline; filename=\"$filename\"");
- } else {
- header("Content-Disposition: attachment; filename=\"$filename\"");
- }
-
- $readfile = new ElggFile();
- $readfile->owner_guid = $file->owner_guid;
- $readfile->setFilename($filename);
-
- /*
- if ($file->open("read"));
- {
- while (!$file->eof())
- {
- echo $file->read(10240, $file->tell());
- }
- }
- */
-
- $contents = $readfile->grabFile();
- if (empty($contents)) {
- echo file_get_contents(dirname(dirname(__FILE__)) . "/graphics/icons/general.jpg" );
- } else {
- echo $contents;
- }
- exit;
- } else {
- register_error(elgg_echo("$plugin:downloadfailed"));
- }
-}
-
-function file_display_thumbnail($file_guid,$size) {
- // Get file entity
- if ($file = get_entity($file_guid)) {
- $simpletype = $file->simpletype;
- if ($simpletype == "image") {
- // Get file thumbnail
- if ($size == "small") {
- $thumbfile = $file->smallthumb;
- } else {
- $thumbfile = $file->largethumb;
- }
-
- // Grab the file
- if ($thumbfile && !empty($thumbfile)) {
- $readfile = new ElggFile();
- $readfile->owner_guid = $file->owner_guid;
- $readfile->setFilename($thumbfile);
- $mime = $file->getMimeType();
- $contents = $readfile->grabFile();
-
- header("Content-type: $mime");
- echo $contents;
- exit;
- }
- }
- }
-}
-
-function file_set_page_owner($file) {
- $page_owner = page_owner_entity();
- if ($page_owner === false || is_null($page_owner)) {
- $container_guid = $file->container_guid;
- if (!empty($container_guid)) {
- if ($page_owner = get_entity($container_guid)) {
- set_page_owner($page_owner->guid);
- }
- }
-
- if (empty($page_owner)) {
- $page_owner = $_SESSION['user'];
- set_page_owner($_SESSION['guid']);
- }
- }
-}
-
-/**
- * Recursively delete a directory
- *
- * @param str $directory
+ * @return bool
*/
function delete_directory($directory) {
// sanity check: must be a directory
@@ -1409,7 +417,11 @@ function delete_directory($directory) {
/**
* Removes all user files
*
- * @param ElggUser $user
+ * @warning This only deletes the physical files and not their entities.
+ * This will result in FileExceptions being thrown. Don't use this function.
+ *
+ * @param ElggUser $user And ElggUser
+ *
* @return void
*/
function clear_user_files($user) {
@@ -1439,6 +451,10 @@ function get_default_filestore() {
/**
* Set the default filestore for the system.
+ *
+ * @param ElggFilestore $filestore An ElggFilestore object.
+ *
+ * @return true
*/
function set_default_filestore(ElggFilestore $filestore) {
global $DEFAULT_FILE_STORE;
@@ -1449,7 +465,11 @@ function set_default_filestore(ElggFilestore $filestore) {
}
/**
- * Run once and only once.
+ * Register entity type objects, subtype file as
+ * ElggFile.
+ *
+ * @return void
+ * @access private
*/
function filestore_run_once() {
// Register a class
@@ -1458,25 +478,43 @@ function filestore_run_once() {
/**
* Initialise the file modules.
- * Listens to system boot and registers any appropriate file types and classes
+ * Listens to system init and configures the default filestore
+ *
+ * @return void
+ * @access private
*/
function filestore_init() {
global $CONFIG;
// Now register a default filestore
- set_default_filestore(new ElggDiskFilestore($CONFIG->dataroot));
-
+ if (isset($CONFIG->dataroot)) {
+ set_default_filestore(new ElggDiskFilestore($CONFIG->dataroot));
+ }
+
// Now run this stuff, but only once
run_function_once("filestore_run_once");
}
-// Register a startup event
-register_elgg_event_handler('init', 'system', 'filestore_init', 100);
-
-// Unit testing
-register_plugin_hook('unit_test', 'system', 'filestore_test');
+/**
+ * Unit tests for files
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
+ */
function filestore_test($hook, $type, $value, $params) {
global $CONFIG;
$value[] = "{$CONFIG->path}engine/tests/objects/filestore.php";
return $value;
}
+
+
+// Register a startup event
+elgg_register_event_handler('init', 'system', 'filestore_init', 100);
+
+// Unit testing
+elgg_register_plugin_hook_handler('unit_test', 'system', 'filestore_test');
diff --git a/engine/lib/group.php b/engine/lib/group.php
index 68829dafb..6ded8a825 100644
--- a/engine/lib/group.php
+++ b/engine/lib/group.php
@@ -1,319 +1,20 @@
<?php
/**
* Elgg Groups.
- * Groups contain other entities, or rather act as a placeholder for other entities to mark any given container
- * as their container.
+ * Groups contain other entities, or rather act as a placeholder for other entities to
+ * mark any given container as their container.
*
- * @package Elgg
- * @subpackage Core
-
- * @author Curverider Ltd
-
- * @link http://elgg.org/
- */
-
-/**
- * @class ElggGroup Class representing a container for other elgg entities.
- * @author Curverider Ltd
+ * @package Elgg.Core
+ * @subpackage DataModel.Group
*/
-class ElggGroup extends ElggEntity
- implements Friendable {
-
- protected function initialise_attributes() {
- parent::initialise_attributes();
-
- $this->attributes['type'] = "group";
- $this->attributes['name'] = "";
- $this->attributes['description'] = "";
- $this->attributes['tables_split'] = 2;
- }
-
- /**
- * Construct a new user entity, optionally from a given id value.
- *
- * @param mixed $guid If an int, load that GUID.
- * If a db row then will attempt to load the rest of the data.
- * @throws Exception if there was a problem creating the user.
- */
- function __construct($guid = null) {
- $this->initialise_attributes();
-
- if (!empty($guid)) {
- // Is $guid is a DB row - either a entity row, or a user table row.
- if ($guid instanceof stdClass) {
- // Load the rest
- if (!$this->load($guid->guid)) {
- throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid->guid));
- }
- }
- // Is $guid is an ElggGroup? Use a copy constructor
- else if ($guid instanceof ElggGroup) {
- elgg_deprecated_notice('This type of usage of the ElggGroup constructor was deprecated. Please use the clone method.', 1.7);
-
- foreach ($guid->attributes as $key => $value) {
- $this->attributes[$key] = $value;
- }
- }
- // Is this is an ElggEntity but not an ElggGroup = ERROR!
- else if ($guid instanceof ElggEntity) {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggGroup'));
- }
- // We assume if we have got this far, $guid is an int
- else if (is_numeric($guid)) {
- if (!$this->load($guid)) {
- throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid));
- }
- }
-
- else {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnrecognisedValue'));
- }
- }
- }
-
- /**
- * Add an ElggObject to this group.
- *
- * @param ElggObject $object The object.
- * @return bool
- */
- public function addObjectToGroup(ElggObject $object) {
- return add_object_to_group($this->getGUID(), $object->getGUID());
- }
-
- /**
- * Remove an object from the containing group.
- *
- * @param int $guid The guid of the object.
- * @return bool
- */
- public function removeObjectFromGroup($guid) {
- return remove_object_from_group($this->getGUID(), $guid);
- }
-
- public function get($name) {
- if ($name == 'username') {
- return 'group:' . $this->getGUID();
- }
- return parent::get($name);
- }
-
-/**
- * Start friendable compatibility block:
- *
- * public function addFriend($friend_guid);
- public function removeFriend($friend_guid);
- public function isFriend();
- public function isFriendsWith($user_guid);
- public function isFriendOf($user_guid);
- public function getFriends($subtype = "", $limit = 10, $offset = 0);
- public function getFriendsOf($subtype = "", $limit = 10, $offset = 0);
- public function getObjects($subtype="", $limit = 10, $offset = 0);
- public function getFriendsObjects($subtype = "", $limit = 10, $offset = 0);
- public function countObjects($subtype = "");
- */
-
- /**
- * For compatibility with Friendable
- */
- public function addFriend($friend_guid) {
- return $this->join(get_entity($friend_guid));
- }
-
- /**
- * For compatibility with Friendable
- */
- public function removeFriend($friend_guid) {
- return $this->leave(get_entity($friend_guid));
- }
-
- /**
- * For compatibility with Friendable
- */
- public function isFriend() {
- return $this->isMember();
- }
-
- /**
- * For compatibility with Friendable
- */
- public function isFriendsWith($user_guid) {
- return $this->isMember($user_guid);
- }
-
- /**
- * For compatibility with Friendable
- */
- public function isFriendOf($user_guid) {
- return $this->isMember($user_guid);
- }
-
- /**
- * For compatibility with Friendable
- */
- public function getFriends($subtype = "", $limit = 10, $offset = 0) {
- return get_group_members($this->getGUID(), $limit, $offset);
- }
-
- /**
- * For compatibility with Friendable
- */
- public function getFriendsOf($subtype = "", $limit = 10, $offset = 0) {
- return get_group_members($this->getGUID(), $limit, $offset);
- }
-
- /**
- * Get objects contained in this group.
- *
- * @param string $subtype
- * @param int $limit
- * @param int $offset
- * @return mixed
- */
- public function getObjects($subtype="", $limit = 10, $offset = 0) {
- return get_objects_in_group($this->getGUID(), $subtype, 0, 0, "", $limit, $offset, false);
- }
-
- /**
- * For compatibility with Friendable
- */
- public function getFriendsObjects($subtype = "", $limit = 10, $offset = 0) {
- return get_objects_in_group($this->getGUID(), $subtype, 0, 0, "", $limit, $offset, false);
- }
-
- /**
- * For compatibility with Friendable
- */
- public function countObjects($subtype = "") {
- return get_objects_in_group($this->getGUID(), $subtype, 0, 0, "", 10, 0, true);
- }
-
-/**
- * End friendable compatibility block
- */
-
- /**
- * Get a list of group members.
- *
- * @param int $limit
- * @param int $offset
- * @return mixed
- */
- public function getMembers($limit = 10, $offset = 0, $count = false) {
- return get_group_members($this->getGUID(), $limit, $offset, 0 , $count);
- }
-
- /**
- * Returns whether the current group is public membership or not.
- * @return bool
- */
- public function isPublicMembership() {
- if ($this->membership == ACCESS_PUBLIC) {
- return true;
- }
-
- return false;
- }
-
- /**
- * Return whether a given user is a member of this group or not.
- *
- * @param ElggUser $user The user
- * @return bool
- */
- public function isMember($user = 0) {
- if (!($user instanceof ElggUser)) {
- $user = get_loggedin_user();
- }
- if (!($user instanceof ElggUser)) {
- return false;
- }
- return is_group_member($this->getGUID(), $user->getGUID());
- }
-
- /**
- * Join an elgg user to this group.
- *
- * @param ElggUser $user
- * @return bool
- */
- public function join(ElggUser $user) {
- return join_group($this->getGUID(), $user->getGUID());
- }
-
- /**
- * Remove a user from the group.
- *
- * @param ElggUser $user
- */
- public function leave(ElggUser $user) {
- return leave_group($this->getGUID(), $user->getGUID());
- }
-
- /**
- * Override the load function.
- * This function will ensure that all data is loaded (were possible), so
- * if only part of the ElggGroup is loaded, it'll load the rest.
- *
- * @param int $guid
- */
- protected function load($guid) {
- // Test to see if we have the generic stuff
- if (!parent::load($guid)) {
- return false;
- }
-
- // Check the type
- if ($this->attributes['type']!='group') {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class()));
- }
-
- // Load missing data
- $row = get_group_entity_as_row($guid);
- if (($row) && (!$this->isFullyLoaded())) {
- // If $row isn't a cached copy then increment the counter
- $this->attributes['tables_loaded'] ++;
- }
-
- // Now put these into the attributes array as core values
- $objarray = (array) $row;
- foreach($objarray as $key => $value) {
- $this->attributes[$key] = $value;
- }
-
- return true;
- }
-
- /**
- * Override the save function.
- */
- public function save() {
- // Save generic stuff
- if (!parent::save()) {
- return false;
- }
-
- // Now save specific stuff
- return create_group_entity($this->get('guid'), $this->get('name'), $this->get('description'));
- }
-
- // EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * Return an array of fields which can be exported.
- */
- public function getExportableValues() {
- return array_merge(parent::getExportableValues(), array(
- 'name',
- 'description',
- ));
- }
-}
/**
* Get the group entity.
*
- * @param int $guid
+ * @param int $guid GUID for a group
+ *
+ * @return array|false
+ * @access private
*/
function get_group_entity_as_row($guid) {
global $CONFIG;
@@ -324,12 +25,15 @@ function get_group_entity_as_row($guid) {
}
/**
- * Create or update the extras table for a given group.
+ * Create or update the entities table for a given group.
* Call create_entity first.
*
- * @param int $guid
- * @param string $name
- * @param string $description
+ * @param int $guid GUID
+ * @param string $name Name
+ * @param string $description Description
+ *
+ * @return bool
+ * @access private
*/
function create_group_entity($guid, $name, $description) {
global $CONFIG;
@@ -342,28 +46,32 @@ function create_group_entity($guid, $name, $description) {
if ($row) {
// Exists and you have access to it
- if ($exists = get_data_row("SELECT guid from {$CONFIG->dbprefix}groups_entity WHERE guid = {$guid}")) {
- $result = update_data("UPDATE {$CONFIG->dbprefix}groups_entity set name='$name', description='$description' where guid=$guid");
- if ($result!=false) {
+ $exists = get_data_row("SELECT guid from {$CONFIG->dbprefix}groups_entity WHERE guid = {$guid}");
+ if ($exists) {
+ $query = "UPDATE {$CONFIG->dbprefix}groups_entity set"
+ . " name='$name', description='$description' where guid=$guid";
+ $result = update_data($query);
+ if ($result != false) {
// Update succeeded, continue
$entity = get_entity($guid);
- if (trigger_elgg_event('update',$entity->type,$entity)) {
+ if (elgg_trigger_event('update', $entity->type, $entity)) {
return $guid;
} else {
$entity->delete();
- //delete_entity($guid);
}
}
} else {
// Update failed, attempt an insert.
- $result = insert_data("INSERT into {$CONFIG->dbprefix}groups_entity (guid, name, description) values ($guid, '$name','$description')");
- if ($result!==false) {
+ $query = "INSERT into {$CONFIG->dbprefix}groups_entity"
+ . " (guid, name, description) values ($guid, '$name', '$description')";
+
+ $result = insert_data($query);
+ if ($result !== false) {
$entity = get_entity($guid);
- if (trigger_elgg_event('create',$entity->type,$entity)) {
+ if (elgg_trigger_event('create', $entity->type, $entity)) {
return $guid;
} else {
$entity->delete();
- //delete_entity($guid);
}
}
}
@@ -372,28 +80,14 @@ function create_group_entity($guid, $name, $description) {
return false;
}
-
-/**
- * THIS FUNCTION IS DEPRECATED.
- *
- * Delete a group's extra data.
- *
- * @param int $guid The guid of the group
- * @return bool
- */
-function delete_group_entity($guid) {
- system_message(sprintf(elgg_echo('deprecatedfunction'), 'delete_user_entity'));
-
- // Always return that we have deleted one row in order to not break existing code.
- return 1;
-}
-
/**
* Add an object to the given group.
*
- * @param int $group_guid The group to add the object to.
+ * @param int $group_guid The group to add the object to.
* @param int $object_guid The guid of the elgg object (must be ElggObject or a child thereof)
+ *
* @return bool
+ * @throws InvalidClassException
*/
function add_object_to_group($group_guid, $object_guid) {
$group_guid = (int)$group_guid;
@@ -407,11 +101,13 @@ function add_object_to_group($group_guid, $object_guid) {
}
if (!($group instanceof ElggGroup)) {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $group_guid, 'ElggGroup'));
+ $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($group_guid, 'ElggGroup'));
+ throw new InvalidClassException($msg);
}
if (!($object instanceof ElggObject)) {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $object_guid, 'ElggObject'));
+ $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($object_guid, 'ElggObject'));
+ throw new InvalidClassException($msg);
}
$object->container_guid = $group_guid;
@@ -421,8 +117,11 @@ function add_object_to_group($group_guid, $object_guid) {
/**
* Remove an object from the given group.
*
- * @param int $group_guid The group to remove the object from
+ * @param int $group_guid The group to remove the object from
* @param int $object_guid The object to remove
+ *
+ * @return bool
+ * @throws InvalidClassException
*/
function remove_object_from_group($group_guid, $object_guid) {
$group_guid = (int)$group_guid;
@@ -436,11 +135,13 @@ function remove_object_from_group($group_guid, $object_guid) {
}
if (!($group instanceof ElggGroup)) {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $group_guid, 'ElggGroup'));
+ $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($group_guid, 'ElggGroup'));
+ throw new InvalidClassException($msg);
}
if (!($object instanceof ElggObject)) {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $object_guid, 'ElggObject'));
+ $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($object_guid, 'ElggObject'));
+ throw new InvalidClassException($msg);
}
$object->container_guid = $object->owner_guid;
@@ -448,301 +149,14 @@ function remove_object_from_group($group_guid, $object_guid) {
}
/**
- * Return an array of objects in a given container.
- * @see get_entities()
- *
- * @param int $group_guid The container (defaults to current page owner)
- * @param string $subtype The subtype
- * @param int $owner_guid Owner
- * @param int $site_guid The site
- * @param string $order_by Order
- * @param unknown_type $limit Limit on number of elements to return, by default 10.
- * @param unknown_type $offset Where to start, by default 0.
- * @param unknown_type $count Whether to return the entities or a count of them.
- */
-function get_objects_in_group($group_guid, $subtype = "", $owner_guid = 0, $site_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false) {
- global $CONFIG;
-
- if ($subtype === false || $subtype === null || $subtype === 0) {
- return false;
- }
-
- $subtype = get_subtype_id('object', $subtype);
-
- 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;
- }
-
- $container_guid = (int)$group_guid;
- if ($container_guid == 0) {
- $container_guid = page_owner();
- }
-
- $where = array();
-
- $where[] = "e.type='object'";
- if ($subtype!=="") {
- $where[] = "e.subtype=$subtype";
- }
- if ($owner_guid != "") {
- if (!is_array($owner_guid)) {
- $owner_guid = (int) $owner_guid;
- $where[] = "e.container_guid = '$owner_guid'";
- } else if (sizeof($owner_guid) > 0) {
- // Cast every element to the owner_guid array to int
- $owner_guid = array_map("sanitise_int", $owner_guid);
- $owner_guid = implode(",",$owner_guid);
- $where[] = "e.container_guid in ({$owner_guid})";
- }
- }
- if ($site_guid > 0) {
- $where[] = "e.site_guid = {$site_guid}";
- }
-
- if ($container_guid > 0) {
- $where[] = "e.container_guid = {$container_guid}";
- }
-
- if (!$count) {
- $query = "SELECT * from {$CONFIG->dbprefix}entities e join {$CONFIG->dbprefix}objects_entity o on e.guid=o.guid where ";
- } else {
- $query = "SELECT count(e.guid) as total from {$CONFIG->dbprefix}entities e join {$CONFIG->dbprefix}objects_entity o on e.guid=o.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";
-
- // 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;
- }
-}
-
-/**
- * Get all the entities from metadata from a group.
- *
- * @param int $group_guid The ID of the group.
- * @param mixed $meta_name
- * @param mixed $meta_value
- * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
- * @param string $entity_subtype The subtype of the entity.
- * @param int $limit
- * @param int $offset
- * @param string $order_by Optional ordering.
- * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites.
- * @param true|false $count If set to true, returns the total number of entities rather than a list. (Default: false)
- */
-function get_entities_from_metadata_groups($group_guid, $meta_name, $meta_value = "", $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) {
- global $CONFIG;
-
- $meta_n = get_metastring_id($meta_name);
- $meta_v = get_metastring_id($meta_value);
-
- $entity_type = sanitise_string($entity_type);
- $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
- $limit = (int)$limit;
- $offset = (int)$offset;
- if ($order_by == "") {
- $order_by = "e.time_created desc";
- }
- $order_by = sanitise_string($order_by);
- $site_guid = (int) $site_guid;
- if (is_array($owner_guid)) {
- foreach($owner_guid as $key => $guid) {
- $owner_guid[$key] = (int) $guid;
- }
- } else {
- $owner_guid = (int) $owner_guid;
- }
- if ($site_guid == 0) {
- $site_guid = $CONFIG->site_guid;
- }
-
- $container_guid = (int)$group_guid;
- if ($container_guid == 0) {
- $container_guid = page_owner();
- }
-
- //$access = get_access_list();
-
- $where = array();
-
- if ($entity_type!="") {
- $where[] = "e.type='$entity_type'";
- }
- if ($entity_subtype) {
- $where[] = "e.subtype=$entity_subtype";
- }
- if ($meta_name!="") {
- $where[] = "m.name_id='$meta_n'";
- }
- if ($meta_value!="") {
- $where[] = "m.value_id='$meta_v'";
- }
- if ($site_guid > 0) {
- $where[] = "e.site_guid = {$site_guid}";
- }
- if ($container_guid > 0) {
- $where[] = "e.container_guid = {$container_guid}";
- }
-
- if (is_array($owner_guid)) {
- $where[] = "e.container_guid in (".implode(",",$owner_guid).")";
- } else if ($owner_guid > 0)
- $where[] = "e.container_guid = {$owner_guid}";
-
- if (!$count) {
- $query = "SELECT distinct e.* ";
- } else {
- $query = "SELECT count(e.guid) as total ";
- }
-
- $query .= "from {$CONFIG->dbprefix}entities e JOIN {$CONFIG->dbprefix}metadata m on e.guid = m.entity_guid join {$CONFIG->dbprefix}objects_entity o on e.guid = o.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 limit $offset, $limit"; // Add order and limit
- return get_data($query, "entity_row_to_elggstar");
- } else {
- if ($row = get_data_row($query)) {
- return $row->total;
- }
- }
- return false;
-}
-
-/**
- * As get_entities_from_metadata_groups() but with multiple entities.
- *
- * @param int $group_guid The ID of the group.
- * @param array $meta_array Array of 'name' => 'value' pairs
- * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
- * @param string $entity_subtype The subtype of the entity.
- * @param int $limit
- * @param int $offset
- * @param string $order_by Optional ordering.
- * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites.
- * @param true|false $count If set to true, returns the total number of entities rather than a list. (Default: false)
- * @return int|array List of ElggEntities, or the total number if count is set to false
- */
-function get_entities_from_metadata_groups_multi($group_guid, $meta_array, $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0, $count = false) {
- global $CONFIG;
-
- if (!is_array($meta_array) || sizeof($meta_array) == 0) {
- return false;
- }
-
- $where = array();
-
- $mindex = 1;
- $join = "";
- foreach($meta_array as $meta_name => $meta_value) {
- $meta_n = get_metastring_id($meta_name);
- $meta_v = get_metastring_id($meta_value);
- $join .= " JOIN {$CONFIG->dbprefix}metadata m{$mindex} on e.guid = m{$mindex}.entity_guid join {$CONFIG->dbprefix}objects_entity o on e.guid = o.guid ";
- if ($meta_name!="") {
- $where[] = "m{$mindex}.name_id='$meta_n'";
- }
-
- if ($meta_value!="") {
- $where[] = "m{$mindex}.value_id='$meta_v'";
- }
-
- $mindex++;
- }
-
- $entity_type = sanitise_string($entity_type);
- $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
- $limit = (int)$limit;
- $offset = (int)$offset;
- if ($order_by == "") {
- $order_by = "e.time_created desc";
- }
- $order_by = sanitise_string($order_by);
- $owner_guid = (int) $owner_guid;
-
- $site_guid = (int) $site_guid;
- if ($site_guid == 0) {
- $site_guid = $CONFIG->site_guid;
- }
-
- //$access = get_access_list();
-
- if ($entity_type!="") {
- $where[] = "e.type = '{$entity_type}'";
- }
-
- if ($entity_subtype) {
- $where[] = "e.subtype = {$entity_subtype}";
- }
-
- if ($site_guid > 0) {
- $where[] = "e.site_guid = {$site_guid}";
- }
-
- if ($owner_guid > 0) {
- $where[] = "e.owner_guid = {$owner_guid}";
- }
-
- if ($container_guid > 0) {
- $where[] = "e.container_guid = {$container_guid}";
- }
-
- if ($count) {
- $query = "SELECT count(e.guid) as total ";
- } else {
- $query = "SELECT distinct e.* ";
- }
-
- $query .= " from {$CONFIG->dbprefix}entities e {$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 limit $offset, $limit"; // Add order and limit
- return get_data($query, "entity_row_to_elggstar");
- } else {
- if ($count = get_data_row($query)) {
- return $count->total;
- }
- }
- return false;
-}
-
-/**
* Return a list of this group's members.
*
- * @param int $group_guid The ID of the container/group.
- * @param int $limit The limit
- * @param int $offset The offset
- * @param int $site_guid The site
- * @param bool $count Return the users (false) or the count of them (true)
+ * @param int $group_guid The ID of the container/group.
+ * @param int $limit The limit
+ * @param int $offset The offset
+ * @param int $site_guid The site
+ * @param bool $count Return the users (false) or the count of them (true)
+ *
* @return mixed
*/
function get_group_members($group_guid, $limit = 10, $offset = 0, $site_guid = 0, $count = false) {
@@ -756,7 +170,7 @@ function get_group_members($group_guid, $limit = 10, $offset = 0, $site_guid = 0
'relationship' => 'member',
'relationship_guid' => $group_guid,
'inverse_relationship' => TRUE,
- 'types' => 'user',
+ 'type' => 'user',
'limit' => $limit,
'offset' => $offset,
'count' => $count,
@@ -768,7 +182,8 @@ function get_group_members($group_guid, $limit = 10, $offset = 0, $site_guid = 0
* Return whether a given user is a member of the group or not.
*
* @param int $group_guid The group ID
- * @param int $user_guid The user guid
+ * @param int $user_guid The user guid
+ *
* @return bool
*/
function is_group_member($group_guid, $user_guid) {
@@ -783,12 +198,19 @@ function is_group_member($group_guid, $user_guid) {
/**
* Join a user to a group.
*
- * @param int $group_guid The group.
- * @param int $user_guid The user.
+ * @param int $group_guid The group GUID.
+ * @param int $user_guid The user GUID.
+ *
+ * @return bool
*/
function join_group($group_guid, $user_guid) {
$result = add_entity_relationship($user_guid, 'member', $group_guid);
- trigger_elgg_event('join', 'group', array('group' => get_entity($group_guid), 'user' => get_entity($user_guid)));
+
+ if ($result) {
+ $params = array('group' => get_entity($group_guid), 'user' => get_entity($user_guid));
+ elgg_trigger_event('join', 'group', $params);
+ }
+
return $result;
}
@@ -796,11 +218,15 @@ function join_group($group_guid, $user_guid) {
* Remove a user from a group.
*
* @param int $group_guid The group.
- * @param int $user_guid The user.
+ * @param int $user_guid The user.
+ *
+ * @return bool
*/
function leave_group($group_guid, $user_guid) {
// event needs to be triggered while user is still member of group to have access to group acl
- trigger_elgg_event('leave', 'group', array('group' => get_entity($group_guid), 'user' => get_entity($user_guid)));
+ $params = array('group' => get_entity($group_guid), 'user' => get_entity($user_guid));
+
+ elgg_trigger_event('leave', 'group', $params);
$result = remove_entity_relationship($user_guid, 'member', $group_guid);
return $result;
}
@@ -808,58 +234,73 @@ function leave_group($group_guid, $user_guid) {
/**
* Return all groups a user is a member of.
*
- * @param unknown_type $user_guid
+ * @param int $user_guid GUID of user
+ *
+ * @return array|false
*/
function get_users_membership($user_guid) {
- return elgg_get_entities_from_relationship(array('relationship' => 'member', 'relationship_guid' => $user_guid, 'inverse_relationship' => FALSE));
+ $options = array(
+ 'type' => 'group',
+ 'relationship' => 'member',
+ 'relationship_guid' => $user_guid,
+ 'inverse_relationship' => false,
+ 'limit' => false,
+ );
+ return elgg_get_entities_from_relationship($options);
}
/**
- * Checks access to a group.
+ * May the current user access item(s) on this page? If the page owner is a group,
+ * membership, visibility, and logged in status are taken into account.
+ *
+ * @param boolean $forward If set to true (default), will forward the page;
+ * if set to false, will return true or false.
*
- * @param boolean $forward If set to true (default), will forward the page; if set to false, will return true or false.
- * @return true|false If $forward is set to false.
+ * @return bool If $forward is set to false.
*/
function group_gatekeeper($forward = true) {
- $allowed = true;
- $url = '';
-
- if ($group = page_owner_entity()) {
- if ($group instanceof ElggGroup) {
- $url = $group->getURL();
- if (
- ((!isloggedin()) && (!$group->isPublicMembership())) ||
- ((!$group->isMember(get_loggedin_user()) && (!$group->isPublicMembership())))
- ) {
- $allowed = false;
- }
- // Admin override
- if (isadminloggedin()) {
- $allowed = true;
- }
- }
+ $page_owner_guid = elgg_get_page_owner_guid();
+ if (!$page_owner_guid) {
+ return true;
}
+ $visibility = ElggGroupItemVisibility::factory($page_owner_guid);
- if ($forward && $allowed == false) {
- register_error(elgg_echo('membershiprequired'));
- forward($url);
- exit;
+ if (!$visibility->shouldHideItems) {
+ return true;
}
+ if ($forward) {
+ // only forward to group if user can see it
+ $group = get_entity($page_owner_guid);
+ $forward_url = $group ? $group->getURL() : '';
- return $allowed;
+ if (!elgg_is_logged_in()) {
+ $_SESSION['last_forward_from'] = current_page_url();
+ $forward_reason = 'login';
+ } else {
+ $forward_reason = 'member';
+ }
+
+ register_error(elgg_echo($visibility->reasonHidden));
+ forward($forward_url, $forward_reason);
+ }
+
+ return false;
}
/**
- * Manages group tool options
+ * Adds a group tool option
*
- * @param string $name Name of the group tool option
- * @param string $label Used for the group edit form
- * @param boolean $default_on True if this option should be active by default
+ * @see remove_group_tool_option().
*
- **/
-
-function add_group_tool_option($name,$label,$default_on=true) {
+ * @param string $name Name of the group tool option
+ * @param string $label Used for the group edit form
+ * @param bool $default_on True if this option should be active by default
+ *
+ * @return void
+ * @since 1.5.0
+ */
+function add_group_tool_option($name, $label, $default_on = true) {
global $CONFIG;
if (!isset($CONFIG->group_tool_options)) {
@@ -876,104 +317,25 @@ function add_group_tool_option($name,$label,$default_on=true) {
}
/**
- * Searches for a group based on a complete or partial name or description
+ * Removes a group tool option based on name
*
- * @param string $criteria The partial or full name or description
- * @param int $limit Limit of the search.
- * @param int $offset Offset.
- * @param string $order_by The order.
- * @param boolean $count Whether to return the count of results or just the results.
- * @deprecated 1.7
+ * @see add_group_tool_option()
+ *
+ * @param string $name Name of the group tool option
+ *
+ * @return void
+ * @since 1.7.5
*/
-function search_for_group($criteria, $limit = 10, $offset = 0, $order_by = "", $count = false) {
- elgg_deprecated_notice('search_for_group() was deprecated by new search plugin.', 1.7);
+function remove_group_tool_option($name) {
global $CONFIG;
- $criteria = sanitise_string($criteria);
- $limit = (int)$limit;
- $offset = (int)$offset;
- $order_by = sanitise_string($order_by);
-
- $access = get_access_sql_suffix("e");
-
- if ($order_by == "") {
- $order_by = "e.time_created desc";
- }
-
- if ($count) {
- $query = "SELECT count(e.guid) as total ";
- } else {
- $query = "SELECT e.* ";
- }
- $query .= "from {$CONFIG->dbprefix}entities e join {$CONFIG->dbprefix}groups_entity g on e.guid=g.guid where ";
- // $query .= " match(u.name,u.username) against ('$criteria') ";
- $query .= "(g.name like \"%{$criteria}%\" or g.description like \"%{$criteria}%\")";
- $query .= " and $access";
-
- if (!$count) {
- $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
- return get_data($query, "entity_row_to_elggstar");
- } else {
- if ($count = get_data_row($query)) {
- return $count->total;
- }
+ if (!isset($CONFIG->group_tool_options)) {
+ return;
}
- return false;
-}
-
-/**
- * Returns a formatted list of groups suitable for injecting into search.
- * @deprecated 1.7
- */
-function search_list_groups_by_name($hook, $user, $returnvalue, $tag) {
- elgg_deprecated_notice('search_list_groups_by_name() was deprecated by new search plugin', 1.7);
- // Change this to set the number of groups that display on the search page
- $threshold = 4;
- $object = get_input('object');
-
- if (!get_input('offset') && (empty($object) || $object == 'group')) {
- if ($groups = search_for_group($tag,$threshold)) {
- $countgroups = search_for_group($tag,0,0,"",true);
-
- $return = elgg_view('group/search/startblurb',array('count' => $countgroups, 'tag' => $tag));
- foreach($groups as $group) {
- $return .= elgg_view_entity($group);
- }
- $return .= elgg_view('group/search/finishblurb',array('count' => $countgroups, 'threshold' => $threshold, 'tag' => $tag));
- return $return;
+ foreach ($CONFIG->group_tool_options as $i => $option) {
+ if ($option->name == $name) {
+ unset($CONFIG->group_tool_options[$i]);
}
}
}
-
-/**
- * Displays a list of group objects that have been searched for.
- *
- * @see elgg_view_entity_list
- *
- * @param string $tag Search criteria
- * @param int $limit The number of entities to display on a page
- * @return string The list in a form suitable to display
- * @deprecated 1.7
- */
-function list_group_search($tag, $limit = 10) {
- elgg_deprecated_notice('list_group_search() was deprecated by new search plugin.', 1.7);
- $offset = (int) get_input('offset');
- $limit = (int) $limit;
- $count = (int) search_for_group($tag, 10, 0, '', true);
- $entities = search_for_group($tag, $limit, $offset);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, false);
-
-}
-
-/**
- * Performs initialisation functions for groups
- *
- */
-function group_init() {
- // Register an entity type
- register_entity_type('group','');
-}
-
-register_elgg_event_handler('init','system','group_init');
diff --git a/engine/lib/input.php b/engine/lib/input.php
index e5daa70ea..80b0b8766 100644
--- a/engine/lib/input.php
+++ b/engine/lib/input.php
@@ -3,51 +3,56 @@
* Parameter input functions.
* This file contains functions for getting input from get/post variables.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Input
*/
/**
- * Get some input from variables passed on the GET or POST line.
+ * Get some input from variables passed submitted through GET or POST.
+ *
+ * If using any data obtained from get_input() in a web page, please be aware that
+ * it is a possible vector for a reflected XSS attack. If you are expecting an
+ * integer, cast it to an int. If it is a string, escape quotes.
*
* Note: this function does not handle nested arrays (ex: form input of param[m][n])
* because of the filtering done in htmlawed from the filter_tags call.
+ * @todo Is this ^ still true?
+ *
+ * @param string $variable The variable name we want.
+ * @param mixed $default A default value for the variable if it is not found.
+ * @param bool $filter_result If true, then the result is filtered for bad tags.
*
- * @param $variable string The variable we want to return.
- * @param $default mixed A default value for the variable if it is not found.
- * @param $filter_result If true then the result is filtered for bad tags.
+ * @return mixed
*/
function get_input($variable, $default = NULL, $filter_result = TRUE) {
global $CONFIG;
+ $result = $default;
+
+ elgg_push_context('input');
+
if (isset($CONFIG->input[$variable])) {
- $var = $CONFIG->input[$variable];
+ $result = $CONFIG->input[$variable];
if ($filter_result) {
- $var = filter_tags($var);
+ $result = filter_tags($result);
}
-
- return $var;
- }
-
- if (isset($_REQUEST[$variable])) {
+ } elseif (isset($_REQUEST[$variable])) {
if (is_array($_REQUEST[$variable])) {
- $var = $_REQUEST[$variable];
+ $result = $_REQUEST[$variable];
} else {
- $var = trim($_REQUEST[$variable]);
+ $result = trim($_REQUEST[$variable]);
}
if ($filter_result) {
- $var = filter_tags($var);
+ $result = filter_tags($result);
}
-
- return $var;
}
- return $default;
+ elgg_pop_context();
+
+ return $result;
}
/**
@@ -55,8 +60,10 @@ function get_input($variable, $default = NULL, $filter_result = TRUE) {
*
* Note: this function does not handle nested arrays (ex: form input of param[m][n])
*
- * @param string $variable The name of the variable
- * @param string $value The value of the variable
+ * @param string $variable The name of the variable
+ * @param string|string[] $value The value of the variable
+ *
+ * @return void
*/
function set_input($variable, $value) {
global $CONFIG;
@@ -65,10 +72,7 @@ function set_input($variable, $value) {
}
if (is_array($value)) {
- foreach ($value as $key => $val) {
- $value[$key] = trim($val);
- }
-
+ array_walk_recursive($value, create_function('&$v, $k', '$v = trim($v);'));
$CONFIG->input[trim($variable)] = $value;
} else {
$CONFIG->input[trim($variable)] = trim($value);
@@ -79,46 +83,171 @@ function set_input($variable, $value) {
* Filter tags from a given string based on registered hooks.
*
* @param mixed $var Anything that does not include an object (strings, ints, arrays)
- * This includes multi-dimensional arrays.
+ * This includes multi-dimensional arrays.
+ *
* @return mixed The filtered result - everything will be strings
*/
function filter_tags($var) {
- return trigger_plugin_hook('validate', 'input', null, $var);
+ return elgg_trigger_plugin_hook('validate', 'input', null, $var);
+}
+
+/**
+ * Validates an email address.
+ *
+ * @param string $address Email address.
+ *
+ * @return bool
+ */
+function is_email_address($address) {
+ return filter_var($address, FILTER_VALIDATE_EMAIL) === $address;
+}
+
+/**
+ * Load all the REQUEST variables into the sticky form cache
+ *
+ * Call this from an action when you want all your submitted variables
+ * available if the submission fails validation and is sent back to the form
+ *
+ * @param string $form_name Name of the sticky form
+ *
+ * @return void
+ * @link http://docs.elgg.org/Tutorials/UI/StickyForms
+ * @since 1.8.0
+ */
+function elgg_make_sticky_form($form_name) {
+
+ elgg_clear_sticky_form($form_name);
+
+ if (!isset($_SESSION['sticky_forms'])) {
+ $_SESSION['sticky_forms'] = array();
+ }
+ $_SESSION['sticky_forms'][$form_name] = array();
+
+ foreach ($_REQUEST as $key => $var) {
+ // will go through XSS filtering on the get function
+ $_SESSION['sticky_forms'][$form_name][$key] = $var;
+ }
+}
+
+/**
+ * Clear the sticky form cache
+ *
+ * Call this if validation is successful in the action handler or
+ * when they sticky values have been used to repopulate the form
+ * after a validation error.
+ *
+ * @param string $form_name Form namespace
+ *
+ * @return void
+ * @link http://docs.elgg.org/Tutorials/UI/StickyForms
+ * @since 1.8.0
+ */
+function elgg_clear_sticky_form($form_name) {
+ unset($_SESSION['sticky_forms'][$form_name]);
+}
+
+/**
+ * Has this form been made sticky?
+ *
+ * @param string $form_name Form namespace
+ *
+ * @return boolean
+ * @link http://docs.elgg.org/Tutorials/UI/StickyForms
+ * @since 1.8.0
+ */
+function elgg_is_sticky_form($form_name) {
+ return isset($_SESSION['sticky_forms'][$form_name]);
+}
+
+/**
+ * Get a specific sticky variable
+ *
+ * @param string $form_name The name of the form
+ * @param string $variable The name of the variable
+ * @param mixed $default Default value if the variable does not exist in sticky cache
+ * @param boolean $filter_result Filter for bad input if true
+ *
+ * @return mixed
+ *
+ * @todo should this filter the default value?
+ * @link http://docs.elgg.org/Tutorials/UI/StickyForms
+ * @since 1.8.0
+ */
+function elgg_get_sticky_value($form_name, $variable = '', $default = NULL, $filter_result = true) {
+ if (isset($_SESSION['sticky_forms'][$form_name][$variable])) {
+ $value = $_SESSION['sticky_forms'][$form_name][$variable];
+ if ($filter_result) {
+ // XSS filter result
+ $value = filter_tags($value);
+ }
+ return $value;
+ }
+ return $default;
}
/**
- * Sanitise file paths for input, ensuring that they begin and end with slashes etc.
+ * Get all the values in a sticky form in an array
*
- * @param string $path The path
- * @return string
+ * @param string $form_name The name of the form
+ * @param bool $filter_result Filter for bad input if true
+ *
+ * @return array
+ * @since 1.8.0
*/
-function sanitise_filepath($path) {
- // Convert to correct UNIX paths
- $path = str_replace('\\', '/', $path);
+function elgg_get_sticky_values($form_name, $filter_result = true) {
+ if (!isset($_SESSION['sticky_forms'][$form_name])) {
+ return array();
+ }
- // Sort trailing slash
- $path = trim($path);
- // rtrim defaults plus /
- $path = rtrim($path, " \n\t\0\x0B/");
- $path = $path . "/";
+ $values = $_SESSION['sticky_forms'][$form_name];
+ if ($filter_result) {
+ foreach ($values as $key => $value) {
+ // XSS filter result
+ $values[$key] = filter_tags($value);
+ }
+ }
+ return $values;
+}
- return $path;
+/**
+ * Clear a specific sticky variable
+ *
+ * @param string $form_name The name of the form
+ * @param string $variable The name of the variable to clear
+ *
+ * @return void
+ * @link http://docs.elgg.org/Tutorials/UI/StickyForms
+ * @since 1.8.0
+ */
+function elgg_clear_sticky_value($form_name, $variable) {
+ unset($_SESSION['sticky_forms'][$form_name][$variable]);
}
/**
* Page handler for autocomplete endpoint.
*
- * @param $page
- * @return unknown_type
+ * @todo split this into functions/objects, this is way too big
+ *
+ * /livesearch?q=<query>
+ *
+ * Other options include:
+ * match_on string all or array(groups|users|friends)
+ * match_owner int 0/1
+ * limit int default is 10
+ *
+ * @param array $page
+ * @return string JSON string is returned and then exit
+ * @access private
*/
function input_livesearch_page_handler($page) {
global $CONFIG;
+
// only return results to logged in users.
- if (!$user = get_loggedin_user()) {
+ if (!$user = elgg_get_logged_in_user_entity()) {
exit;
}
- if (!$q = get_input('q')) {
+ if (!$q = get_input('term', get_input('q'))) {
exit;
}
@@ -128,134 +257,203 @@ function input_livesearch_page_handler($page) {
$q = str_replace(array('_', '%'), array('\_', '\%'), $q);
$match_on = get_input('match_on', 'all');
- if ($match_on == 'all' || $match_on[0] == 'all') {
- $match_on = array('users', 'groups');
- }
if (!is_array($match_on)) {
$match_on = array($match_on);
}
+ // all = users and groups
+ if (in_array('all', $match_on)) {
+ $match_on = array('users', 'groups');
+ }
+
if (get_input('match_owner', false)) {
- $owner_guid = $user->getGUID();
$owner_where = 'AND e.owner_guid = ' . $user->getGUID();
} else {
- $owner_guid = null;
$owner_where = '';
}
- $limit = get_input('limit', 10);
+ $limit = sanitise_int(get_input('limit', 10));
// grab a list of entities and send them in json.
$results = array();
- foreach ($match_on as $type) {
- switch ($type) {
- case 'all':
- // only need to pull up title from objects.
-
- if (!$entities = elgg_get_entities(array('owner_guid' => $owner_guid, 'limit' => $limit)) AND is_array($entities)) {
- $results = array_merge($results, $entities);
- }
- break;
-
+ foreach ($match_on as $match_type) {
+ switch ($match_type) {
case 'users':
$query = "SELECT * FROM {$CONFIG->dbprefix}users_entity as ue, {$CONFIG->dbprefix}entities as e
WHERE e.guid = ue.guid
AND e.enabled = 'yes'
AND ue.banned = 'no'
- AND (ue.name LIKE '$q%' OR ue.username LIKE '$q%')
+ AND (ue.name LIKE '$q%' OR ue.name LIKE '% $q%' OR ue.username LIKE '$q%')
LIMIT $limit
";
if ($entities = get_data($query)) {
foreach ($entities as $entity) {
- $json = json_encode(array(
+ // @todo use elgg_get_entities (don't query in a loop!)
+ $entity = get_entity($entity->guid);
+ /* @var ElggUser $entity */
+ if (!$entity) {
+ continue;
+ }
+
+ if (in_array('groups', $match_on)) {
+ $value = $entity->guid;
+ } else {
+ $value = $entity->username;
+ }
+
+ $output = elgg_view_list_item($entity, array(
+ 'use_hover' => false,
+ 'class' => 'elgg-autocomplete-item',
+ ));
+
+ $icon = elgg_view_entity_icon($entity, 'tiny', array(
+ 'use_hover' => false,
+ ));
+
+ $result = array(
'type' => 'user',
'name' => $entity->name,
'desc' => $entity->username,
- 'icon' => '<img class="livesearch_icon" src="' . get_entity($entity->guid)->getIcon('tiny') . '" />',
- 'guid' => $entity->guid
- ));
- $results[$entity->name . rand(1,100)] = $json;
+ 'guid' => $entity->guid,
+ 'label' => $output,
+ 'value' => $value,
+ 'icon' => $icon,
+ 'url' => $entity->getURL(),
+ );
+ $results[$entity->name . rand(1, 100)] = $result;
}
}
break;
case 'groups':
// don't return results if groups aren't enabled.
- if (!is_plugin_enabled('groups')) {
+ if (!elgg_is_active_plugin('groups')) {
continue;
}
$query = "SELECT * FROM {$CONFIG->dbprefix}groups_entity as ge, {$CONFIG->dbprefix}entities as e
WHERE e.guid = ge.guid
AND e.enabled = 'yes'
$owner_where
- AND (ge.name LIKE '$q%' OR ge.description LIKE '%$q%')
+ AND (ge.name LIKE '$q%' OR ge.name LIKE '% $q%' OR ge.description LIKE '% $q%')
LIMIT $limit
";
if ($entities = get_data($query)) {
foreach ($entities as $entity) {
- $json = json_encode(array(
+ // @todo use elgg_get_entities (don't query in a loop!)
+ $entity = get_entity($entity->guid);
+ /* @var ElggGroup $entity */
+ if (!$entity) {
+ continue;
+ }
+
+ $output = elgg_view_list_item($entity, array(
+ 'use_hover' => false,
+ 'class' => 'elgg-autocomplete-item',
+ ));
+
+ $icon = elgg_view_entity_icon($entity, 'tiny', array(
+ 'use_hover' => false,
+ ));
+
+ $result = array(
'type' => 'group',
'name' => $entity->name,
'desc' => strip_tags($entity->description),
- 'icon' => '<img class="livesearch_icon" src="' . get_entity($entity->guid)->getIcon('tiny') . '" />',
- 'guid' => $entity->guid
- ));
- //$results[$entity->name . rand(1,100)] = "$json|{$entity->guid}";
- $results[$entity->name . rand(1,100)] = $json;
+ 'guid' => $entity->guid,
+ 'label' => $output,
+ 'value' => $entity->guid,
+ 'icon' => $icon,
+ 'url' => $entity->getURL(),
+ );
+
+ $results[$entity->name . rand(1, 100)] = $result;
}
}
break;
case 'friends':
- $access = get_access_sql_suffix();
- $query = "SELECT * FROM {$CONFIG->dbprefix}users_entity as ue, {$CONFIG->dbprefix}entity_relationships as er, {$CONFIG->dbprefix}entities as e
+ $query = "SELECT * FROM
+ {$CONFIG->dbprefix}users_entity as ue,
+ {$CONFIG->dbprefix}entity_relationships as er,
+ {$CONFIG->dbprefix}entities as e
WHERE er.relationship = 'friend'
AND er.guid_one = {$user->getGUID()}
AND er.guid_two = ue.guid
AND e.guid = ue.guid
AND e.enabled = 'yes'
AND ue.banned = 'no'
- AND (ue.name LIKE '$q%' OR ue.username LIKE '$q%')
+ AND (ue.name LIKE '$q%' OR ue.name LIKE '% $q%' OR ue.username LIKE '$q%')
LIMIT $limit
";
if ($entities = get_data($query)) {
foreach ($entities as $entity) {
- $json = json_encode(array(
+ // @todo use elgg_get_entities (don't query in a loop!)
+ $entity = get_entity($entity->guid);
+ /* @var ElggUser $entity */
+ if (!$entity) {
+ continue;
+ }
+
+ $output = elgg_view_list_item($entity, array(
+ 'use_hover' => false,
+ 'class' => 'elgg-autocomplete-item',
+ ));
+
+ $icon = elgg_view_entity_icon($entity, 'tiny', array(
+ 'use_hover' => false,
+ ));
+
+ $result = array(
'type' => 'user',
'name' => $entity->name,
'desc' => $entity->username,
- 'icon' => '<img class="livesearch_icon" src="' . get_entity($entity->guid)->getIcon('tiny') . '" />',
- 'guid' => $entity->guid
- ));
- $results[$entity->name . rand(1,100)] = $json;
+ 'guid' => $entity->guid,
+ 'label' => $output,
+ 'value' => $entity->username,
+ 'icon' => $icon,
+ 'url' => $entity->getURL(),
+ );
+ $results[$entity->name . rand(1, 100)] = $result;
}
}
break;
default:
- // arbitrary subtype.
- //@todo you cannot specify a subtype without a type.
- // did this ever work?
- elgg_get_entities(array('subtype' => $type, 'owner_guid' => $owner_guid));
+ header("HTTP/1.0 400 Bad Request", true);
+ echo "livesearch: unknown match_on of $match_type";
+ exit;
break;
}
}
ksort($results);
- echo implode($results, "\n");
+ header("Content-Type: application/json");
+ echo json_encode(array_values($results));
exit;
}
-
+/**
+ * Register input functions and sanitize input
+ *
+ * @return void
+ * @access private
+ */
function input_init() {
// register an endpoint for live search / autocomplete.
- register_page_handler('livesearch', 'input_livesearch_page_handler');
+ elgg_register_page_handler('livesearch', 'input_livesearch_page_handler');
+
+ if (ini_get_bool('magic_quotes_gpc')) {
- if (ini_get_bool('magic_quotes_gpc') ) {
- //do keys as well, cos array_map ignores them
+ /**
+ * do keys as well, cos array_map ignores them
+ *
+ * @param array $array Array of values
+ *
+ * @return array Sanitized array
+ */
function stripslashes_arraykeys($array) {
if (is_array($array)) {
$array2 = array();
@@ -272,6 +470,13 @@ function input_init() {
}
}
+ /**
+ * Strip slashes on everything
+ *
+ * @param mixed $value The value to remove slashes from
+ *
+ * @return mixed
+ */
function stripslashes_deep($value) {
if (is_array($value)) {
$value = stripslashes_arraykeys($value);
@@ -312,4 +517,4 @@ function input_init() {
}
}
-register_elgg_event_handler('init','system','input_init');
+elgg_register_event_handler('init', 'system', 'input_init');
diff --git a/engine/lib/install.php b/engine/lib/install.php
deleted file mode 100644
index e2b0c5251..000000000
--- a/engine/lib/install.php
+++ /dev/null
@@ -1,140 +0,0 @@
-<?php
-
-/**
- * Elgg installation
- * Various functions to assist with installing and upgrading the system
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
- */
-
-/**
- * Check that the installed version of PHP meets the minimum requirements (currently 5.2 or greater).
- *
- * @return bool
- */
-function php_check_version() {
- if (version_compare(phpversion(), '5.1.2', '>=')) {
- return true;
- }
-
- return false;
-}
-
-/**
- * Validate the platform Elgg is being installed on.
- *
- * @throws ConfigurationException if the validation fails.
- * @return bool
- */
-function validate_platform() {
- // Get database version
- if (!db_check_version()) {
- throw new ConfigurationException(elgg_echo('ConfigurationException:BadDatabaseVersion'));
- }
-
- // Now check PHP
- if (!php_check_version()) {
- throw new ConfigurationException(elgg_echo('ConfigurationException:BadPHPVersion'));
- }
-
- // TODO: Consider checking for installed modules etc
- return true;
-}
-
-/**
- * Confirm the settings for the database
- *
- * @param string $user
- * @param string $password
- * @param string $dbname
- * @param string $host
- * @return bool
- */
-function db_check_settings($user, $password, $dbname, $host) {
- $mysql_dblink = mysql_connect($host, $user, $password, true);
- if ($mysql_dblink == FALSE) {
- return $FALSE;
- }
-
- $result = mysql_select_db($dbname, $mysql_dblink);
-
- mysql_close($mysql_dblink);
-
- return $result;
-}
-
-
-/**
- * Returns whether or not the database has been installed
- *
- * @return true|false Whether the database has been installed
- */
-function is_db_installed() {
- global $CONFIG;
-
- if (isset($CONFIG->db_installed)) {
- return $CONFIG->db_installed;
- }
-
- if ($dblink = get_db_link('read')) {
- mysql_query("select name from {$CONFIG->dbprefix}datalists limit 1", $dblink);
- if (mysql_errno($dblink) > 0) {
- return false;
- }
- } else {
- return false;
- }
-
- // Set flag if db is installed (if false then we want to check every time)
- $CONFIG->db_installed = true;
-
- return true;
-}
-
-/**
- * Returns whether or not other settings have been set
- *
- * @return true|false Whether or not the rest of the installation has been followed through with
- */
-function is_installed() {
- global $CONFIG;
- return datalist_get('installed');
-}
-
-/**
- * Copy and create a new settings.php from settings.example.php, substituting the variables in
- * $vars where appropriate.
- *
- * $vars is an associate array of $key => $value, where $key is the variable text you wish to substitute (eg
- * CONFIG_DBNAME will replace {{CONFIG_DBNAME}} in the settings file.
- *
- * @param array $vars The array of vars
- * @param string $in_file Optional input file (if not settings.example.php)
- * @return string The file containing substitutions.
- */
-function create_settings(array $vars, $in_file="engine/settings.example.php") {
- $file = file_get_contents($in_file);
-
- if (!$file) {
- return false;
- }
-
- foreach ($vars as $k => $v) {
- $file = str_replace("{{".$k."}}", $v, $file);
- }
-
- return $file;
-}
-
-/**
- * Initialisation for installation functions
- *
- */
-function install_init() {
- register_action("systemsettings/install",true);
-}
-
-register_elgg_event_handler("boot","system","install_init"); \ No newline at end of file
diff --git a/engine/lib/languages.php b/engine/lib/languages.php
index 98283f141..61ba91ddb 100644
--- a/engine/lib/languages.php
+++ b/engine/lib/languages.php
@@ -3,13 +3,70 @@
* Elgg language module
* Functions to manage language and translations.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Languages
*/
/**
+ * Given a message key, returns an appropriately translated full-text string
+ *
+ * @param string $message_key The short message code
+ * @param array $args An array of arguments to pass through vsprintf().
+ * @param string $language Optionally, the standard language code
+ * (defaults to site/user default, then English)
+ *
+ * @return string Either the translated string, the English string,
+ * or the original language string.
+ */
+function elgg_echo($message_key, $args = array(), $language = "") {
+ global $CONFIG;
+
+ static $CURRENT_LANGUAGE;
+
+ // old param order is deprecated
+ if (!is_array($args)) {
+ elgg_deprecated_notice(
+ 'As of Elgg 1.8, the 2nd arg to elgg_echo() is an array of string replacements and the 3rd arg is the language.',
+ 1.8
+ );
+
+ $language = $args;
+ $args = array();
+ }
+
+ if (!isset($CONFIG->translations)) {
+ // this means we probably had an exception before translations were initialized
+ register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/");
+ }
+
+ if (!$CURRENT_LANGUAGE) {
+ $CURRENT_LANGUAGE = get_language();
+ }
+ if (!$language) {
+ $language = $CURRENT_LANGUAGE;
+ }
+
+ if (isset($CONFIG->translations[$language][$message_key])) {
+ $string = $CONFIG->translations[$language][$message_key];
+ } else if (isset($CONFIG->translations["en"][$message_key])) {
+ $string = $CONFIG->translations["en"][$message_key];
+ $lang = $CONFIG->translations["en"][$language];
+ elgg_log(sprintf('Missing %s translation for "%s" language key', $lang, $message_key), 'NOTICE');
+ } else {
+ $string = $message_key;
+ elgg_log(sprintf('Missing English translation for "%s" language key', $message_key), 'NOTICE');
+ }
+
+ // only pass through if we have arguments to allow backward compatibility
+ // with manual sprintf() calls.
+ if ($args) {
+ $string = vsprintf($string, $args);
+ }
+
+ return $string;
+}
+
+/**
* Add a translation.
*
* Translations are arrays in the Zend Translation array format, eg:
@@ -17,9 +74,10 @@
* $english = array('message1' => 'message1', 'message2' => 'message2');
* $german = array('message1' => 'Nachricht1','message2' => 'Nachricht2');
*
- * @param string $country_code Standard country code (eg 'en', 'nl', 'es')
- * @param array $language_array Formatted array of strings
- * @return true|false Depending on success
+ * @param string $country_code Standard country code (eg 'en', 'nl', 'es')
+ * @param array $language_array Formatted array of strings
+ *
+ * @return bool Depending on success
*/
function add_translation($country_code, $language_array) {
global $CONFIG;
@@ -46,8 +104,6 @@ function add_translation($country_code, $language_array) {
* @return string The language code for the site/user or "en" if not set
*/
function get_current_language() {
- global $CONFIG;
-
$language = get_language();
if (!$language) {
@@ -65,7 +121,7 @@ function get_current_language() {
function get_language() {
global $CONFIG;
- $user = get_loggedin_user();
+ $user = elgg_get_logged_in_user_entity();
$language = false;
if (($user) && ($user->language)) {
@@ -84,90 +140,137 @@ function get_language() {
}
/**
- * Given a message shortcode, returns an appropriately translated full-text string
- *
- * @param string $message_key The short message code
- * @param string $language Optionally, the standard language code (defaults to site/user default, then English)
- * @return string Either the translated string or the original English string
+ * @access private
*/
-function elgg_echo($message_key, $language = "") {
+function _elgg_load_translations() {
global $CONFIG;
- static $CURRENT_LANGUAGE;
- if (!$CURRENT_LANGUAGE) {
- $CURRENT_LANGUAGE = get_language();
- }
- if (!$language) {
- $language = $CURRENT_LANGUAGE;
- }
+ if ($CONFIG->system_cache_enabled) {
+ $loaded = true;
+ $languages = array_unique(array('en', get_current_language()));
+ foreach ($languages as $language) {
+ $data = elgg_load_system_cache("$language.lang");
+ if ($data) {
+ add_translation($language, unserialize($data));
+ } else {
+ $loaded = false;
+ }
+ }
- if (isset($CONFIG->translations[$language][$message_key])) {
- return $CONFIG->translations[$language][$message_key];
- } else if (isset($CONFIG->translations["en"][$message_key])) {
- return $CONFIG->translations["en"][$message_key];
+ if ($loaded) {
+ $CONFIG->i18n_loaded_from_cache = true;
+ // this is here to force
+ $CONFIG->language_paths[dirname(dirname(dirname(__FILE__))) . "/languages/"] = true;
+ return;
+ }
}
- return $message_key;
+ // load core translations from languages directory
+ register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/");
}
+
+
/**
* When given a full path, finds translation files and loads them
*
- * @param string $path Full path
- * @param bool $load_all If true all languages are loaded, if false only the current language + en are loaded
+ * @param string $path Full path
+ * @param bool $load_all If true all languages are loaded, if
+ * false only the current language + en are loaded
+ *
+ * @return bool success
*/
function register_translations($path, $load_all = false) {
global $CONFIG;
+ $path = sanitise_filepath($path);
+
// Make a note of this path just incase we need to register this language later
- if(!isset($CONFIG->language_paths)) $CONFIG->language_paths = array();
+ if (!isset($CONFIG->language_paths)) {
+ $CONFIG->language_paths = array();
+ }
$CONFIG->language_paths[$path] = true;
// Get the current language based on site defaults and user preference
$current_language = get_current_language();
elgg_log("Translations loaded from: $path");
- if ($handle = opendir($path)) {
- while ($language = readdir($handle)) {
- if (
- ((in_array($language, array('en.php', $current_language . '.php'))) /*&& (!is_dir($path . $language))*/) ||
- (($load_all) && (strpos($language, '.php')!==false)/* && (!is_dir($path . $language))*/)
- ) {
- include_once($path . $language);
+ // only load these files unless $load_all is true.
+ $load_language_files = array(
+ 'en.php',
+ "$current_language.php"
+ );
+
+ $load_language_files = array_unique($load_language_files);
+
+ $handle = opendir($path);
+ if (!$handle) {
+ elgg_log("Could not open language path: $path", 'ERROR');
+ return false;
+ }
+
+ $return = true;
+ while (false !== ($language = readdir($handle))) {
+ // ignore bad files
+ if (substr($language, 0, 1) == '.' || substr($language, -4) !== '.php') {
+ continue;
+ }
+
+ if (in_array($language, $load_language_files) || $load_all) {
+ if (!include_once($path . $language)) {
+ $return = false;
+ continue;
}
}
- } else {
- elgg_log("Missing translation path $path", 'ERROR');
}
+
+ return $return;
}
/**
* Reload all translations from all registered paths.
*
- * This is only called by functions which need to know all possible translations, namely the
- * statistic gathering ones.
+ * This is only called by functions which need to know all possible translations.
*
- * TODO: Better on demand loading based on language_paths array
+ * @todo Better on demand loading based on language_paths array
*
- * @return bool
+ * @return void
*/
function reload_all_translations() {
global $CONFIG;
static $LANG_RELOAD_ALL_RUN;
if ($LANG_RELOAD_ALL_RUN) {
- return null;
+ return;
}
- foreach ($CONFIG->language_paths as $path => $dummy) {
- register_translations($path, true);
+ if ($CONFIG->i18n_loaded_from_cache) {
+ $cache = elgg_get_system_cache();
+ $cache_dir = $cache->getVariable("cache_path");
+ $filenames = elgg_get_file_list($cache_dir, array(), array(), array(".lang"));
+ foreach ($filenames as $filename) {
+ if (preg_match('/([a-z]+)\.[^.]+$/', $filename, $matches)) {
+ $language = $matches[1];
+ $data = elgg_load_system_cache("$language.lang");
+ if ($data) {
+ add_translation($language, unserialize($data));
+ }
+ }
+ }
+ } else {
+ foreach ($CONFIG->language_paths as $path => $dummy) {
+ register_translations($path, true);
+ }
}
$LANG_RELOAD_ALL_RUN = true;
}
/**
- * Return an array of installed translations as an associative array "two letter code" => "native language name".
+ * Return an array of installed translations as an associative
+ * array "two letter code" => "native language name".
+ *
+ * @return array
*/
function get_installed_translations() {
global $CONFIG;
@@ -178,8 +281,8 @@ function get_installed_translations() {
$installed = array();
foreach ($CONFIG->translations as $k => $v) {
- $installed[$k] = elgg_echo($k, $k);
- if (isadminloggedin()) {
+ $installed[$k] = elgg_echo($k, array(), $k);
+ if (elgg_is_admin_logged_in()) {
$completeness = get_language_completeness($k);
if (($completeness < 100) && ($k != 'en')) {
$installed[$k] .= " (" . $completeness . "% " . elgg_echo('complete') . ")";
@@ -192,6 +295,10 @@ function get_installed_translations() {
/**
* Return the level of completeness for a given language code (compared to english)
+ *
+ * @param string $language Language
+ *
+ * @return int
*/
function get_language_completeness($language) {
global $CONFIG;
@@ -217,7 +324,12 @@ function get_language_completeness($language) {
}
/**
- * Return the translation keys missing from a given language, or those that are identical to the english version.
+ * Return the translation keys missing from a given language,
+ * or those that are identical to the english version.
+ *
+ * @param string $language The language
+ *
+ * @return mixed
*/
function get_missing_language_keys($language) {
global $CONFIG;
@@ -240,5 +352,3 @@ function get_missing_language_keys($language) {
return false;
}
-
-register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/");
diff --git a/engine/lib/location.php b/engine/lib/location.php
index 21ee7d5fa..1534c7d7b 100644
--- a/engine/lib/location.php
+++ b/engine/lib/location.php
@@ -2,67 +2,31 @@
/**
* Elgg geo-location tagging library.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Location
*/
/**
- * Define an interface for geo-tagging entities.
- *
- */
-interface Locatable {
- /** Set a location text */
- public function setLocation($location);
-
- /**
- * Set latitude and longitude tags for a given entity.
- *
- * @param float $lat
- * @param float $long
- */
- public function setLatLong($lat, $long);
-
- /**
- * Get the contents of the ->geo:lat field.
- *
- */
- public function getLatitude();
-
- /**
- * Get the contents of the ->geo:lat field.
- *
- */
- public function getLongitude();
-
- /**
- * Get the ->location metadata.
- *
- */
- public function getLocation();
-}
-
-/**
* Encode a location into a latitude and longitude, caching the result.
*
- * Works by triggering the 'geocode' 'location' plugin hook, and requires a geocoding module to be installed
- * activated in order to work.
+ * Works by triggering the 'geocode' 'location' plugin
+ * hook, and requires a geocoding plugin to be installed.
*
- * @param String $location The location, e.g. "London", or "24 Foobar Street, Gotham City"
+ * @param string $location The location, e.g. "London", or "24 Foobar Street, Gotham City"
+ * @return string|false
*/
function elgg_geocode_location($location) {
global $CONFIG;
- // Handle cases where we are passed an array (shouldn't be but can happen if location is a tag field)
if (is_array($location)) {
- $location = implode(', ', $location);
+ return false;
}
$location = sanitise_string($location);
// Look for cached version
- $cached_location = get_data_row("SELECT * from {$CONFIG->dbprefix}geocode_cache WHERE location='$location'");
+ $query = "SELECT * from {$CONFIG->dbprefix}geocode_cache WHERE location='$location'";
+ $cached_location = get_data_row($query);
if ($cached_location) {
return array('lat' => $cached_location->lat, 'long' => $cached_location->long);
@@ -70,7 +34,7 @@ function elgg_geocode_location($location) {
// Trigger geocode event if not cached
$return = false;
- $return = trigger_plugin_hook('geocode', 'location', array('location' => $location), $return);
+ $return = elgg_trigger_plugin_hook('geocode', 'location', array('location' => $location), $return);
// If returned, cache and return value
if (($return) && (is_array($return))) {
@@ -78,7 +42,10 @@ function elgg_geocode_location($location) {
$long = (float)$return['long'];
// Put into cache at the end of the page since we don't really care that much
- execute_delayed_write_query("INSERT DELAYED INTO {$CONFIG->dbprefix}geocode_cache (location, lat, `long`) VALUES ('$location', '{$lat}', '{$long}') ON DUPLICATE KEY UPDATE lat='{$lat}', `long`='{$long}'");
+ $query = "INSERT DELAYED INTO {$CONFIG->dbprefix}geocode_cache "
+ . " (location, lat, `long`) VALUES ('$location', '{$lat}', '{$long}')"
+ . " ON DUPLICATE KEY UPDATE lat='{$lat}', `long`='{$long}'";
+ execute_delayed_write_query($query);
}
return $return;
@@ -87,196 +54,104 @@ function elgg_geocode_location($location) {
/**
* Return entities within a given geographic area.
*
- * @param real $lat Latitude
- * @param real $long Longitude
- * @param real $radius The radius
- * @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.
+ * Also accepts all options available to elgg_get_entities().
+ *
+ * @see elgg_get_entities
+ *
+ * @param array $options Array in format:
+ *
+ * latitude => FLOAT Latitude of the location
+ *
+ * longitude => FLOAT Longitude of the location
+ *
+ * distance => FLOAT/ARR (
+ * latitude => float,
+ * longitude => float,
+ * )
+ * The distance in degrees that determines the search box. A
+ * single float will result in a square in degrees.
+ * @warning The Earth is round.
+ *
+ * @see ElggEntity::setLatLong()
+ *
+ * @return mixed If count, int. If not count, array. false on errors.
+ * @since 1.8.0
*/
-function get_entities_in_area($lat, $long, $radius, $type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0, $count = false, $site_guid = 0, $container_guid) {
- global $CONFIG;
+function elgg_get_entities_from_location(array $options = array()) {
- if ($subtype === false || $subtype === null || $subtype === 0) {
+ global $CONFIG;
+
+ if (!isset($options['latitude']) || !isset($options['longitude']) ||
+ !isset($options['distance'])) {
return false;
}
- $lat = (real)$lat;
- $long = (real)$long;
- $radius = (real)$radius;
-
- $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);
- if (!empty($subtypeval)) {
- $subtypeval = (int) get_subtype_id($typekey, $subtypeval);
- } else {
- $subtypeval = 0;
- }
- if (!empty($tempwhere)) $tempwhere .= " or ";
- $tempwhere .= "(e.type = '{$typekey}' and e.subtype = {$subtypeval})";
- }
- }
- }
- if (!empty($tempwhere)) {
- $where[] = "({$tempwhere})";
- }
+ if (!is_array($options['distance'])) {
+ $lat_distance = (float)$options['distance'];
+ $long_distance = (float)$options['distance'];
} else {
- $type = sanitise_string($type);
- $subtype = get_subtype_id($type, $subtype);
-
- 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[] = "e.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 = implode(",",$owner_guid); //
- $where[] = "e.owner_guid in ({$owner_guid})" ; //
- }
- if (is_null($container_guid)) {
- $container_guid = $owner_array;
- }
+ $lat_distance = (float)$options['distance']['latitude'];
+ $long_distance = (float)$options['distance']['longitude'];
}
- if ($site_guid > 0) {
- $where[] = "e.site_guid = {$site_guid}";
+ $lat = (float)$options['latitude'];
+ $long = (float)$options['longitude'];
+ $lat_min = $lat - $lat_distance;
+ $lat_max = $lat + $lat_distance;
+ $long_min = $long - $long_distance;
+ $long_max = $long + $long_distance;
+
+ $wheres = array();
+ $wheres[] = "lat_name.string='geo:lat'";
+ $wheres[] = "lat_value.string >= $lat_min";
+ $wheres[] = "lat_value.string <= $lat_max";
+ $wheres[] = "lon_name.string='geo:long'";
+ $wheres[] = "lon_value.string >= $long_min";
+ $wheres[] = "lon_value.string <= $long_max";
+
+ $joins = array();
+ $joins[] = "JOIN {$CONFIG->dbprefix}metadata lat on e.guid=lat.entity_guid";
+ $joins[] = "JOIN {$CONFIG->dbprefix}metastrings lat_name on lat.name_id=lat_name.id";
+ $joins[] = "JOIN {$CONFIG->dbprefix}metastrings lat_value on lat.value_id=lat_value.id";
+ $joins[] = "JOIN {$CONFIG->dbprefix}metadata lon on e.guid=lon.entity_guid";
+ $joins[] = "JOIN {$CONFIG->dbprefix}metastrings lon_name on lon.name_id=lon_name.id";
+ $joins[] = "JOIN {$CONFIG->dbprefix}metastrings lon_value on lon.value_id=lon_value.id";
+
+ // merge wheres to pass to get_entities()
+ if (isset($options['wheres']) && !is_array($options['wheres'])) {
+ $options['wheres'] = array($options['wheres']);
+ } elseif (!isset($options['wheres'])) {
+ $options['wheres'] = array();
}
+ $options['wheres'] = array_merge($options['wheres'], $wheres);
- 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}";
- }
- }
-
- // Add the calendar stuff
- $loc_join = "
- JOIN {$CONFIG->dbprefix}metadata loc_start on e.guid=loc_start.entity_guid
- JOIN {$CONFIG->dbprefix}metastrings loc_start_name on loc_start.name_id=loc_start_name.id
- JOIN {$CONFIG->dbprefix}metastrings loc_start_value on loc_start.value_id=loc_start_value.id
-
- JOIN {$CONFIG->dbprefix}metadata loc_end on e.guid=loc_end.entity_guid
- JOIN {$CONFIG->dbprefix}metastrings loc_end_name on loc_end.name_id=loc_end_name.id
- JOIN {$CONFIG->dbprefix}metastrings loc_end_value on loc_end.value_id=loc_end_value.id
- ";
-
- $lat_min = $lat - $radius;
- $lat_max = $lat + $radius;
- $long_min = $long - $radius;
- $long_max = $long + $radius;
-
- $where[] = "loc_start_name.string='geo:lat'";
- $where[] = "loc_start_value.string>=$lat_min";
- $where[] = "loc_start_value.string<=$lat_max";
- $where[] = "loc_end_name.string='geo:long'";
- $where[] = "loc_end_value.string >= $long_min";
- $where[] = "loc_end_value.string <= $long_max";
-
- if (!$count) {
- $query = "SELECT e.* from {$CONFIG->dbprefix}entities e $loc_join where ";
- } else {
- $query = "SELECT count(e.guid) as total from {$CONFIG->dbprefix}entities e $loc_join where ";
- }
- foreach ($where as $w) {
- $query .= " $w and ";
+ // merge joins to pass to get_entities()
+ if (isset($options['joins']) && !is_array($options['joins'])) {
+ $options['joins'] = array($options['joins']);
+ } elseif (!isset($options['joins'])) {
+ $options['joins'] = array();
}
+ $options['joins'] = array_merge($options['joins'], $joins);
- $query .= get_access_sql_suffix('e'); // Add access controls
-
- if (!$count) {
- $query .= " order by n.calendar_start $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;
- }
+ return elgg_get_entities_from_relationship($options);
}
/**
- * List entities in a given location
+ * Returns a viewable list of entities from location
*
- * @param string $location Location
- * @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_location($location, $type= "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $navigation = true) {
- return list_entities_from_metadata('location', $location, $type, $subtype, $owner_guid, $limit, $fullview, $viewtypetoggle, $navigation);
-}
-
-/**
- * List items within a given geographic area.
+ * @param array $options Options array
*
- * @param real $lat Latitude
- * @param real $long Longitude
- * @param real $radius The radius
- * @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
+ * @see elgg_list_entities()
+ * @see elgg_get_entities_from_location()
+ *
+ * @return string The viewable list of entities
+ * @since 1.8.0
*/
-function list_entities_in_area($lat, $long, $radius, $type= "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $navigation = true) {
-
- $offset = (int) get_input('offset');
- $count = get_entities_in_area($lat, $long, $radius, $type, $subtype, $owner_guid, "", $limit, $offset, true);
- $entities = get_entities_in_area($lat, $long, $radius, $type, $subtype, $owner_guid, "", $limit, $offset);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $navigation);
+function elgg_list_entities_from_location(array $options = array()) {
+ return elgg_list_entities($options, 'elgg_get_entities_from_location');
}
// Some distances in degrees (approximate)
+// @todo huh? see warning on elgg_get_entities_from_location()
define("MILE", 0.01515);
define("KILOMETER", 0.00932);
-
-// TODO: get objects within x miles by entities, metadata and relationship
-
-// TODO: List \ No newline at end of file
diff --git a/engine/lib/mb_wrapper.php b/engine/lib/mb_wrapper.php
index 9aa4aac4c..68fa69005 100644
--- a/engine/lib/mb_wrapper.php
+++ b/engine/lib/mb_wrapper.php
@@ -11,8 +11,10 @@ if (is_callable('mb_internal_encoding')) {
* NOTE: This differs from parse_str() by returning the results
* instead of placing them in the local scope!
*
- * @param str $str
+ * @param string $str The string
+ *
* @return array
+ * @since 1.7.0
*/
function elgg_parse_str($str) {
if (is_callable('mb_parse_str')) {
@@ -24,44 +26,208 @@ function elgg_parse_str($str) {
return $results;
}
-// map string functions to their mb_str_func alternatives
-// and wrap them in elgg_str_fun()
-
-// list of non-mb safe string functions to wrap in elgg_*()
-// only will work with mb_* functions that take the same
-// params in the same order as their non-mb safe counterparts.
-$str_funcs = array(
- // can't wrap parse_str() because of its 2nd parameter.
- //'parse_str',
- 'split',
- 'stristr',
- 'strlen',
- 'strpos',
- 'strrchr',
- 'strripos',
- 'strrpos',
- 'strstr',
- 'strtolower',
- 'strtoupper',
- 'substr_count',
- 'substr'
-);
-
-$eval_statement = '';
-foreach ($str_funcs as $func) {
- // create wrapper function passing in the same args as given
- $mb_func = "mb_$func";
- $eval_statement .= "
- function elgg_$func() {
- \$args = func_get_args();
- if (is_callable('$mb_func')) {
- return call_user_func_array('$mb_func', \$args);
- }
- return call_user_func_array('$func', \$args);
+
+
+/**
+ * Wrapper function for mb_split(). Falls back to split() if
+ * mb_split() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return string
+ * @since 1.7.0
+ */
+function elgg_split() {
+ $args = func_get_args();
+ if (is_callable('mb_split')) {
+ return call_user_func_array('mb_split', $args);
+ }
+ return call_user_func_array('split', $args);
+}
+
+/**
+ * Wrapper function for mb_stristr(). Falls back to stristr() if
+ * mb_stristr() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return string
+ * @since 1.7.0
+ */
+function elgg_stristr() {
+ $args = func_get_args();
+ if (is_callable('mb_stristr')) {
+ return call_user_func_array('mb_stristr', $args);
+ }
+ return call_user_func_array('stristr', $args);
+}
+
+/**
+ * Wrapper function for mb_strlen(). Falls back to strlen() if
+ * mb_strlen() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return string
+ * @since 1.7.0
+ */
+function elgg_strlen() {
+ $args = func_get_args();
+ if (is_callable('mb_strlen')) {
+ return call_user_func_array('mb_strlen', $args);
+ }
+ return call_user_func_array('strlen', $args);
+}
+
+/**
+ * Wrapper function for mb_strpos(). Falls back to strpos() if
+ * mb_strpos() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return string
+ * @since 1.7.0
+ */
+function elgg_strpos() {
+ $args = func_get_args();
+ if (is_callable('mb_strpos')) {
+ return call_user_func_array('mb_strpos', $args);
+ }
+ return call_user_func_array('strpos', $args);
+}
+
+/**
+ * Wrapper function for mb_strrchr(). Falls back to strrchr() if
+ * mb_strrchr() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return string
+ * @since 1.7.0
+ */
+function elgg_strrchr() {
+ $args = func_get_args();
+ if (is_callable('mb_strrchr')) {
+ return call_user_func_array('mb_strrchr', $args);
+ }
+ return call_user_func_array('strrchr', $args);
+}
+
+/**
+ * Wrapper function for mb_strripos(). Falls back to strripos() if
+ * mb_strripos() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return int
+ * @since 1.7.0
+ */
+function elgg_strripos() {
+ $args = func_get_args();
+ if (is_callable('mb_strripos')) {
+ return call_user_func_array('mb_strripos', $args);
+ }
+ return call_user_func_array('strripos', $args);
+}
+
+/**
+ * Wrapper function for mb_strrpos(). Falls back to strrpos() if
+ * mb_strrpos() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return int
+ * @since 1.7.0
+ */
+function elgg_strrpos() {
+ $args = func_get_args();
+ if (is_callable('mb_strrpos')) {
+ return call_user_func_array('mb_strrpos', $args);
+ }
+ return call_user_func_array('strrpos', $args);
+}
+
+/**
+ * Wrapper function for mb_strstr(). Falls back to strstr() if
+ * mb_strstr() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return bool
+ * @since 1.7.0
+ */
+function elgg_strstr() {
+ $args = func_get_args();
+ if (is_callable('mb_strstr')) {
+ return call_user_func_array('mb_strstr', $args);
}
-";
+ return call_user_func_array('strstr', $args);
}
-eval($eval_statement);
+/**
+ * Wrapper function for mb_strtolower(). Falls back to strtolower() if
+ * mb_strtolower() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return string
+ * @since 1.7.0
+ */
+function elgg_strtolower() {
+ $args = func_get_args();
+ if (is_callable('mb_strtolower')) {
+ return call_user_func_array('mb_strtolower', $args);
+ }
+ return call_user_func_array('strtolower', $args);
+}
-// TODO: Other wrapper functions \ No newline at end of file
+/**
+ * Wrapper function for mb_strtoupper(). Falls back to strtoupper() if
+ * mb_strtoupper() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return string
+ * @since 1.7.0
+ */
+function elgg_strtoupper() {
+ $args = func_get_args();
+ if (is_callable('mb_strtoupper')) {
+ return call_user_func_array('mb_strtoupper', $args);
+ }
+ return call_user_func_array('strtoupper', $args);
+}
+
+/**
+ * Wrapper function for mb_substr_count(). Falls back to substr_count() if
+ * mb_substr_count() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return int
+ * @since 1.7.0
+ */
+function elgg_substr_count() {
+ $args = func_get_args();
+ if (is_callable('mb_substr_count')) {
+ return call_user_func_array('mb_substr_count', $args);
+ }
+ return call_user_func_array('substr_count', $args);
+}
+
+/**
+ * Wrapper function for mb_substr(). Falls back to substr() if
+ * mb_substr() isn't available. Parameters are passed to the
+ * wrapped function in the same order they are passed to this
+ * function.
+ *
+ * @return string
+ * @since 1.7.0
+ */
+function elgg_substr() {
+ $args = func_get_args();
+ if (is_callable('mb_substr')) {
+ return call_user_func_array('mb_substr', $args);
+ }
+ return call_user_func_array('substr', $args);
+}
diff --git a/engine/lib/memcache.php b/engine/lib/memcache.php
index ed93cacf0..79b87e850 100644
--- a/engine/lib/memcache.php
+++ b/engine/lib/memcache.php
@@ -4,164 +4,11 @@
*
* Requires php5-memcache to work.
*
- * @package Elgg
- * @subpackage API
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Cache.Memcache
*/
/**
- * Memcache wrapper class.
- * @author Curverider Ltd <info@elgg.com>
- */
-class ElggMemcache extends ElggSharedMemoryCache {
- /**
- * Minimum version of memcached needed to run
- *
- */
- private static $MINSERVERVERSION = '1.1.12';
-
- /**
- * Memcache object
- */
- private $memcache;
-
- /**
- * Expiry of saved items (default timeout after a day to prevent anything getting too stale)
- */
- private $expires = 86400;
-
- /**
- * The version of memcache running
- */
- private $version = 0;
-
- /**
- * Connect to memcache.
- *
- * @param string $cache_id The namespace for this cache to write to - note, namespaces of the same name are shared!
- */
- function __construct($namespace = 'default') {
- global $CONFIG;
-
- $this->setNamespace($namespace);
-
- // Do we have memcache?
- if (!class_exists('Memcache')) {
- throw new ConfigurationException(elgg_echo('memcache:notinstalled'));
- }
-
- // Create memcache object
- $this->memcache = new Memcache;
-
- // Now add servers
- if (!$CONFIG->memcache_servers) {
- throw new ConfigurationException(elgg_echo('memcache:noservers'));
- }
-
- if (is_callable($this->memcache, 'addServer')) {
- foreach ($CONFIG->memcache_servers as $server) {
- if (is_array($server)) {
- $this->memcache->addServer(
- $server[0],
- isset($server[1]) ? $server[1] : 11211,
- isset($server[2]) ? $server[2] : true,
- isset($server[3]) ? $server[3] : null,
- isset($server[4]) ? $server[4] : 1,
- isset($server[5]) ? $server[5] : 15,
- isset($server[6]) ? $server[6] : true
- );
-
- } else {
- $this->memcache->addServer($server, 11211);
- }
- }
- } else {
- elgg_log(elgg_echo('memcache:noaddserver'), 'ERROR');
-
- $server = $CONFIG->memcache_servers[0];
- if (is_array($server)) {
- $this->memcache->connect($server[0], $server[1]);
- } else {
- $this->memcache->addServer($server, 11211);
- }
- }
-
- // Get version
- $this->version = $this->memcache->getversion();
- if (version_compare($this->version, ElggMemcache::$MINSERVERVERSION, '<')) {
- throw new ConfigurationException(sprintf(elgg_echo('memcache:versiontoolow'), ElggMemcache::$MINSERVERVERSION, $this->version));
- }
-
- // Set some defaults
- if (isset($CONFIG->memcache_expires)) {
- $this->expires = $CONFIG->memcache_expires;
- }
- }
-
- /**
- * Set the default expiry.
- *
- * @param int $expires The lifetime as a unix timestamp or time from now. Defaults forever.
- */
- public function setDefaultExpiry($expires = 0) {
- $this->expires = $expires;
- }
-
- /**
- * Combine a key with the namespace.
- * Memcache can only accept <250 char key. If the given key is too long it is shortened.
- *
- * @param string $key The key
- * @return string The new key.
- */
- private function make_memcache_key($key) {
- $prefix = $this->getNamespace() . ":";
-
- if (strlen($prefix.$key)> 250) {
- $key = md5($key);
- }
-
- return $prefix.$key;
- }
-
- public function save($key, $data) {
- $key = $this->make_memcache_key($key);
-
- $result = $this->memcache->set($key, $data, null, $this->expires);
- if (!$result) {
- elgg_log("MEMCACHE: FAILED TO SAVE $key", 'ERROR');
- }
-
- return $result;
- }
-
- public function load($key, $offset = 0, $limit = null) {
- $key = $this->make_memcache_key($key);
-
- $result = $this->memcache->get($key);
- if (!$result) {
- elgg_log("MEMCACHE: FAILED TO LOAD $key", 'ERROR');
- }
-
- return $result;
- }
-
- public function delete($key) {
- $key = $this->make_memcache_key($key);
-
- return $this->memcache->delete($key, 0);
- }
-
- public function clear() {
- // DISABLE clearing for now - you must use delete on a specific key.
- return true;
-
- //TODO: Namespaces as in #532
- }
-}
-
-/**
* Return true if memcache is available and configured.
*
* @return bool
@@ -176,7 +23,7 @@ function is_memcache_available() {
}
// If we haven't set variable to something
- if (($memcache_available!==true) && ($memcache_available!==false)) {
+ if (($memcache_available !== true) && ($memcache_available !== false)) {
try {
$tmp = new ElggMemcache();
// No exception thrown so we have memcache available
@@ -187,4 +34,24 @@ function is_memcache_available() {
}
return $memcache_available;
+}
+
+/**
+ * Invalidate an entity in memcache
+ *
+ * @param int $entity_guid The GUID of the entity to invalidate
+ *
+ * @return void
+ * @access private
+ */
+function _elgg_invalidate_memcache_for_entity($entity_guid) {
+ static $newentity_cache;
+
+ if ((!$newentity_cache) && (is_memcache_available())) {
+ $newentity_cache = new ElggMemcache('new_entity_cache');
+ }
+
+ if ($newentity_cache) {
+ $newentity_cache->delete($entity_guid);
+ }
} \ No newline at end of file
diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php
index d28999a77..fdb1b85f6 100644
--- a/engine/lib/metadata.php
+++ b/engine/lib/metadata.php
@@ -1,132 +1,19 @@
<?php
/**
* Elgg metadata
- * Functions to manage object metadata.
+ * Functions to manage entity metadata.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage DataModel.Metadata
*/
/**
- * ElggMetadata
- * This class describes metadata that can be attached to ElggEntities.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Core
- */
-class ElggMetadata extends ElggExtender {
- /**
- * Construct a new site object, optionally from a given id value or row.
- *
- * @param mixed $id
- */
- function __construct($id = null) {
- $this->attributes = array();
-
- if (!empty($id)) {
- // Create from db row
- if ($id instanceof stdClass) {
- $metadata = $id;
- } else {
- $metadata = get_metadata($id);
- }
-
- if ($metadata) {
- $objarray = (array) $metadata;
- foreach($objarray as $key => $value) {
- $this->attributes[$key] = $value;
- }
- $this->attributes['type'] = "metadata";
- }
- }
- }
-
- /**
- * 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);
- }
-
- /**
- * Determines whether or not the user can edit this piece of metadata
- *
- * @return true|false Depending on permissions
- */
- function canEdit() {
- if ($entity = get_entity($this->get('entity_guid'))) {
- return $entity->canEditMetadata($this);
- }
- return false;
- }
-
- /**
- * Save matadata object
- *
- * @return int the metadata object id
- */
- function save() {
- if ($this->id > 0) {
- return update_metadata($this->id, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id);
- } else {
- $this->id = create_metadata($this->entity_guid, $this->name, $this->value, $this->value_type, $this->owner_guid, $this->access_id);
- if (!$this->id) {
- throw new IOException(sprintf(elgg_new('IOException:UnableToSaveNew'), get_class()));
- }
- return $this->id;
- }
- }
-
- /**
- * Delete a given metadata.
- */
- function delete() {
- return delete_metadata($this->id);
- }
-
- /**
- * Get a url for this item of metadata.
- *
- * @return string
- */
- public function getURL() {
- return get_metadata_url($this->id);
- }
-
- // SYSTEM LOG INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * For a given ID, return the object associated with it.
- * This is used by the river functionality primarily.
- * This is useful for checking access permissions etc on objects.
- */
- public function getObjectFromID($id) {
- return get_metadata($id);
- }
-}
-
-/**
* Convert a database row to a new ElggMetadata
*
- * @param stdClass $row
- * @return stdClass or ElggMetadata
+ * @param stdClass $row An object from the database
+ *
+ * @return stdClass|ElggMetadata
+ * @access private
*/
function row_to_elggmetadata($row) {
if (!($row instanceof stdClass)) {
@@ -137,64 +24,55 @@ function row_to_elggmetadata($row) {
}
/**
- * Get a specific item of metadata.
+ * Get a specific metadata object by its id.
+ * If you want multiple metadata objects, use
+ * {@link elgg_get_metadata()}.
*
- * @param $id int The item of metadata being retrieved.
+ * @param int $id The id of the metadata object being retrieved.
+ *
+ * @return ElggMetadata|false FALSE if not found
*/
-function get_metadata($id) {
- global $CONFIG;
-
- $id = (int)$id;
- $access = get_access_sql_suffix("e");
- $md_access = get_access_sql_suffix("m");
-
- return row_to_elggmetadata(get_data_row("SELECT m.*, n.string as name, v.string as value from {$CONFIG->dbprefix}metadata m JOIN {$CONFIG->dbprefix}entities e on e.guid = m.entity_guid JOIN {$CONFIG->dbprefix}metastrings v on m.value_id = v.id JOIN {$CONFIG->dbprefix}metastrings n on m.name_id = n.id where m.id=$id and $access and $md_access"));
+function elgg_get_metadata_from_id($id) {
+ return elgg_get_metastring_based_object_from_id($id, 'metadata');
}
/**
- * Removes metadata on an entity with a particular name, optionally with a given value.
+ * Deletes metadata using its ID.
*
- * @param int $entity_guid The entity GUID
- * @param string $name The name of the metadata
- * @param string $value The optional value of the item (useful for removing a single item in a multiple set)
- * @return true|false Depending on success
+ * @param int $id The metadata ID to delete.
+ * @return bool
*/
-function remove_metadata($entity_guid, $name, $value = "") {
- global $CONFIG;
- $entity_guid = (int) $entity_guid;
- $name = sanitise_string($name);
- $value = sanitise_string($value);
-
- $query = "SELECT * from {$CONFIG->dbprefix}metadata WHERE entity_guid = $entity_guid and name_id=" . add_metastring($name);
- if ($value!="") {
- $query .= " and value_id=" . add_metastring($value);
- }
-
- if ($existing = get_data($query)) {
- foreach($existing as $ex) {
- delete_metadata($ex->id);
- }
- return true;
+function elgg_delete_metadata_by_id($id) {
+ $metadata = elgg_get_metadata_from_id($id);
+ if (!$metadata) {
+ return false;
}
-
- return false;
+ return $metadata->delete();
}
/**
* Create a new metadata object, or update an existing one.
*
- * @param int $entity_guid The entity to attach the metadata to
- * @param string $name Name of the metadata
- * @param string $value Value of the metadata (cannot be associative array)
- * @param string $value_type
- * @param int $owner_guid
- * @param int $access_id
- * @param bool $allow_multiple
+ * Metadata can be an array by setting allow_multiple to TRUE, but it is an
+ * indexed array with no control over the indexing.
+ *
+ * @param int $entity_guid The entity to attach the metadata to
+ * @param string $name Name of the metadata
+ * @param string $value Value of the metadata
+ * @param string $value_type 'text', 'integer', or '' for automatic detection
+ * @param int $owner_guid GUID of entity that owns the metadata
+ * @param int $access_id Default is ACCESS_PRIVATE
+ * @param bool $allow_multiple Allow multiple values for one key. Default is FALSE
+ *
+ * @return int|false id of metadata or FALSE if failure
*/
-function create_metadata($entity_guid, $name, $value, $value_type, $owner_guid, $access_id = ACCESS_PRIVATE, $allow_multiple = false) {
+function create_metadata($entity_guid, $name, $value, $value_type = '', $owner_guid = 0,
+ $access_id = ACCESS_PRIVATE, $allow_multiple = false) {
+
global $CONFIG;
$entity_guid = (int)$entity_guid;
+ // name and value are encoded in add_metastring()
//$name = sanitise_string(trim($name));
//$value = sanitise_string(trim($value));
$value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type)));
@@ -202,81 +80,85 @@ function create_metadata($entity_guid, $name, $value, $value_type, $owner_guid,
$owner_guid = (int)$owner_guid;
$allow_multiple = (boolean)$allow_multiple;
- if ($owner_guid==0) {
- $owner_guid = get_loggedin_userid();
+ if (!isset($value)) {
+ return FALSE;
+ }
+
+ if ($owner_guid == 0) {
+ $owner_guid = elgg_get_logged_in_user_guid();
}
$access_id = (int)$access_id;
- $id = false;
+ $query = "SELECT * from {$CONFIG->dbprefix}metadata"
+ . " WHERE entity_guid = $entity_guid and name_id=" . add_metastring($name) . " limit 1";
- $existing = get_data_row("SELECT * from {$CONFIG->dbprefix}metadata WHERE entity_guid = $entity_guid and name_id=" . add_metastring($name) . " limit 1");
- if (($existing) && (!$allow_multiple) && (isset($value))) {
- $id = $existing->id;
+ $existing = get_data_row($query);
+ if ($existing && !$allow_multiple) {
+ $id = (int)$existing->id;
$result = update_metadata($id, $name, $value, $value_type, $owner_guid, $access_id);
if (!$result) {
return false;
}
- }
- else if (isset($value)) {
+ } else {
// Support boolean types
if (is_bool($value)) {
- if ($value) {
- $value = 1;
- } else {
- $value = 0;
- }
+ $value = (int) $value;
}
// Add the metastrings
- $value = add_metastring($value);
- if (!$value) {
+ $value_id = add_metastring($value);
+ if (!$value_id) {
return false;
}
- $name = add_metastring($name);
- if (!$name) {
+ $name_id = add_metastring($name);
+ if (!$name_id) {
return false;
}
// If ok then add it
- $id = insert_data("INSERT into {$CONFIG->dbprefix}metadata (entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id) VALUES ($entity_guid, '$name','$value','$value_type', $owner_guid, $time, $access_id)");
+ $query = "INSERT into {$CONFIG->dbprefix}metadata"
+ . " (entity_guid, name_id, value_id, value_type, owner_guid, time_created, access_id)"
+ . " VALUES ($entity_guid, '$name_id','$value_id','$value_type', $owner_guid, $time, $access_id)";
+
+ $id = insert_data($query);
+
+ if ($id !== false) {
+ $obj = elgg_get_metadata_from_id($id);
+ if (elgg_trigger_event('create', 'metadata', $obj)) {
+
+ elgg_get_metadata_cache()->save($entity_guid, $name, $value, $allow_multiple);
- if ($id!==false) {
- $obj = get_metadata($id);
- if (trigger_elgg_event('create', 'metadata', $obj)) {
- return true;
+ return $id;
} else {
- delete_metadata($id);
+ elgg_delete_metadata_by_id($id);
}
}
-
- } else if ($existing) {
- // TODO: Check... are you sure you meant to do this Ben? :)
- $id = $existing->id;
- delete_metadata($id);
}
return $id;
}
/**
- * Update an item of metadata.
- *
- * @param int $id
- * @param string $name
- * @param string $value
- * @param string $value_type
- * @param int $owner_guid
- * @param int $access_id
+ * Update a specific piece of metadata.
+ *
+ * @param int $id ID of the metadata to update
+ * @param string $name Metadata name
+ * @param string $value Metadata value
+ * @param string $value_type Value type
+ * @param int $owner_guid Owner guid
+ * @param int $access_id Access ID
+ *
+ * @return bool
*/
function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_id) {
global $CONFIG;
$id = (int)$id;
- if (!$md = get_metadata($id)) {
+ if (!$md = elgg_get_metadata_from_id($id)) {
return false;
}
if (!$md->canEdit()) {
@@ -290,51 +172,50 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i
}
if ($metabyname_memcache) {
+ // @todo fix memcache (name_id is not a property of ElggMetadata)
$metabyname_memcache->delete("{$md->entity_guid}:{$md->name_id}");
}
- //$name = sanitise_string(trim($name));
- //$value = sanitise_string(trim($value));
$value_type = detect_extender_valuetype($value, sanitise_string(trim($value_type)));
$owner_guid = (int)$owner_guid;
- if ($owner_guid==0) {
- $owner_guid = get_loggedin_userid();
+ if ($owner_guid == 0) {
+ $owner_guid = elgg_get_logged_in_user_guid();
}
$access_id = (int)$access_id;
- $access = get_access_sql_suffix();
-
// Support boolean types (as integers)
if (is_bool($value)) {
- if ($value) {
- $value = 1;
- } else {
- $value = 0;
- }
+ $value = (int) $value;
}
// Add the metastring
- $value = add_metastring($value);
- if (!$value) {
+ $value_id = add_metastring($value);
+ if (!$value_id) {
return false;
}
- $name = add_metastring($name);
- if (!$name) {
+ $name_id = add_metastring($name);
+ if (!$name_id) {
return false;
}
// If ok then add it
- $result = update_data("UPDATE {$CONFIG->dbprefix}metadata set value_id='$value', value_type='$value_type', access_id=$access_id, owner_guid=$owner_guid where id=$id and name_id='$name'");
- if ($result!==false) {
- $obj = get_metadata($id);
- if (trigger_elgg_event('update', 'metadata', $obj)) {
- return true;
- } else {
- delete_metadata($id);
- }
+ $query = "UPDATE {$CONFIG->dbprefix}metadata"
+ . " set name_id='$name_id', value_id='$value_id', value_type='$value_type', access_id=$access_id,"
+ . " owner_guid=$owner_guid where id=$id";
+
+ $result = update_data($query);
+ if ($result !== false) {
+
+ elgg_get_metadata_cache()->save($md->entity_guid, $name, $value);
+
+ // @todo this event tells you the metadata has been updated, but does not
+ // let you do anything about it. What is needed is a plugin hook before
+ // the update that passes old and new values.
+ $obj = elgg_get_metadata_from_id($id);
+ elgg_trigger_event('update', 'metadata', $obj);
}
return $result;
@@ -343,16 +224,26 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i
/**
* This function creates metadata from an associative array of "key => value" pairs.
*
- * @param int $entity_guid
- * @param string $name_and_values
- * @param string $value_type
- * @param int $owner_guid
- * @param int $access_id
- * @param bool $allow_multiple
+ * To achieve an array for a single key, pass in the same key multiple times with
+ * allow_multiple set to TRUE. This creates an indexed array. It does not support
+ * associative arrays and there is no guarantee on the ordering in the array.
+ *
+ * @param int $entity_guid The entity to attach the metadata to
+ * @param array $name_and_values Associative array - a value can be a string, number, bool
+ * @param string $value_type 'text', 'integer', or '' for automatic detection
+ * @param int $owner_guid GUID of entity that owns the metadata
+ * @param int $access_id Default is ACCESS_PRIVATE
+ * @param bool $allow_multiple Allow multiple values for one key. Default is FALSE
+ *
+ * @return bool
*/
-function create_metadata_from_array($entity_guid, array $name_and_values, $value_type, $owner_guid, $access_id = ACCESS_PRIVATE, $allow_multiple = false) {
+function create_metadata_from_array($entity_guid, array $name_and_values, $value_type, $owner_guid,
+$access_id = ACCESS_PRIVATE, $allow_multiple = false) {
+
foreach ($name_and_values as $k => $v) {
- if (!create_metadata($entity_guid, $k, $v, $value_type, $owner_guid, $access_id, $allow_multiple)) {
+ $result = create_metadata($entity_guid, $k, $v, $value_type, $owner_guid,
+ $access_id, $allow_multiple);
+ if (!$result) {
return false;
}
}
@@ -360,228 +251,202 @@ function create_metadata_from_array($entity_guid, array $name_and_values, $value
}
/**
- * Delete an item of metadata, where the current user has access.
+ * Returns metadata. Accepts all elgg_get_entities() options for entity
+ * restraints.
+ *
+ * @see elgg_get_entities
+ *
+ * @warning 1.7's find_metadata() didn't support limits and returned all metadata.
+ * This function defaults to a limit of 25. There is probably not a reason
+ * for you to return all metadata unless you're exporting an entity,
+ * have other restraints in place, or are doing something horribly
+ * wrong in your code.
*
- * @param $id int The item of metadata to delete.
+ * @param array $options Array in format:
+ *
+ * metadata_names => NULL|ARR metadata names
+ * metadata_values => NULL|ARR metadata values
+ * metadata_ids => NULL|ARR metadata ids
+ * metadata_case_sensitive => BOOL Overall Case sensitive
+ * metadata_owner_guids => NULL|ARR guids for metadata owners
+ * metadata_created_time_lower => INT Lower limit for created time.
+ * metadata_created_time_upper => INT Upper limit for created time.
+ * metadata_calculation => STR Perform the MySQL function on the metadata values returned.
+ * The "metadata_calculation" option causes this function to
+ * return the result of performing a mathematical calculation on
+ * all metadata that match the query instead of returning
+ * ElggMetadata objects.
+ *
+ * @return ElggMetadata[]|mixed
+ * @since 1.8.0
*/
-function delete_metadata($id) {
- global $CONFIG;
-
- $id = (int)$id;
- $metadata = get_metadata($id);
-
- if ($metadata) {
- // Tidy up if memcache is enabled.
- static $metabyname_memcache;
- if ((!$metabyname_memcache) && (is_memcache_available())) {
- $metabyname_memcache = new ElggMemcache('metabyname_memcache');
- }
-
- if ($metabyname_memcache) {
- $metabyname_memcache->delete("{$metadata->entity_guid}:{$metadata->name_id}");
- }
+function elgg_get_metadata(array $options = array()) {
- if (($metadata->canEdit()) && (trigger_elgg_event('delete', 'metadata', $metadata))) {
- return delete_data("DELETE from {$CONFIG->dbprefix}metadata where id=$id");
- }
+ // @todo remove support for count shortcut - see #4393
+ // support shortcut of 'count' => true for 'metadata_calculation' => 'count'
+ if (isset($options['count']) && $options['count']) {
+ $options['metadata_calculation'] = 'count';
+ unset($options['count']);
}
- return false;
+ $options['metastring_type'] = 'metadata';
+ return elgg_get_metastring_based_objects($options);
}
/**
- * Return the metadata values that match your query.
+ * Deletes metadata based on $options.
*
- * @param string $meta_name
- * @return mixed either a value, an array of ElggMetadata or false.
+ * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
+ * This requires at least one constraint: metadata_owner_guid(s),
+ * metadata_name(s), metadata_value(s), or guid(s) must be set.
+ *
+ * @param array $options An options array. {@see elgg_get_metadata()}
+ * @return bool|null true on success, false on failure, null if no metadata to delete.
+ * @since 1.8.0
*/
-function get_metadata_byname($entity_guid, $meta_name) {
- global $CONFIG;
-
- $meta_name = get_metastring_id($meta_name);
-
- if (empty($meta_name)) {
+function elgg_delete_metadata(array $options) {
+ if (!elgg_is_valid_options_for_batch_operation($options, 'metadata')) {
return false;
}
+ $options['metastring_type'] = 'metadata';
+ $result = elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback', false);
- $entity_guid = (int)$entity_guid;
- $access = get_access_sql_suffix("e");
- $md_access = get_access_sql_suffix("m");
-
- // If memcache is available then cache this (cache only by name for now since this is the most common query)
- $meta = null;
- static $metabyname_memcache;
- if ((!$metabyname_memcache) && (is_memcache_available())) {
- $metabyname_memcache = new ElggMemcache('metabyname_memcache');
- }
- if ($metabyname_memcache) {
- $meta = $metabyname_memcache->load("{$entity_guid}:{$meta_name}");
- }
- if ($meta) {
- return $meta;
- }
-
- $result = get_data("SELECT m.*, n.string as name, v.string as value from {$CONFIG->dbprefix}metadata m JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.entity_guid JOIN {$CONFIG->dbprefix}metastrings v on m.value_id = v.id JOIN {$CONFIG->dbprefix}metastrings n on m.name_id = n.id where m.entity_guid=$entity_guid and m.name_id='$meta_name' and $access and $md_access ORDER BY m.id ASC", "row_to_elggmetadata");
- if (!$result) {
- return false;
- }
-
- // Cache if memcache available
- if ($metabyname_memcache) {
- if (count($result) == 1) {
- $r = $result[0];
- } else {
- $r = $result;
- }
- // This is a bit of a hack - we shorten the expiry on object
- // metadata so that it'll be gone in an hour. This means that
- // deletions and more importantly updates will filter through eventually.
- $metabyname_memcache->setDefaultExpiry(3600);
- $metabyname_memcache->save("{$entity_guid}:{$meta_name}", $r);
- }
- if (count($result) == 1) {
- return $result[0];
- }
+ // This moved last in case an object's constructor sets metadata. Currently the batch
+ // delete process has to create the entity to delete its metadata. See #5214
+ elgg_get_metadata_cache()->invalidateByOptions('delete', $options);
return $result;
}
/**
- * Return all the metadata for a given GUID.
+ * Disables metadata based on $options.
*
- * @param int $entity_guid
+ * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
+ *
+ * @param array $options An options array. {@See elgg_get_metadata()}
+ * @return bool|null true on success, false on failure, null if no metadata disabled.
+ * @since 1.8.0
*/
-function get_metadata_for_entity($entity_guid) {
- global $CONFIG;
+function elgg_disable_metadata(array $options) {
+ if (!elgg_is_valid_options_for_batch_operation($options, 'metadata')) {
+ return false;
+ }
- $entity_guid = (int)$entity_guid;
- $access = get_access_sql_suffix("e");
- $md_access = get_access_sql_suffix("m");
+ elgg_get_metadata_cache()->invalidateByOptions('disable', $options);
+
+ // if we can see hidden (disabled) we need to use the offset
+ // otherwise we risk an infinite loop if there are more than 50
+ $inc_offset = access_get_show_hidden_status();
- return get_data("SELECT m.*, n.string as name, v.string as value from {$CONFIG->dbprefix}metadata m JOIN {$CONFIG->dbprefix}entities e ON e.guid = m.entity_guid JOIN {$CONFIG->dbprefix}metastrings v on m.value_id = v.id JOIN {$CONFIG->dbprefix}metastrings n on m.name_id = n.id where m.entity_guid=$entity_guid and $access and $md_access", "row_to_elggmetadata");
+ $options['metastring_type'] = 'metadata';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback', $inc_offset);
}
/**
- * Get the metadata where the entities they are referring to match a given criteria.
- *
- * @param mixed $meta_name
- * @param mixed $meta_value
- * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
- * @param string $entity_subtype The subtype of the entity.
- * @param int $limit
- * @param int $offset
- * @param string $order_by Optional ordering.
- * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites.
+ * Enables metadata based on $options.
+ *
+ * @warning Unlike elgg_get_metadata() this will not accept an empty options array!
+ *
+ * @warning In order to enable metadata, you must first use
+ * {@link access_show_hidden_entities()}.
+ *
+ * @param array $options An options array. {@See elgg_get_metadata()}
+ * @return bool|null true on success, false on failure, null if no metadata enabled.
+ * @since 1.8.0
*/
-function find_metadata($meta_name = "", $meta_value = "", $entity_type = "", $entity_subtype = "", $limit = 10, $offset = 0, $order_by = "", $site_guid = 0) {
- global $CONFIG;
-
- $meta_n = get_metastring_id($meta_name);
- $meta_v = get_metastring_id($meta_value);
-
- $entity_type = sanitise_string($entity_type);
- $entity_subtype = get_subtype_id($entity_type, $entity_subtype);
- $limit = (int)$limit;
- $offset = (int)$offset;
- if ($order_by == "") {
- $order_by = "e.time_created desc";
- }
-
- $order_by = sanitise_string($order_by);
- $site_guid = (int) $site_guid;
- if ($site_guid == 0) {
- $site_guid = $CONFIG->site_guid;
- }
-
- $where = array();
-
- if ($entity_type!="") {
- $where[] = "e.type='$entity_type'";
- }
-
- if ($entity_subtype) {
- $where[] = "e.subtype=$entity_subtype";
- }
-
- if ($meta_name!="") {
- if (!$meta_v) {
- // The value is set, but we didn't get a value... so something went wrong.
- return false;
- }
- $where[] = "m.name_id='$meta_n'";
- }
- if ($meta_value!="") {
- // The value is set, but we didn't get a value... so something went wrong.
- if (!$meta_v) {
- return false;
- }
- $where[] = "m.value_id='$meta_v'";
- }
- if ($site_guid > 0) {
- $where[] = "e.site_guid = {$site_guid}";
+function elgg_enable_metadata(array $options) {
+ if (!$options || !is_array($options)) {
+ return false;
}
- $query = "SELECT m.*, n.string as name, v.string as value from {$CONFIG->dbprefix}entities e JOIN {$CONFIG->dbprefix}metadata m on e.guid = m.entity_guid JOIN {$CONFIG->dbprefix}metastrings v on m.value_id = v.id JOIN {$CONFIG->dbprefix}metastrings n on m.name_id = n.id where";
- foreach ($where as $w) {
- $query .= " $w and ";
- }
- $query .= get_access_sql_suffix("e"); // Add access controls
- $query .= ' and ' . get_access_sql_suffix("m"); // Add access controls
- $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
+ elgg_get_metadata_cache()->invalidateByOptions('enable', $options);
- return get_data($query, "row_to_elggmetadata");
+ $options['metastring_type'] = 'metadata';
+ return elgg_batch_metastring_based_objects($options, 'elgg_batch_enable_callback');
}
/**
+ * ElggEntities interfaces
+ */
+
+/**
* Returns entities based upon metadata. Also accepts all
* options available to elgg_get_entities(). Supports
* the singular option shortcut.
*
- * NB: Using metadata_names and metadata_values results in a
+ * @note Using metadata_names and metadata_values results in a
* "names IN (...) AND values IN (...)" clause. This is subtly
* differently than default multiple metadata_name_value_pairs, which use
* "(name = value) AND (name = value)" clauses.
*
* When in doubt, use name_value_pairs.
*
+ * To ask for entities that do not have a metadata value, use a custom
+ * where clause like this:
+ *
+ * $options['wheres'][] = "NOT EXISTS (
+ * SELECT 1 FROM {$dbprefix}metadata md
+ * WHERE md.entity_guid = e.guid
+ * AND md.name_id = $name_metastring_id
+ * AND md.value_id = $value_metastring_id)";
+ *
+ * Note the metadata name and value has been denormalized in the above example.
+ *
* @see elgg_get_entities
- * @see elgg_get_entities_from_annotations
+ *
* @param array $options Array in format:
*
* metadata_names => NULL|ARR metadata names
*
* metadata_values => NULL|ARR metadata values
*
- * metadata_name_value_pairs => NULL|ARR (name => 'name', value => 'value', 'operand' => '=', 'case_sensitive' => TRUE) entries.
- * Currently if multiple values are sent via an array (value => array('value1', 'value2') the pair's operand will be forced to "IN".
- *
- * metadata_name_value_pairs_operator => NULL|STR The operator to use for combining (name = value) OPERATOR (name = value); default AND
+ * metadata_name_value_pairs => NULL|ARR (
+ * name => 'name',
+ * value => 'value',
+ * 'operand' => '=',
+ * 'case_sensitive' => TRUE
+ * )
+ * Currently if multiple values are sent via
+ * an array (value => array('value1', 'value2')
+ * the pair's operand will be forced to "IN".
+ * If passing "IN" as the operand and a string as the value,
+ * the value must be a properly quoted and escaped string.
+ *
+ * metadata_name_value_pairs_operator => NULL|STR The operator to use for combining
+ * (name = value) OPERATOR (name = value); default AND
*
* metadata_case_sensitive => BOOL Overall Case sensitive
*
- * order_by_metadata => NULL|ARR (array('name' => 'metadata_text1', 'direction' => ASC|DESC, 'as' => text|integer),
- * Also supports array('name' => 'metadata_text1')
+ * order_by_metadata => NULL|ARR array(
+ * 'name' => 'metadata_text1',
+ * 'direction' => ASC|DESC,
+ * 'as' => text|integer
+ * )
+ * Also supports array('name' => 'metadata_text1')
*
* metadata_owner_guids => NULL|ARR guids for metadata owners
*
- * @return array
+ * @return ElggEntity[]|mixed If count, int. If not count, array. false on errors.
+ * @since 1.7.0
*/
function elgg_get_entities_from_metadata(array $options = array()) {
$defaults = array(
- 'metadata_names' => ELGG_ENTITIES_ANY_VALUE,
- 'metadata_values' => ELGG_ENTITIES_ANY_VALUE,
- 'metadata_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
+ 'metadata_names' => ELGG_ENTITIES_ANY_VALUE,
+ 'metadata_values' => ELGG_ENTITIES_ANY_VALUE,
+ 'metadata_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
- 'metadata_name_value_pairs_operator'=> 'AND',
- 'metadata_case_sensitive' => TRUE,
- 'order_by_metadata' => array(),
+ 'metadata_name_value_pairs_operator' => 'AND',
+ 'metadata_case_sensitive' => TRUE,
+ 'order_by_metadata' => array(),
- 'metadata_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'metadata_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
);
$options = array_merge($defaults, $options);
- $singulars = array('metadata_name', 'metadata_value', 'metadata_name_value_pair', 'metadata_owner_guid');
+ $singulars = array('metadata_name', 'metadata_value',
+ 'metadata_name_value_pair', 'metadata_owner_guid');
+
$options = elgg_normalise_plural_options_array($options, $singulars);
if (!$options = elgg_entities_get_metastrings_options('metadata', $options)) {
@@ -592,63 +457,6 @@ function elgg_get_entities_from_metadata(array $options = array()) {
}
/**
- * Returns options to pass to elgg_get_entities() for metastrings operations.
- *
- * @param string $type Metastring type: annotations or metadata
- * @param array $options Options
- *
- * @return array
- */
-function elgg_entities_get_metastrings_options($type, $options) {
- $valid_types = array('metadata', 'annotation');
- if (!in_array($type, $valid_types)) {
- return FALSE;
- }
-
- // the options for annotations are singular (annotation_name) but the table
- // is plural (elgg_annotations) so rewrite for the table name.
- $n_table = ($type == 'annotation') ? 'annotations' : $type;
-
- $singulars = array("{$type}_name", "{$type}_value", "{$type}_name_value_pair", "{$type}_owner_guid");
- $options = elgg_normalise_plural_options_array($options, $singulars);
-
- $clauses = elgg_get_entity_metadata_where_sql('e', $n_table, $options["{$type}_names"], $options["{$type}_values"],
- $options["{$type}_name_value_pairs"], $options["{$type}_name_value_pairs_operator"], $options["{$type}_case_sensitive"],
- $options["order_by_{$type}"], $options["{$type}_owner_guids"]);
-
- if ($clauses) {
- // merge wheres to pass to get_entities()
- if (isset($options['wheres']) && !is_array($options['wheres'])) {
- $options['wheres'] = array($options['wheres']);
- } elseif (!isset($options['wheres'])) {
- $options['wheres'] = array();
- }
-
- $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
-
- // merge joins to pass to get_entities()
- if (isset($options['joins']) && !is_array($options['joins'])) {
- $options['joins'] = array($options['joins']);
- } elseif (!isset($options['joins'])) {
- $options['joins'] = array();
- }
-
- $options['joins'] = array_merge($options['joins'], $clauses['joins']);
-
- if ($clauses['orders']) {
- $order_by_metadata = implode(", ",$clauses['orders']);
- if (isset($options['order_by']) && $options['order_by']) {
- $options['order_by'] = "$order_by_metadata, {$options['order_by']}";
- } else {
- $options['order_by'] = "$order_by_metadata, e.time_created DESC";
- }
- }
- }
-
- return $options;
-}
-
-/**
* Returns metadata name and value SQL where for entities.
* NB: $names and $values are not paired. Use $pairs for this.
* Pairs default to '=' operand.
@@ -656,17 +464,25 @@ function elgg_entities_get_metastrings_options($type, $options) {
* This function is reused for annotations because the tables are
* exactly the same.
*
- * @param string $e_table Entities table name
- * @param string $n_table Normalized metastrings table name (Where entities, values, and names are joined. annotations / metadata)
- * @param ARR|NULL $names
- * @param ARR|NULL $values
- * @param ARR|NULL $pairs array of names / values / operands
- * @param AND|OR $pair_operator Operator to use to join the where clauses for pairs
- * @param BOOL $case_sensitive
- * @param ARR|NULL $order_by_metadata array of names / direction
- * @return FALSE|array False on fail, array('joins', 'wheres')
+ * @param string $e_table Entities table name
+ * @param string $n_table Normalized metastrings table name (Where entities,
+ * values, and names are joined. annotations / metadata)
+ * @param array|null $names Array of names
+ * @param array|null $values Array of values
+ * @param array|null $pairs Array of names / values / operands
+ * @param string $pair_operator ("AND" or "OR") Operator to use to join the where clauses for pairs
+ * @param bool $case_sensitive Case sensitive metadata names?
+ * @param array|null $order_by_metadata Array of names / direction
+ * @param array|null $owner_guids Array of owner GUIDs
+ *
+ * @return false|array False on fail, array('joins', 'wheres')
+ * @since 1.7.0
+ * @access private
*/
-function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $values = NULL, $pairs = NULL, $pair_operator = 'AND', $case_sensitive = TRUE, $order_by_metadata = NULL, $owner_guids = NULL) {
+function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $values = NULL,
+$pairs = NULL, $pair_operator = 'AND', $case_sensitive = TRUE, $order_by_metadata = NULL,
+$owner_guids = NULL) {
+
global $CONFIG;
// short circuit if nothing requested
@@ -677,7 +493,7 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $
&& (!$values && $values !== 0)
&& (!$pairs && $pairs !== 0)
&& (!$owner_guids && $owner_guids !== 0)
- && !isset($order_by_metadata)) {
+ && !$order_by_metadata) {
return '';
}
@@ -698,7 +514,8 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $
);
// will always want to join these tables if pulling metastrings.
- $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table on {$e_table}.guid = n_table.entity_guid";
+ $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table on
+ {$e_table}.guid = n_table.entity_guid";
$wheres = array();
@@ -805,6 +622,8 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $
// if the operand is IN don't quote it because quoting should be done already.
if (is_numeric($pair['value'])) {
$value = sanitise_string($pair['value']);
+ } else if (is_bool($pair['value'])) {
+ $value = (int) $pair['value'];
} else if (is_array($pair['value'])) {
$values_array = array();
@@ -832,16 +651,20 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $
$name = sanitise_string($pair['name']);
// @todo The multiple joins are only needed when the operator is AND
- $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i} on {$e_table}.guid = n_table{$i}.entity_guid";
- $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} on n_table{$i}.name_id = msn{$i}.id";
- $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} on n_table{$i}.value_id = msv{$i}.id";
+ $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i}
+ on {$e_table}.guid = n_table{$i}.entity_guid";
+ $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i}
+ on n_table{$i}.name_id = msn{$i}.id";
+ $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i}
+ on n_table{$i}.value_id = msv{$i}.id";
- $pair_wheres[] = "(msn{$i}.string = '$name' AND {$pair_binary}msv{$i}.string $operand $value AND $access)";
+ $pair_wheres[] = "(msn{$i}.string = '$name' AND {$pair_binary}msv{$i}.string
+ $operand $value AND $access)";
$i++;
}
- if ($where = implode (" $pair_operator ", $pair_wheres)) {
+ if ($where = implode(" $pair_operator ", $pair_wheres)) {
$wheres[] = "($where)";
}
}
@@ -863,7 +686,7 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $
}
if (is_array($order_by_metadata)) {
- if ((count($order_by_metadata) > 0) && !is_array($order_by_metadata[0])) {
+ if ((count($order_by_metadata) > 0) && !isset($order_by_metadata[0])) {
// singleton, so fix
$order_by_metadata = array($order_by_metadata);
}
@@ -875,9 +698,12 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $
} else {
$direction = 'ASC';
}
- $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i} on {$e_table}.guid = n_table{$i}.entity_guid";
- $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i} on n_table{$i}.name_id = msn{$i}.id";
- $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i} on n_table{$i}.value_id = msv{$i}.id";
+ $return['joins'][] = "JOIN {$CONFIG->dbprefix}{$n_table} n_table{$i}
+ on {$e_table}.guid = n_table{$i}.entity_guid";
+ $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msn{$i}
+ on n_table{$i}.name_id = msn{$i}.id";
+ $return['joins'][] = "JOIN {$CONFIG->dbprefix}metastrings msv{$i}
+ on n_table{$i}.value_id = msv{$i}.id";
$access = get_access_sql_suffix("n_table{$i}");
@@ -896,272 +722,35 @@ function elgg_get_entity_metadata_where_sql($e_table, $n_table, $names = NULL, $
}
/**
- * Return a list of entities based on the given search criteria.
- *
- * @deprecated 1.7 use elgg_get_entities_from_metadata().
- * @param mixed $meta_name
- * @param mixed $meta_value
- * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
- * @param string $entity_subtype The subtype of the entity.
- * @param int $limit
- * @param int $offset
- * @param string $order_by Optional ordering.
- * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites.
- * @param true|false $count If set to true, returns the total number of entities rather than a list. (Default: false)
- * @param true|false $case_sensitive If set to false this searches for the meta data without case sensitivity. (Default: true)
- *
- * @return int|array A list of entities, or a count if $count is set to true
- */
-function get_entities_from_metadata($meta_name, $meta_value = "", $entity_type = "", $entity_subtype = "",
-$owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0,
-$count = FALSE, $case_sensitive = TRUE) {
-
- elgg_deprecated_notice('get_entities_from_metadata() was deprecated by elgg_get_entities_from_metadata()!', 1.7);
-
- $options = array();
-
- $options['metadata_names'] = $meta_name;
-
- if ($meta_value) {
- $options['metadata_values'] = $meta_value;
- }
-
- if ($entity_type) {
- $options['types'] = $entity_type;
- }
-
- if ($entity_subtype) {
- $options['subtypes'] = $entity_subtype;
- }
-
- if ($owner_guid) {
- $options['owner_guid'] = $owner_guid;
- }
-
- if ($limit) {
- $options['limit'] = $limit;
- }
-
- if ($offset) {
- $options['offset'] = $offset;
- }
-
- if ($order_by) {
- $options['order_by'];
- }
-
- if ($site_guid) {
- $options['site_guid'];
- }
-
- if ($count) {
- $options['count'] = $count;
- }
-
- // need to be able to pass false
- $options['metadata_case_sensitive'] = $case_sensitive;
-
- return elgg_get_entities_from_metadata($options);
-}
-
-/**
- * Return a list of entities suitable for display based on the given search criteria.
- *
- * @see elgg_view_entity_list
- *
- * @deprecated 1.8 Use elgg_list_entities_from_metadata
- * @param mixed $meta_name Metadata name to search on
- * @param mixed $meta_value The value to match, optionally
- * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
- * @param string $entity_subtype The subtype of the entity
- * @param int $limit Number of entities to display per page
- * @param true|false $fullview Whether or not to display the full view (default: true)
- * @param true|false $viewtypetoggle Whether or not to allow users to toggle to the gallery view. Default: true
- * @param true|false $pagination Display pagination? Default: true
- *
- * @return string A list of entities suitable for display
- */
-function list_entities_from_metadata($meta_name, $meta_value = "", $entity_type = ELGG_ENTITIES_ANY_VALUE, $entity_subtype = ELGG_ENTITIES_ANY_VALUE, $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = true, $pagination = true, $case_sensitive = true ) {
- elgg_deprecated_notice('get_entities_from_metadata_multi() was deprecated by elgg_get_entities_from_metadata()!', 1.8);
-
- $offset = (int) get_input('offset');
- $limit = (int) $limit;
- $options = array(
- 'metadata_name' => $meta_name,
- 'metadata_value' => $meta_value,
- 'types' => $entity_type,
- 'subtypes' => $entity_subtype,
- 'owner_guid' => $owner_guid,
- 'limit' => $limit,
- 'offset' => $offset,
- 'count' => TRUE,
- 'metadata_case_sensitive' => $case_sensitive
- );
- $count = elgg_get_entities_from_metadata($options);
-
- $options['count'] = FALSE;
- $entities = elgg_get_entities_from_metadata($options);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination);
-}
-
-/**
* Returns a list of entities filtered by provided metadata.
*
* @see elgg_get_entities_from_metadata
*
- * @param array $options
+ * @param array $options Options array
+ *
+ * @return array
+ * @since 1.7.0
*/
function elgg_list_entities_from_metadata($options) {
- $defaults = array(
- 'offset' => (int) max(get_input('offset', 0), 0),
- 'limit' => (int) max(get_input('limit', 10), 0),
- 'full_view' => TRUE,
- 'view_type_toggle' => FALSE,
- 'pagination' => TRUE
- );
-
- $options = array_merge($defaults, $options);
-
- $count = elgg_get_entities_from_metadata(array_merge(array('count' => TRUE), $options));
- $entities = elgg_get_entities_from_metadata($options);
-
- return elgg_view_entity_list($entities, $count, $options['offset'], $options['limit'], $options['full_view'], $options['view_type_toggle'], $options['pagination']);
-}
-
-/**
- * @deprecated 1.7. Use elgg_get_entities_from_metadata().
- * @param $meta_array
- * @param $entity_type
- * @param $entity_subtype
- * @param $owner_guid
- * @param $limit
- * @param $offset
- * @param $order_by
- * @param $site_guid
- * @param $count
- * @param $meta_array_operator
- * @return unknown_type
- */
-function get_entities_from_metadata_multi($meta_array, $entity_type = "", $entity_subtype = "",
-$owner_guid = 0, $limit = 10, $offset = 0, $order_by = "", $site_guid = 0,
-$count = false, $meta_array_operator = 'and') {
- elgg_deprecated_notice('get_entities_from_metadata_multi() was deprecated by elgg_get_entities_from_metadata()!', 1.7);
-
- if (!is_array($meta_array) || sizeof($meta_array) == 0) {
- return false;
- }
-
- $options = array();
-
- $options['metadata_name_value_pairs'] = $meta_array;
-
- if ($entity_type) {
- $options['types'] = $entity_type;
- }
-
- if ($entity_subtype) {
- $options['subtypes'] = $entity_subtype;
- }
-
- if ($owner_guid) {
- $options['owner_guid'] = $owner_guid;
- }
-
- if ($limit) {
- $options['limit'] = $limit;
- }
-
- if ($offset) {
- $options['offset'] = $offset;
- }
-
- if ($order_by) {
- $options['order_by'];
- }
-
- if ($site_guid) {
- $options['site_guid'];
- }
-
- if ($count) {
- $options['count'] = $count;
- }
-
- $options['metadata_name_value_pairs_operator'] = $meta_array_operator;
-
- return elgg_get_entities_from_metadata($options);
+ return elgg_list_entities($options, 'elgg_get_entities_from_metadata');
}
/**
- * Returns a viewable list of entities based on the given search criteria.
- *
- * @see elgg_view_entity_list
- *
- * @param array $meta_array Array of 'name' => 'value' pairs
- * @param string $entity_type The type of entity to look for, eg 'site' or 'object'
- * @param string $entity_subtype The subtype of the entity.
- * @param int $limit
- * @param int $offset
- * @param string $order_by Optional ordering.
- * @param true|false $fullview Whether or not to display the full view (default: true)
- * @param true|false $viewtypetoggle Whether or not to allow users to toggle to the gallery view. Default: true
- * @param true|false $pagination Display pagination? Default: true
- * @return string List of ElggEntities suitable for display
+ * Other functions
*/
-function list_entities_from_metadata_multi($meta_array, $entity_type = "", $entity_subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = true, $pagination = true) {
- $offset = (int) get_input('offset');
- $limit = (int) $limit;
- $count = get_entities_from_metadata_multi($meta_array, $entity_type, $entity_subtype, $owner_guid, $limit, $offset, "", $site_guid, true);
- $entities = get_entities_from_metadata_multi($meta_array, $entity_type, $entity_subtype, $owner_guid, $limit, $offset, "", $site_guid, false);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination);
-}
/**
- * Clear all the metadata for a given entity, assuming you have access to that metadata.
+ * Handler called by trigger_plugin_hook on the "export" event.
*
- * @param int $guid
- */
-function clear_metadata($entity_guid) {
- global $CONFIG;
-
- $entity_guid = (int)$entity_guid;
- if ($entity = get_entity($entity_guid)) {
- if ($entity->canEdit()) {
- return delete_data("DELETE from {$CONFIG->dbprefix}metadata where entity_guid={$entity_guid}");
- }
- }
- return false;
-}
-
-/**
- * Clear all annotations belonging to a given owner_guid
+ * @param string $hook export
+ * @param string $entity_type all
+ * @param mixed $returnvalue Value returned from previous hook
+ * @param mixed $params Params
*
- * @param int $owner_guid The owner
- */
-function clear_metadata_by_owner($owner_guid) {
- global $CONFIG;
-
- $owner_guid = (int)$owner_guid;
-
- $metas = get_data("SELECT id from {$CONFIG->dbprefix}metadata WHERE owner_guid=$owner_guid");
- $deleted = 0;
-
- if (is_array($metas)) {
- foreach ($metas as $id) {
- // Is this the best way?
- if (delete_metadata($id->id)) {
- $deleted++;
- }
- }
- }
-
- return $deleted;
-}
-
-/**
- * Handler called by trigger_plugin_hook on the "export" event.
+ * @return array
+ * @access private
+ *
+ * @throws InvalidParameterException
*/
function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params) {
// Sanity check values
@@ -1173,12 +762,13 @@ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params)
throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonArrayReturnValue'));
}
- $guid = (int)$params['guid'];
- $name = $params['name'];
-
- $result = get_metadata_for_entity($guid);
+ $result = elgg_get_metadata(array(
+ 'guid' => (int)$params['guid'],
+ 'limit' => 0,
+ ));
if ($result) {
+ /* @var ElggMetadata[] $result */
foreach ($result as $r) {
$returnvalue[] = $r->export();
}
@@ -1188,34 +778,37 @@ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params)
}
/**
- * Takes in a comma-separated string and returns an array of tags which have been trimmed and set to lower case
+ * Takes in a comma-separated string and returns an array of tags
+ * which have been trimmed
*
* @param string $string Comma-separated tag string
+ *
* @return array|false An array of strings, or false on failure
*/
function string_to_tag_array($string) {
if (is_string($string)) {
- $ar = explode(",",$string);
- $ar = array_map('trim', $ar); // trim blank spaces
- $ar = array_map('elgg_strtolower', $ar); // make lower case : [Marcus Povey 20090605 - Using mb wrapper function using UTF8 safe function where available]
- $ar = array_filter($ar, 'is_not_null'); // Remove null values
+ $ar = explode(",", $string);
+ $ar = array_map('trim', $ar);
+ $ar = array_filter($ar, 'is_not_null');
+ $ar = array_map('strip_tags', $ar);
return $ar;
}
return false;
-
}
/**
- * Takes a metadata array (which has all kinds of properties) and turns it into a simple array of strings
+ * Takes a metadata array (which has all kinds of properties)
+ * and turns it into a simple array of strings
*
* @param array $array Metadata array
+ *
* @return array Array of strings
*/
function metadata_array_to_values($array) {
$valuearray = array();
if (is_array($array)) {
- foreach($array as $element) {
+ foreach ($array as $element) {
$valuearray[] = $element->value;
}
}
@@ -1224,14 +817,18 @@ function metadata_array_to_values($array) {
}
/**
- * Get the URL for this item of metadata, by default this links to the export handler in the current view.
+ * Get the URL for this metadata
+ *
+ * By default this links to the export handler in the current view.
*
- * @param int $id
+ * @param int $id Metadata ID
+ *
+ * @return mixed
*/
function get_metadata_url($id) {
$id = (int)$id;
- if ($extender = get_metadata($id)) {
+ if ($extender = elgg_get_metadata_from_id($id)) {
return get_extender_url($extender);
}
return false;
@@ -1241,8 +838,10 @@ function get_metadata_url($id) {
* Mark entities with a particular type and subtype as having access permissions
* that can be changed independently from their parent entity
*
- * @param string $type The type - object, user, etc
+ * @param string $type The type - object, user, etc
* @param string $subtype The subtype; all subtypes by default
+ *
+ * @return void
*/
function register_metadata_as_independent($type, $subtype = '*') {
global $CONFIG;
@@ -1256,9 +855,10 @@ function register_metadata_as_independent($type, $subtype = '*') {
* Determines whether entities of a given type and subtype should not change
* their metadata in line with their parent entity
*
- * @param string $type The type - object, user, etc
+ * @param string $type The type - object, user, etc
* @param string $subtype The entity subtype
- * @return true|false
+ *
+ * @return bool
*/
function is_metadata_independent($type, $subtype) {
global $CONFIG;
@@ -1275,17 +875,20 @@ function is_metadata_independent($type, $subtype) {
/**
* When an entity is updated, resets the access ID on all of its child metadata
*
- * @param string $event The name of the event
- * @param string $object_type The type of object
- * @param ElggEntity $object The entity itself
+ * @param string $event The name of the event
+ * @param string $object_type The type of object
+ * @param ElggEntity $object The entity itself
+ *
+ * @return true
*/
function metadata_update($event, $object_type, $object) {
if ($object instanceof ElggEntity) {
if (!is_metadata_independent($object->getType(), $object->getSubtype())) {
- global $CONFIG;
+ $db_prefix = elgg_get_config('dbprefix');
$access_id = (int) $object->access_id;
$guid = (int) $object->getGUID();
- update_data("update {$CONFIG->dbprefix}metadata set access_id = {$access_id} where entity_guid = {$guid}");
+ $query = "update {$db_prefix}metadata set access_id = {$access_id} where entity_guid = {$guid}";
+ update_data($query);
}
}
return true;
@@ -1294,22 +897,82 @@ function metadata_update($event, $object_type, $object) {
/**
* Register a metadata url handler.
*
- * @param string $function_name The function.
* @param string $extender_name The name, default 'all'.
+ * @param string $function The function name.
+ *
+ * @return bool
*/
-function register_metadata_url_handler($function_name, $extender_name = "all") {
- return register_extender_url_handler($function_name, 'metadata', $extender_name);
+function elgg_register_metadata_url_handler($extender_name, $function) {
+ return elgg_register_extender_url_handler('metadata', $extender_name, $function);
+}
+
+/**
+ * Get the global metadata cache instance
+ *
+ * @return ElggVolatileMetadataCache
+ *
+ * @access private
+ */
+function elgg_get_metadata_cache() {
+ global $CONFIG;
+ if (empty($CONFIG->local_metadata_cache)) {
+ $CONFIG->local_metadata_cache = new ElggVolatileMetadataCache();
+ }
+ return $CONFIG->local_metadata_cache;
+}
+
+/**
+ * Invalidate the metadata cache based on options passed to various *_metadata functions
+ *
+ * @param string $action Action performed on metadata. "delete", "disable", or "enable"
+ * @param array $options Options passed to elgg_(delete|disable|enable)_metadata
+ * @return void
+ */
+function elgg_invalidate_metadata_cache($action, array $options) {
+ // remove as little as possible, optimizing for common cases
+ $cache = elgg_get_metadata_cache();
+ if (empty($options['guid'])) {
+ // safest to clear everything unless we want to make this even more complex :(
+ $cache->flush();
+ } else {
+ if (empty($options['metadata_name'])) {
+ // safest to clear the whole entity
+ $cache->clear($options['guid']);
+ } else {
+ switch ($action) {
+ case 'delete':
+ $cache->markEmpty($options['guid'], $options['metadata_name']);
+ break;
+ default:
+ $cache->markUnknown($options['guid'], $options['metadata_name']);
+ }
+ }
+ }
}
/** Register the hook */
-register_plugin_hook("export", "all", "export_metadata_plugin_hook", 2);
+elgg_register_plugin_hook_handler("export", "all", "export_metadata_plugin_hook", 2);
+
/** Call a function whenever an entity is updated **/
-register_elgg_event_handler('update','all','metadata_update');
+elgg_register_event_handler('update', 'all', 'metadata_update');
// unit testing
-register_plugin_hook('unit_test', 'system', 'metadata_test');
+elgg_register_plugin_hook_handler('unit_test', 'system', 'metadata_test');
+
+/**
+ * Metadata unit test
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of other tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
+ */
function metadata_test($hook, $type, $value, $params) {
global $CONFIG;
- $value[] = $CONFIG->path . 'engine/tests/objects/metadata.php';
+ $value[] = $CONFIG->path . 'engine/tests/api/metadata.php';
+ $value[] = $CONFIG->path . 'engine/tests/api/metadata_cache.php';
return $value;
}
diff --git a/engine/lib/metastrings.php b/engine/lib/metastrings.php
index 71f32a786..57d876c06 100644
--- a/engine/lib/metastrings.php
+++ b/engine/lib/metastrings.php
@@ -3,35 +3,39 @@
* Elgg metastrngs
* Functions to manage object metastrings.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage DataModel.MetaStrings
*/
/** Cache metastrings for a page */
+global $METASTRINGS_CACHE;
$METASTRINGS_CACHE = array();
/** Keep a record of strings we know don't exist */
+global $METASTRINGS_DEADNAME_CACHE;
$METASTRINGS_DEADNAME_CACHE = array();
+
+
/**
* Return the meta string id for a given tag, or false.
*
- * @param string $string The value (whatever that is) to be stored
- * @param bool $case_sensitive Do we want to make the query case sensitive? If not there may be more than one result
- * @return int|array|false meta string id, array of ids or false if none found
+ * @param string $string The value to store
+ * @param bool $case_sensitive Do we want to make the query case sensitive?
+ * If not there may be more than one result
+ *
+ * @return int|array|false meta string id, array of ids or false if none found
*/
function get_metastring_id($string, $case_sensitive = TRUE) {
global $CONFIG, $METASTRINGS_CACHE, $METASTRINGS_DEADNAME_CACHE;
$string = sanitise_string($string);
-
- // caching doesn't work for case insensitive searches
- if ($case_sensitive) {
+
+ // caching doesn't work for case insensitive searches
+ if ($case_sensitive) {
$result = array_search($string, $METASTRINGS_CACHE, true);
-
- if ($result!==false) {
+
+ if ($result !== false) {
elgg_log("** Returning id for string:$string from cache.");
return $result;
}
@@ -40,7 +44,7 @@ function get_metastring_id($string, $case_sensitive = TRUE) {
if (in_array($string, $METASTRINGS_DEADNAME_CACHE, true)) {
return false;
}
-
+
// Experimental memcache
$msfc = null;
static $metastrings_memcache;
@@ -63,19 +67,19 @@ function get_metastring_id($string, $case_sensitive = TRUE) {
}
$row = FALSE;
- $metaStrings = get_data($query, "entity_row_to_elggstar");
+ $metaStrings = get_data($query);
if (is_array($metaStrings)) {
if (sizeof($metaStrings) > 1) {
$ids = array();
- foreach($metaStrings as $metaString) {
+ foreach ($metaStrings as $metaString) {
$ids[] = $metaString->id;
}
return $ids;
- } else {
+ } else if (isset($metaStrings[0])) {
$row = $metaStrings[0];
}
}
-
+
if ($row) {
$METASTRINGS_CACHE[$row->id] = $row->string; // Cache it
@@ -98,6 +102,7 @@ function get_metastring_id($string, $case_sensitive = TRUE) {
* When given an ID, returns the corresponding metastring
*
* @param int $id Metastring ID
+ *
* @return string Metastring
*/
function get_metastring($id) {
@@ -126,8 +131,9 @@ function get_metastring($id) {
* Add a metastring.
* It returns the id of the tag, whether by creating it or updating it.
*
- * @param string $string The value (whatever that is) to be stored
- * @param bool $case_sensitive Do we want to make the query case sensitive?
+ * @param string $string The value (whatever that is) to be stored
+ * @param bool $case_sensitive Do we want to make the query case sensitive?
+ *
* @return mixed Integer tag or false.
*/
function add_metastring($string, $case_sensitive = true) {
@@ -154,6 +160,8 @@ function add_metastring($string, $case_sensitive = true) {
/**
* Delete any orphaned entries in metastrings. This is run by the garbage collector.
*
+ * @return bool
+ * @access private
*/
function delete_orphaned_metastrings() {
global $CONFIG;
@@ -194,4 +202,702 @@ function delete_orphaned_metastrings() {
)";
return delete_data($query);
-} \ No newline at end of file
+}
+
+/**
+ * Returns an array of either ElggAnnotation or ElggMetadata objects.
+ * Accepts all elgg_get_entities() options for entity restraints.
+ *
+ * @see elgg_get_entities
+ *
+ * @param array $options Array in format:
+ *
+ * metastring_names => NULL|ARR metastring names
+ *
+ * metastring_values => NULL|ARR metastring values
+ *
+ * metastring_ids => NULL|ARR metastring ids
+ *
+ * metastring_case_sensitive => BOOL Overall Case sensitive
+ *
+ * metastring_owner_guids => NULL|ARR Guids for metadata owners
+ *
+ * metastring_created_time_lower => INT Lower limit for created time.
+ *
+ * metastring_created_time_upper => INT Upper limit for created time.
+ *
+ * metastring_calculation => STR Perform the MySQL function on the metastring values
+ * returned.
+ * This differs from egef_annotation_calculation in that
+ * it returns only the calculation of all annotation values.
+ * You can sum, avg, count, etc. egef_annotation_calculation()
+ * returns ElggEntities ordered by a calculation on their
+ * annotation values.
+ *
+ * metastring_type => STR metadata or annotation(s)
+ *
+ * @return mixed
+ * @access private
+ */
+function elgg_get_metastring_based_objects($options) {
+ $options = elgg_normalize_metastrings_options($options);
+
+ switch ($options['metastring_type']) {
+ case 'metadata':
+ $type = 'metadata';
+ $callback = 'row_to_elggmetadata';
+ break;
+
+ case 'annotations':
+ case 'annotation':
+ $type = 'annotations';
+ $callback = 'row_to_elggannotation';
+ break;
+
+ default:
+ return false;
+ }
+
+ $defaults = array(
+ // entities
+ 'types' => ELGG_ENTITIES_ANY_VALUE,
+ 'subtypes' => ELGG_ENTITIES_ANY_VALUE,
+ 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
+
+ 'guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'owner_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'container_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'site_guids' => get_config('site_guid'),
+
+ 'modified_time_lower' => ELGG_ENTITIES_ANY_VALUE,
+ 'modified_time_upper' => ELGG_ENTITIES_ANY_VALUE,
+ 'created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
+ 'created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
+
+ // options are normalized to the plural in case we ever add support for them.
+ 'metastring_names' => ELGG_ENTITIES_ANY_VALUE,
+ 'metastring_values' => ELGG_ENTITIES_ANY_VALUE,
+ //'metastring_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
+ //'metastring_name_value_pairs_operator' => 'AND',
+
+ 'metastring_case_sensitive' => TRUE,
+ //'order_by_metastring' => array(),
+ 'metastring_calculation' => ELGG_ENTITIES_NO_VALUE,
+
+ 'metastring_created_time_lower' => ELGG_ENTITIES_ANY_VALUE,
+ 'metastring_created_time_upper' => ELGG_ENTITIES_ANY_VALUE,
+
+ 'metastring_owner_guids' => ELGG_ENTITIES_ANY_VALUE,
+
+ 'metastring_ids' => ELGG_ENTITIES_ANY_VALUE,
+
+ // sql
+ 'order_by' => 'n_table.time_created asc',
+ 'limit' => 10,
+ 'offset' => 0,
+ 'count' => FALSE,
+ 'selects' => array(),
+ 'wheres' => array(),
+ 'joins' => array(),
+
+ 'callback' => $callback
+ );
+
+ // @todo Ignore site_guid right now because of #2910
+ $options['site_guid'] = ELGG_ENTITIES_ANY_VALUE;
+
+ $options = array_merge($defaults, $options);
+
+ // can't use helper function with type_subtype_pair because
+ // it's already an array...just need to merge it
+ if (isset($options['type_subtype_pair'])) {
+ if (isset($options['type_subtype_pairs'])) {
+ $options['type_subtype_pairs'] = array_merge($options['type_subtype_pairs'],
+ $options['type_subtype_pair']);
+ } else {
+ $options['type_subtype_pairs'] = $options['type_subtype_pair'];
+ }
+ }
+
+ $singulars = array(
+ 'type', 'subtype', 'type_subtype_pair',
+ 'guid', 'owner_guid', 'container_guid', 'site_guid',
+ 'metastring_name', 'metastring_value',
+ 'metastring_owner_guid', 'metastring_id',
+ 'select', 'where', 'join'
+ );
+
+ $options = elgg_normalise_plural_options_array($options, $singulars);
+
+ if (!$options) {
+ return false;
+ }
+
+ $db_prefix = elgg_get_config('dbprefix');
+
+ // evaluate where clauses
+ if (!is_array($options['wheres'])) {
+ $options['wheres'] = array($options['wheres']);
+ }
+
+ $wheres = $options['wheres'];
+
+ // entities
+ $wheres[] = elgg_get_entity_type_subtype_where_sql('e', $options['types'],
+ $options['subtypes'], $options['type_subtype_pairs']);
+
+ $wheres[] = elgg_get_guid_based_where_sql('e.guid', $options['guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']);
+
+ $wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
+ $options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
+
+
+ $wheres[] = elgg_get_entity_time_where_sql('n_table', $options['metastring_created_time_upper'],
+ $options['metastring_created_time_lower'], null, null);
+
+ $wheres[] = elgg_get_guid_based_where_sql('n_table.owner_guid',
+ $options['metastring_owner_guids']);
+
+ // see if any functions failed
+ // remove empty strings on successful functions
+ foreach ($wheres as $i => $where) {
+ if ($where === FALSE) {
+ return FALSE;
+ } elseif (empty($where)) {
+ unset($wheres[$i]);
+ }
+ }
+
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
+
+ // evaluate join clauses
+ if (!is_array($options['joins'])) {
+ $options['joins'] = array($options['joins']);
+ }
+
+ $joins = $options['joins'];
+ $joins[] = "JOIN {$db_prefix}entities e ON n_table.entity_guid = e.guid";
+
+ // evaluate selects
+ if (!is_array($options['selects'])) {
+ $options['selects'] = array($options['selects']);
+ }
+
+ $selects = $options['selects'];
+
+ // For performance reasons we don't want the joins required for metadata / annotations
+ // unless we're going through one of their callbacks.
+ // this means we expect the functions passing different callbacks to pass their required joins.
+ // If we're doing a calculation
+ $custom_callback = ($options['callback'] == 'row_to_elggmetadata'
+ || $options['callback'] == 'row_to_elggannotation');
+ $is_calculation = $options['metastring_calculation'] ? true : false;
+
+ if ($custom_callback || $is_calculation) {
+ $joins[] = "JOIN {$db_prefix}metastrings n on n_table.name_id = n.id";
+ $joins[] = "JOIN {$db_prefix}metastrings v on n_table.value_id = v.id";
+
+ $selects[] = 'n.string as name';
+ $selects[] = 'v.string as value';
+ }
+
+ foreach ($joins as $i => $join) {
+ if ($join === FALSE) {
+ return FALSE;
+ } elseif (empty($join)) {
+ unset($joins[$i]);
+ }
+ }
+
+ // metastrings
+ $metastring_clauses = elgg_get_metastring_sql('n_table', $options['metastring_names'],
+ $options['metastring_values'], null, $options['metastring_ids'],
+ $options['metastring_case_sensitive']);
+
+ if ($metastring_clauses) {
+ $wheres = array_merge($wheres, $metastring_clauses['wheres']);
+ $joins = array_merge($joins, $metastring_clauses['joins']);
+ } else {
+ $wheres[] = get_access_sql_suffix('n_table');
+ }
+
+ if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) {
+ $selects = array_unique($selects);
+ // evalutate selects
+ $select_str = '';
+ if ($selects) {
+ foreach ($selects as $select) {
+ $select_str .= ", $select";
+ }
+ }
+
+ $query = "SELECT DISTINCT n_table.*{$select_str} FROM {$db_prefix}$type n_table";
+ } elseif ($options['count']) {
+ // count is over the entities
+ $query = "SELECT count(DISTINCT e.guid) as calculation FROM {$db_prefix}$type n_table";
+ } else {
+ $query = "SELECT {$options['metastring_calculation']}(v.string) as calculation FROM {$db_prefix}$type n_table";
+ }
+
+ // remove identical join clauses
+ $joins = array_unique($joins);
+
+ // add joins
+ foreach ($joins as $j) {
+ $query .= " $j ";
+ }
+
+ // add wheres
+ $query .= ' WHERE ';
+
+ foreach ($wheres as $w) {
+ $query .= " $w AND ";
+ }
+
+ // Add access controls
+ $query .= get_access_sql_suffix('e');
+
+ // reverse order by
+ if (isset($options['reverse_order_by']) && $options['reverse_order_by']) {
+ $options['order_by'] = elgg_sql_reverse_order_by_clause($options['order_by'],
+ $defaults['order_by']);
+ }
+
+ if ($options['metastring_calculation'] === ELGG_ENTITIES_NO_VALUE && !$options['count']) {
+ if (isset($options['group_by'])) {
+ $options['group_by'] = sanitise_string($options['group_by']);
+ $query .= " GROUP BY {$options['group_by']}";
+ }
+
+ if (isset($options['order_by']) && $options['order_by']) {
+ $options['order_by'] = sanitise_string($options['order_by']);
+ $query .= " ORDER BY {$options['order_by']}, n_table.id";
+ }
+
+ if ($options['limit']) {
+ $limit = sanitise_int($options['limit']);
+ $offset = sanitise_int($options['offset'], false);
+ $query .= " LIMIT $offset, $limit";
+ }
+
+ $dt = get_data($query, $options['callback']);
+ return $dt;
+ } else {
+ $result = get_data_row($query);
+ return $result->calculation;
+ }
+}
+
+/**
+ * Returns an array of joins and wheres for use in metastrings.
+ *
+ * @note The $pairs is reserved for name/value pairs if we want to implement those.
+ *
+ * @param string $table The annotation or metadata table name or alias
+ * @param array $names An array of names
+ * @param array $values An array of values
+ * @param array $pairs Name / value pairs. Not currently used.
+ * @param array $ids Metastring IDs
+ * @param bool $case_sensitive Should name and values be case sensitive?
+ *
+ * @return array
+ * @access private
+ */
+function elgg_get_metastring_sql($table, $names = null, $values = null,
+ $pairs = null, $ids = null, $case_sensitive = false) {
+
+ if ((!$names && $names !== 0)
+ && (!$values && $values !== 0)
+ && !$ids
+ && (!$pairs && $pairs !== 0)) {
+
+ return array();
+ }
+
+ $db_prefix = elgg_get_config('dbprefix');
+
+ // binary forces byte-to-byte comparision of strings, making
+ // it case- and diacritical-mark- sensitive.
+ // only supported on values.
+ $binary = ($case_sensitive) ? ' BINARY ' : '';
+
+ $return = array (
+ 'joins' => array (),
+ 'wheres' => array()
+ );
+
+ $wheres = array();
+
+ // get names wheres and joins
+ $names_where = '';
+ if ($names !== NULL) {
+ if (!is_array($names)) {
+ $names = array($names);
+ }
+
+ $sanitised_names = array();
+ foreach ($names as $name) {
+ // normalise to 0.
+ if (!$name) {
+ $name = '0';
+ }
+ $sanitised_names[] = '\'' . sanitise_string($name) . '\'';
+ }
+
+ if ($names_str = implode(',', $sanitised_names)) {
+ $return['joins'][] = "JOIN {$db_prefix}metastrings msn on $table.name_id = msn.id";
+ $names_where = "(msn.string IN ($names_str))";
+ }
+ }
+
+ // get values wheres and joins
+ $values_where = '';
+ if ($values !== NULL) {
+ if (!is_array($values)) {
+ $values = array($values);
+ }
+
+ $sanitised_values = array();
+ foreach ($values as $value) {
+ // normalize to 0
+ if (!$value) {
+ $value = 0;
+ }
+ $sanitised_values[] = '\'' . sanitise_string($value) . '\'';
+ }
+
+ if ($values_str = implode(',', $sanitised_values)) {
+ $return['joins'][] = "JOIN {$db_prefix}metastrings msv on $table.value_id = msv.id";
+ $values_where = "({$binary}msv.string IN ($values_str))";
+ }
+ }
+
+ if ($ids !== NULL) {
+ if (!is_array($ids)) {
+ $ids = array($ids);
+ }
+
+ $ids_str = implode(',', $ids);
+
+ if ($ids_str) {
+ $wheres[] = "n_table.id IN ($ids_str)";
+ }
+ }
+
+ if ($names_where && $values_where) {
+ $wheres[] = "($names_where AND $values_where)";
+ } elseif ($names_where) {
+ $wheres[] = $names_where;
+ } elseif ($values_where) {
+ $wheres[] = $values_where;
+ }
+
+ $wheres[] = get_access_sql_suffix($table);
+
+ if ($where = implode(' AND ', $wheres)) {
+ $return['wheres'][] = "($where)";
+ }
+
+ return $return;
+}
+
+/**
+ * Normalizes metadata / annotation option names to their corresponding metastrings name.
+ *
+ * @param array $options An options array
+ * @since 1.8.0
+ * @return array
+ * @access private
+ */
+function elgg_normalize_metastrings_options(array $options = array()) {
+
+ // support either metastrings_type or metastring_type
+ // because I've made this mistake many times and hunting it down is a pain...
+ $type = elgg_extract('metastring_type', $options, null);
+ $type = elgg_extract('metastrings_type', $options, $type);
+
+ $options['metastring_type'] = $type;
+
+ // support annotation_ and annotations_ because they're way too easy to confuse
+ $prefixes = array('metadata_', 'annotation_', 'annotations_');
+
+ // map the metadata_* options to metastring_* options
+ $map = array(
+ 'names' => 'metastring_names',
+ 'values' => 'metastring_values',
+ 'case_sensitive' => 'metastring_case_sensitive',
+ 'owner_guids' => 'metastring_owner_guids',
+ 'created_time_lower' => 'metastring_created_time_lower',
+ 'created_time_upper' => 'metastring_created_time_upper',
+ 'calculation' => 'metastring_calculation',
+ 'ids' => 'metastring_ids'
+ );
+
+ foreach ($prefixes as $prefix) {
+ $singulars = array("{$prefix}name", "{$prefix}value", "{$prefix}owner_guid", "{$prefix}id");
+ $options = elgg_normalise_plural_options_array($options, $singulars);
+
+ foreach ($map as $specific => $normalized) {
+ $key = $prefix . $specific;
+ if (isset($options[$key])) {
+ $options[$normalized] = $options[$key];
+ }
+ }
+ }
+
+ return $options;
+}
+
+/**
+ * Enables or disables a metastrings-based object by its id.
+ *
+ * @warning To enable disabled metastrings you must first use
+ * {@link access_show_hidden_entities()}.
+ *
+ * @param int $id The object's ID
+ * @param string $enabled Value to set to: yes or no
+ * @param string $type The type of table to use: metadata or annotations
+ *
+ * @return bool
+ * @throws InvalidParameterException
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_set_metastring_based_object_enabled_by_id($id, $enabled, $type) {
+ $id = (int)$id;
+ $db_prefix = elgg_get_config('dbprefix');
+
+ $object = elgg_get_metastring_based_object_from_id($id, $type);
+
+ switch($type) {
+ case 'annotation':
+ case 'annotations':
+ $table = "{$db_prefix}annotations";
+ break;
+
+ case 'metadata':
+ $table = "{$db_prefix}metadata";
+ break;
+ }
+
+ if ($enabled === 'yes' || $enabled === 1 || $enabled === true) {
+ $enabled = 'yes';
+ $event = 'enable';
+ } elseif ($enabled === 'no' || $enabled === 0 || $enabled === false) {
+ $enabled = 'no';
+ $event = 'disable';
+ } else {
+ return false;
+ }
+
+ $return = false;
+
+ if ($object) {
+ // don't set it if it's already set.
+ if ($object->enabled == $enabled) {
+ $return = false;
+ } elseif ($object->canEdit() && (elgg_trigger_event($event, $type, $object))) {
+ $return = update_data("UPDATE $table SET enabled = '$enabled' where id = $id");
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Runs metastrings-based objects found using $options through $callback
+ *
+ * @warning Unlike elgg_get_metastring_based_objects() this will not accept an
+ * empty options array!
+ *
+ * @warning This returns null on no ops.
+ *
+ * @param array $options An options array. {@See elgg_get_metastring_based_objects()}
+ * @param string $callback The callback to pass each result through
+ * @param bool $inc_offset Increment the offset? Pass false for callbacks that delete / disable
+ *
+ * @return bool|null true on success, false on failure, null if no objects are found.
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_batch_metastring_based_objects(array $options, $callback, $inc_offset = true) {
+ if (!$options || !is_array($options)) {
+ return false;
+ }
+
+ $batch = new ElggBatch('elgg_get_metastring_based_objects', $options, $callback, 50, $inc_offset);
+ return $batch->callbackResult;
+}
+
+/**
+ * Returns a singular metastring-based object by its ID.
+ *
+ * @param int $id The metastring-based object's ID
+ * @param string $type The type: annotation or metadata
+ * @return ElggMetadata|ElggAnnotation
+ *
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_get_metastring_based_object_from_id($id, $type) {
+ $id = (int)$id;
+ if (!$id) {
+ return false;
+ }
+
+ $options = array(
+ 'metastring_type' => $type,
+ 'metastring_id' => $id
+ );
+
+ $obj = elgg_get_metastring_based_objects($options);
+
+ if ($obj && count($obj) == 1) {
+ return $obj[0];
+ }
+
+ return false;
+}
+
+/**
+ * Deletes a metastring-based object by its id
+ *
+ * @param int $id The object's ID
+ * @param string $type The object's metastring type: annotation or metadata
+ * @return bool
+ *
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_delete_metastring_based_object_by_id($id, $type) {
+ $id = (int)$id;
+ $db_prefix = elgg_get_config('dbprefix');
+
+ switch ($type) {
+ case 'annotation':
+ case 'annotations':
+ $type = 'annotations';
+ break;
+
+ case 'metadata':
+ $type = 'metadata';
+ break;
+
+ default:
+ return false;
+ }
+
+ $obj = elgg_get_metastring_based_object_from_id($id, $type);
+ $table = $db_prefix . $type;
+
+ if ($obj) {
+ // Tidy up if memcache is enabled.
+ // @todo only metadata is supported
+ if ($type == 'metadata') {
+ static $metabyname_memcache;
+ if ((!$metabyname_memcache) && (is_memcache_available())) {
+ $metabyname_memcache = new ElggMemcache('metabyname_memcache');
+ }
+
+ if ($metabyname_memcache) {
+ // @todo why name_id? is that even populated?
+ $metabyname_memcache->delete("{$obj->entity_guid}:{$obj->name_id}");
+ }
+ }
+
+ if (($obj->canEdit()) && (elgg_trigger_event('delete', $type, $obj))) {
+ return (bool)delete_data("DELETE from $table where id=$id");
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Entities interface helpers
+ */
+
+/**
+ * Returns options to pass to elgg_get_entities() for metastrings operations.
+ *
+ * @param string $type Metastring type: annotations or metadata
+ * @param array $options Options
+ *
+ * @return array
+ * @since 1.7.0
+ * @access private
+ */
+function elgg_entities_get_metastrings_options($type, $options) {
+ $valid_types = array('metadata', 'annotation');
+ if (!in_array($type, $valid_types)) {
+ return FALSE;
+ }
+
+ // the options for annotations are singular (annotation_name) but the table
+ // is plural (elgg_annotations) so rewrite for the table name.
+ $n_table = ($type == 'annotation') ? 'annotations' : $type;
+
+ $singulars = array("{$type}_name", "{$type}_value",
+ "{$type}_name_value_pair", "{$type}_owner_guid");
+ $options = elgg_normalise_plural_options_array($options, $singulars);
+
+ $clauses = elgg_get_entity_metadata_where_sql('e', $n_table, $options["{$type}_names"],
+ $options["{$type}_values"], $options["{$type}_name_value_pairs"],
+ $options["{$type}_name_value_pairs_operator"], $options["{$type}_case_sensitive"],
+ $options["order_by_{$type}"], $options["{$type}_owner_guids"]);
+
+ if ($clauses) {
+ // merge wheres to pass to get_entities()
+ if (isset($options['wheres']) && !is_array($options['wheres'])) {
+ $options['wheres'] = array($options['wheres']);
+ } elseif (!isset($options['wheres'])) {
+ $options['wheres'] = array();
+ }
+
+ $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
+
+ // merge joins to pass to get_entities()
+ if (isset($options['joins']) && !is_array($options['joins'])) {
+ $options['joins'] = array($options['joins']);
+ } elseif (!isset($options['joins'])) {
+ $options['joins'] = array();
+ }
+
+ $options['joins'] = array_merge($options['joins'], $clauses['joins']);
+
+ if ($clauses['orders']) {
+ $order_by_metadata = implode(", ", $clauses['orders']);
+ if (isset($options['order_by']) && $options['order_by']) {
+ $options['order_by'] = "$order_by_metadata, {$options['order_by']}";
+ } else {
+ $options['order_by'] = "$order_by_metadata, e.time_created DESC";
+ }
+ }
+ }
+
+ return $options;
+}
+
+// unit testing
+elgg_register_plugin_hook_handler('unit_test', 'system', 'metastrings_test');
+
+/**
+ * Metadata unit test
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of other tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
+ */
+function metastrings_test($hook, $type, $value, $params) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/metastrings.php';
+ return $value;
+}
diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php
new file mode 100644
index 000000000..ab9cc05e8
--- /dev/null
+++ b/engine/lib/navigation.php
@@ -0,0 +1,527 @@
+<?php
+/**
+ * Elgg navigation library
+ * Functions for managing menus and other navigational elements
+ *
+ * Breadcrumbs
+ * Elgg uses a breadcrumb stack. The page handlers (controllers in MVC terms)
+ * push the breadcrumb links onto the stack. @see elgg_push_breadcrumb()
+ *
+ *
+ * Pagination
+ * Automatically handled by Elgg when using elgg_list_entities* functions.
+ * @see elgg_list_entities()
+ *
+ *
+ * Tabs
+ * @see navigation/tabs view
+ *
+ *
+ * Menus
+ * Elgg uses a single interface to manage its menus. Menu items are added with
+ * {@link elgg_register_menu_item()}. This is generally used for menus that
+ * appear only once per page. For dynamic menus (such as the hover
+ * menu for user's avatar), a plugin hook is emitted when the menu is being
+ * created. The hook is 'register', 'menu:<menu_name>'. For more details on this,
+ * @see elgg_view_menu().
+ *
+ * Menus supported by the Elgg core
+ * Standard menus:
+ * site Site navigation shown on every page.
+ * page Page menu usually shown in a sidebar. Uses Elgg's context.
+ * topbar Topbar menu shown on every page. The default has two sections.
+ * footer Like the topbar but in the footer.
+ * extras Links about content on the page. The RSS link is added to this.
+ *
+ * Dynamic menus (also called just-in-time menus):
+ * user_hover Avatar hover menu. The user entity is passed as a parameter.
+ * entity The set of links shown in the summary of an entity.
+ * river Links shown on river items.
+ * owner_block Links shown for a user or group in their owner block.
+ * filter The tab filter for content (all, mine, friends)
+ * title The buttons shown next to a content title.
+ * long-text The links shown above the input/longtext view.
+ *
+ * @package Elgg.Core
+ * @subpackage Navigation
+ */
+
+/**
+ * Register an item for an Elgg menu
+ *
+ * @warning Generally you should not use this in response to the plugin hook:
+ * 'register', 'menu:<menu_name>'. If you do, you may end up with many incorrect
+ * links on a dynamic menu.
+ *
+ * @warning A menu item's name must be unique per menu. If more than one menu
+ * item with the same name are registered, the last menu item takes priority.
+ *
+ * @see elgg_view_menu() for the plugin hooks available for modifying a menu as
+ * it is being rendered.
+ *
+ * @param string $menu_name The name of the menu: site, page, userhover,
+ * userprofile, groupprofile, or any custom menu
+ * @param mixed $menu_item A ElggMenuItem object or an array of options in format:
+ * name => STR Menu item identifier (required)
+ * text => STR Menu item display text (required)
+ * href => STR Menu item URL (required) (false for non-links.
+ * @warning If you disable the href the <a> tag will
+ * not appear, so the link_class will not apply. If you
+ * put <a> tags in manually through the 'text' option
+ * the default CSS selector .elgg-menu-$menu > li > a
+ * may affect formatting. Wrap in a <span> if it does.)
+ * contexts => ARR Page context strings
+ * section => STR Menu section identifier
+ * title => STR Menu item tooltip
+ * selected => BOOL Is this menu item currently selected
+ * parent_name => STR Identifier of the parent menu item
+ * link_class => STR A class or classes for the <a> tag
+ * item_class => STR A class or classes for the <li> tag
+ *
+ * Additional options that the view output/url takes can be
+ * passed in the array. If the 'confirm' key is passed, the
+ * menu link uses the 'output/confirmlink' view. Custom
+ * options can be added by using the 'data' key with the
+ * value being an associative array.
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_register_menu_item($menu_name, $menu_item) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->menus[$menu_name])) {
+ $CONFIG->menus[$menu_name] = array();
+ }
+
+ if (is_array($menu_item)) {
+ $item = ElggMenuItem::factory($menu_item);
+ if (!$item) {
+ elgg_log("Unable to add menu item '{$menu_item['name']}' to '$menu_name' menu", 'WARNING');
+ elgg_log(print_r($menu_item, true), 'DEBUG');
+ return false;
+ }
+ } else {
+ $item = $menu_item;
+ }
+
+ $CONFIG->menus[$menu_name][] = $item;
+ return true;
+}
+
+/**
+ * Remove an item from a menu
+ *
+ * @param string $menu_name The name of the menu
+ * @param string $item_name The unique identifier for this menu item
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_unregister_menu_item($menu_name, $item_name) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->menus[$menu_name])) {
+ return false;
+ }
+
+ foreach ($CONFIG->menus[$menu_name] as $index => $menu_object) {
+ /* @var ElggMenuItem $menu_object */
+ if ($menu_object->getName() == $item_name) {
+ unset($CONFIG->menus[$menu_name][$index]);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Check if a menu item has been registered
+ *
+ * @param string $menu_name The name of the menu
+ * @param string $item_name The unique identifier for this menu item
+ *
+ * @return bool
+ * @since 1.8.0
+ */
+function elgg_is_menu_item_registered($menu_name, $item_name) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->menus[$menu_name])) {
+ return false;
+ }
+
+ foreach ($CONFIG->menus[$menu_name] as $menu_object) {
+ /* @var ElggMenuItem $menu_object */
+ if ($menu_object->getName() == $item_name) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+/**
+ * Convenience function for registering a button to title menu
+ *
+ * The URL must be $handler/$name/$guid where $guid is the guid of the page owner.
+ * The label of the button is "$handler:$name" so that must be defined in a
+ * language file.
+ *
+ * This is used primarily to support adding an add content button
+ *
+ * @param string $handler The handler to use or null to autodetect from context
+ * @param string $name Name of the button
+ * @return void
+ * @since 1.8.0
+ */
+function elgg_register_title_button($handler = null, $name = 'add') {
+ if (elgg_is_logged_in()) {
+
+ if (!$handler) {
+ $handler = elgg_get_context();
+ }
+
+ $owner = elgg_get_page_owner_entity();
+ if (!$owner) {
+ // no owns the page so this is probably an all site list page
+ $owner = elgg_get_logged_in_user_entity();
+ }
+ if ($owner && $owner->canWriteToContainer()) {
+ $guid = $owner->getGUID();
+ elgg_register_menu_item('title', array(
+ 'name' => $name,
+ 'href' => "$handler/$name/$guid",
+ 'text' => elgg_echo("$handler:$name"),
+ 'link_class' => 'elgg-button elgg-button-action',
+ ));
+ }
+ }
+}
+
+/**
+ * Adds a breadcrumb to the breadcrumbs stack.
+ *
+ * @param string $title The title to display
+ * @param string $link Optional. The link for the title.
+ *
+ * @return void
+ * @since 1.8.0
+ *
+ * @link http://docs.elgg.org/Tutorials/UI/Breadcrumbs
+ */
+function elgg_push_breadcrumb($title, $link = NULL) {
+ global $CONFIG;
+ if (!isset($CONFIG->breadcrumbs)) {
+ $CONFIG->breadcrumbs = array();
+ }
+
+ // avoid key collisions.
+ $CONFIG->breadcrumbs[] = array('title' => elgg_get_excerpt($title, 100), 'link' => $link);
+}
+
+/**
+ * Removes last breadcrumb entry.
+ *
+ * @return array popped item.
+ * @since 1.8.0
+ * @link http://docs.elgg.org/Tutorials/UI/Breadcrumbs
+ */
+function elgg_pop_breadcrumb() {
+ global $CONFIG;
+
+ if (is_array($CONFIG->breadcrumbs)) {
+ return array_pop($CONFIG->breadcrumbs);
+ }
+
+ return FALSE;
+}
+
+/**
+ * Returns all breadcrumbs as an array of array('title' => 'Readable Title', 'link' => 'URL')
+ *
+ * @return array Breadcrumbs
+ * @since 1.8.0
+ * @link http://docs.elgg.org/Tutorials/UI/Breadcrumbs
+ */
+function elgg_get_breadcrumbs() {
+ global $CONFIG;
+
+ if (isset($CONFIG->breadcrumbs) && is_array($CONFIG->breadcrumbs)) {
+ return $CONFIG->breadcrumbs;
+ }
+
+ return array();
+}
+
+/**
+ * Set up the site menu
+ *
+ * Handles default, featured, and custom menu items
+ *
+ * @param string $hook
+ * @param string $type
+ * @param array $return Menu array
+ * @param array $params
+ * @return array
+ * @access private
+ */
+function elgg_site_menu_setup($hook, $type, $return, $params) {
+
+ $featured_menu_names = elgg_get_config('site_featured_menu_names');
+ $custom_menu_items = elgg_get_config('site_custom_menu_items');
+ if ($featured_menu_names || $custom_menu_items) {
+ // we have featured or custom menu items
+
+ $registered = $return['default'];
+
+ // set up featured menu items
+ $featured = array();
+ foreach ($featured_menu_names as $name) {
+ foreach ($registered as $index => $item) {
+ if ($item->getName() == $name) {
+ $featured[] = $item;
+ unset($registered[$index]);
+ }
+ }
+ }
+
+ // add custom menu items
+ $n = 1;
+ foreach ($custom_menu_items as $title => $url) {
+ $item = new ElggMenuItem("custom$n", $title, $url);
+ $featured[] = $item;
+ $n++;
+ }
+
+ $return['default'] = $featured;
+ if (count($registered) > 0) {
+ $return['more'] = $registered;
+ }
+ } else {
+ // no featured menu items set
+ $max_display_items = 5;
+
+ // the first n are shown, rest added to more list
+ // if only one item on more menu, stick it with the rest
+ $num_menu_items = count($return['default']);
+ if ($num_menu_items > ($max_display_items + 1)) {
+ $return['more'] = array_splice($return['default'], $max_display_items);
+ }
+ }
+
+ // check if we have anything selected
+ $selected = false;
+ foreach ($return as $section) {
+ foreach ($section as $item) {
+ if ($item->getSelected()) {
+ $selected = true;
+ break 2;
+ }
+ }
+ }
+
+ if (!$selected) {
+ // nothing selected, match name to context or match url
+ $current_url = current_page_url();
+ foreach ($return as $section_name => $section) {
+ foreach ($section as $key => $item) {
+ // only highlight internal links
+ if (strpos($item->getHref(), elgg_get_site_url()) === 0) {
+ if ($item->getName() == elgg_get_context()) {
+ $return[$section_name][$key]->setSelected(true);
+ break 2;
+ }
+ if ($item->getHref() == $current_url) {
+ $return[$section_name][$key]->setSelected(true);
+ break 2;
+ }
+ }
+ }
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Add the comment and like links to river actions menu
+ * @access private
+ */
+function elgg_river_menu_setup($hook, $type, $return, $params) {
+ if (elgg_is_logged_in()) {
+ $item = $params['item'];
+ /* @var ElggRiverItem $item */
+ $object = $item->getObjectEntity();
+ // comments and non-objects cannot be commented on or liked
+ if (!elgg_in_context('widgets') && $item->annotation_id == 0) {
+ // comments
+ if ($object->canComment()) {
+ $options = array(
+ 'name' => 'comment',
+ 'href' => "#comments-add-$object->guid",
+ 'text' => elgg_view_icon('speech-bubble'),
+ 'title' => elgg_echo('comment:this'),
+ 'rel' => 'toggle',
+ 'priority' => 50,
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+ }
+
+ if (elgg_is_admin_logged_in()) {
+ $options = array(
+ 'name' => 'delete',
+ 'href' => elgg_add_action_tokens_to_url("action/river/delete?id=$item->id"),
+ 'text' => elgg_view_icon('delete'),
+ 'title' => elgg_echo('delete'),
+ 'confirm' => elgg_echo('deleteconfirm'),
+ 'priority' => 200,
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Entity menu is list of links and info on any entity
+ * @access private
+ */
+function elgg_entity_menu_setup($hook, $type, $return, $params) {
+ if (elgg_in_context('widgets')) {
+ return $return;
+ }
+
+ $entity = $params['entity'];
+ /* @var ElggEntity $entity */
+ $handler = elgg_extract('handler', $params, false);
+
+ // access
+ $access = elgg_view('output/access', array('entity' => $entity));
+ $options = array(
+ 'name' => 'access',
+ 'text' => $access,
+ 'href' => false,
+ 'priority' => 100,
+ );
+ $return[] = ElggMenuItem::factory($options);
+
+ if ($entity->canEdit() && $handler) {
+ // edit link
+ $options = array(
+ 'name' => 'edit',
+ 'text' => elgg_echo('edit'),
+ 'title' => elgg_echo('edit:this'),
+ 'href' => "$handler/edit/{$entity->getGUID()}",
+ 'priority' => 200,
+ );
+ $return[] = ElggMenuItem::factory($options);
+
+ // delete link
+ $options = array(
+ 'name' => 'delete',
+ 'text' => elgg_view_icon('delete'),
+ 'title' => elgg_echo('delete:this'),
+ 'href' => "action/$handler/delete?guid={$entity->getGUID()}",
+ 'confirm' => elgg_echo('deleteconfirm'),
+ 'priority' => 300,
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+
+ return $return;
+}
+
+/**
+ * Widget menu is a set of widget controls
+ * @access private
+ */
+function elgg_widget_menu_setup($hook, $type, $return, $params) {
+
+ $widget = $params['entity'];
+ /* @var ElggWidget $widget */
+ $show_edit = elgg_extract('show_edit', $params, true);
+
+ $collapse = array(
+ 'name' => 'collapse',
+ 'text' => ' ',
+ 'href' => "#elgg-widget-content-$widget->guid",
+ 'class' => 'elgg-widget-collapse-button',
+ 'rel' => 'toggle',
+ 'priority' => 1
+ );
+ $return[] = ElggMenuItem::factory($collapse);
+
+ if ($widget->canEdit()) {
+ $delete = array(
+ 'name' => 'delete',
+ 'text' => elgg_view_icon('delete-alt'),
+ 'title' => elgg_echo('widget:delete', array($widget->getTitle())),
+ 'href' => "action/widgets/delete?widget_guid=$widget->guid",
+ 'is_action' => true,
+ 'class' => 'elgg-widget-delete-button',
+ 'id' => "elgg-widget-delete-button-$widget->guid",
+ 'priority' => 900
+ );
+ $return[] = ElggMenuItem::factory($delete);
+
+ if ($show_edit) {
+ $edit = array(
+ 'name' => 'settings',
+ 'text' => elgg_view_icon('settings-alt'),
+ 'title' => elgg_echo('widget:edit'),
+ 'href' => "#widget-edit-$widget->guid",
+ 'class' => "elgg-widget-edit-button",
+ 'rel' => 'toggle',
+ 'priority' => 800,
+ );
+ $return[] = ElggMenuItem::factory($edit);
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Adds a delete link to "generic_comment" annotations
+ * @access private
+ */
+function elgg_annotation_menu_setup($hook, $type, $return, $params) {
+ $annotation = $params['annotation'];
+ /* @var ElggAnnotation $annotation */
+
+ if ($annotation->name == 'generic_comment' && $annotation->canEdit()) {
+ $url = elgg_http_add_url_query_elements('action/comments/delete', array(
+ 'annotation_id' => $annotation->id,
+ ));
+
+ $options = array(
+ 'name' => 'delete',
+ 'href' => $url,
+ 'text' => "<span class=\"elgg-icon elgg-icon-delete\"></span>",
+ 'confirm' => elgg_echo('deleteconfirm'),
+ 'encode_text' => false
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+
+ return $return;
+}
+
+
+/**
+ * Navigation initialization
+ * @access private
+ */
+function elgg_nav_init() {
+ elgg_register_plugin_hook_handler('prepare', 'menu:site', 'elgg_site_menu_setup');
+ elgg_register_plugin_hook_handler('register', 'menu:river', 'elgg_river_menu_setup');
+ elgg_register_plugin_hook_handler('register', 'menu:entity', 'elgg_entity_menu_setup');
+ elgg_register_plugin_hook_handler('register', 'menu:widget', 'elgg_widget_menu_setup');
+ elgg_register_plugin_hook_handler('register', 'menu:annotation', 'elgg_annotation_menu_setup');
+}
+
+elgg_register_event_handler('init', 'system', 'elgg_nav_init');
diff --git a/engine/lib/notification.php b/engine/lib/notification.php
index 7f949c32f..be0c359d4 100644
--- a/engine/lib/notification.php
+++ b/engine/lib/notification.php
@@ -3,38 +3,42 @@
* Notifications
* This file contains classes and functions which allow plugins to register and send notifications.
*
- * There are notification methods which are provided out of the box (see notification_init() ). Each method
- * is identified by a string, e.g. "email".
+ * There are notification methods which are provided out of the box
+ * (see notification_init() ). Each method is identified by a string, e.g. "email".
*
- * To register an event use register_notification_handler() and pass the method name and a handler function.
+ * To register an event use register_notification_handler() and pass the method name and a
+ * handler function.
*
- * To send a notification call notify() passing it the method you wish to use combined with a number of method
- * specific addressing parameters.
+ * To send a notification call notify() passing it the method you wish to use combined with a
+ * number of method specific addressing parameters.
*
* Catch NotificationException to trap errors.
*
- * @package Elgg
- * @subpackage API
-
- * @author Curverider Ltd
-
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Notifications
*/
/** Notification handlers */
+global $NOTIFICATION_HANDLERS;
$NOTIFICATION_HANDLERS = array();
/**
* This function registers a handler for a given notification type (eg "email")
*
- * @param string $method The method
- * @param string $handler The handler function, in the format "handler(ElggEntity $from, ElggUser $to, $subject, $message, array $params = NULL)". This function should return false on failure, and true/a tracking message ID on success.
- * @param array $params A associated array of other parameters for this handler defining some properties eg. supported message length or rich text support.
+ * @param string $method The method
+ * @param string $handler The handler function, in the format
+ * "handler(ElggEntity $from, ElggUser $to, $subject,
+ * $message, array $params = NULL)". This function should
+ * return false on failure, and true/a tracking message ID on success.
+ * @param array $params An associated array of other parameters for this handler
+ * defining some properties eg. supported msg length or rich text support.
+ *
+ * @return bool
*/
function register_notification_handler($method, $handler, $params = NULL) {
global $NOTIFICATION_HANDLERS;
- if (is_callable($handler)) {
+ if (is_callable($handler, true)) {
$NOTIFICATION_HANDLERS[$method] = new stdClass;
$NOTIFICATION_HANDLERS[$method]->handler = $handler;
@@ -54,6 +58,9 @@ function register_notification_handler($method, $handler, $params = NULL) {
* This function unregisters a handler for a given notification type (eg "email")
*
* @param string $method The method
+ *
+ * @return void
+ * @since 1.7.1
*/
function unregister_notification_handler($method) {
global $NOTIFICATION_HANDLERS;
@@ -66,18 +73,20 @@ function unregister_notification_handler($method) {
/**
* Notify a user via their preferences.
*
- * @param mixed $to Either a guid or an array of guid's to notify.
- * @param int $from GUID of the sender, which may be a user, site or object.
- * @param string $subject Message subject.
- * @param string $message Message body.
- * @param array $params Misc additional parameters specific to various methods.
- * @param mixed $methods_override A string, or an array of strings specifying the delivery methods to use - or leave blank
- * for delivery using the user's chosen delivery methods.
+ * @param mixed $to Either a guid or an array of guid's to notify.
+ * @param int $from GUID of the sender, which may be a user, site or object.
+ * @param string $subject Message subject.
+ * @param string $message Message body.
+ * @param array $params Misc additional parameters specific to various methods.
+ * @param mixed $methods_override A string, or an array of strings specifying the delivery
+ * methods to use - or leave blank for delivery using the
+ * user's chosen delivery methods.
+ *
* @return array Compound array of each delivery user/delivery method's success or failure.
* @throws NotificationException
*/
function notify_user($to, $from, $subject, $message, array $params = NULL, $methods_override = "") {
- global $NOTIFICATION_HANDLERS, $CONFIG;
+ global $NOTIFICATION_HANDLERS;
// Sanitise
if (!is_array($to)) {
@@ -101,12 +110,15 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth
// Are we overriding delivery?
$methods = $methods_override;
if (!$methods) {
- $tmp = (array)get_user_notification_settings($guid);
+ $tmp = get_user_notification_settings($guid);
$methods = array();
- foreach($tmp as $k => $v) {
- // Add method if method is turned on for user!
- if ($v) {
- $methods[] = $k;
+ // $tmp may be false. don't cast
+ if (is_object($tmp)) {
+ foreach ($tmp as $k => $v) {
+ // Add method if method is turned on for user!
+ if ($v) {
+ $methods[] = $k;
+ }
}
}
}
@@ -122,16 +134,17 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth
// Extract method details from list
$details = $NOTIFICATION_HANDLERS[$method];
$handler = $details->handler;
+ /* @var callable $handler */
- if ((!$NOTIFICATION_HANDLERS[$method]) || (!$handler)) {
- error_log(sprintf(elgg_echo('NotificationException:NoHandlerFound'), $method));
+ if ((!$NOTIFICATION_HANDLERS[$method]) || (!$handler) || (!is_callable($handler))) {
+ error_log(elgg_echo('NotificationException:NoHandlerFound', array($method)));
}
elgg_log("Sending message to $guid using $method");
// Trigger handler and retrieve result.
try {
- $result[$guid][$method] = $handler(
+ $result[$guid][$method] = call_user_func($handler,
$from ? get_entity($from) : NULL, // From entity
get_entity($guid), // To entity
$subject, // The subject
@@ -154,16 +167,22 @@ function notify_user($to, $from, $subject, $message, array $params = NULL, $meth
* Get the notification settings for a given user.
*
* @param int $user_guid The user id
- * @return stdClass
+ *
+ * @return stdClass|false
*/
function get_user_notification_settings($user_guid = 0) {
$user_guid = (int)$user_guid;
if ($user_guid == 0) {
- $user_guid = get_loggedin_userid();
+ $user_guid = elgg_get_logged_in_user_guid();
}
- $all_metadata = get_metadata_for_entity($user_guid);
+ // @todo: there should be a better way now that metadata is cached. E.g. just query for MD names, then
+ // query user object directly
+ $all_metadata = elgg_get_metadata(array(
+ 'guid' => $user_guid,
+ 'limit' => 0
+ ));
if ($all_metadata) {
$prefix = "notification:method:";
$return = new stdClass;
@@ -186,9 +205,10 @@ function get_user_notification_settings($user_guid = 0) {
/**
* Set a user notification pref.
*
- * @param int $user_guid The user id.
- * @param string $method The delivery method (eg. email)
- * @param bool $value On(true) or off(false).
+ * @param int $user_guid The user id.
+ * @param string $method The delivery method (eg. email)
+ * @param bool $value On(true) or off(false).
+ *
* @return bool
*/
function set_user_notification_setting($user_guid, $method, $value) {
@@ -197,7 +217,7 @@ function set_user_notification_setting($user_guid, $method, $value) {
$user = get_entity($user_guid);
if (!$user) {
- $user = get_loggedin_user();
+ $user = elgg_get_logged_in_user_entity();
}
if (($user) && ($user instanceof ElggUser)) {
@@ -212,42 +232,43 @@ function set_user_notification_setting($user_guid, $method, $value) {
}
/**
- * Notification exception.
- * @author Curverider Ltd
- */
-class NotificationException extends Exception {}
-
-
-/**
* Send a notification via email.
*
- * @param ElggEntity $from The from user/site/object
- * @param ElggUser $to To which user?
- * @param string $subject The subject of the message.
- * @param string $message The message body
- * @param array $params Optional parameters (none taken in this instance)
+ * @param ElggEntity $from The from user/site/object
+ * @param ElggUser $to To which user?
+ * @param string $subject The subject of the message.
+ * @param string $message The message body
+ * @param array $params Optional parameters (none taken in this instance)
+ *
* @return bool
+ * @throws NotificationException
+ * @access private
*/
-function email_notify_handler(ElggEntity $from, ElggUser $to, $subject, $message, array $params = NULL) {
+function email_notify_handler(ElggEntity $from, ElggUser $to, $subject, $message,
+array $params = NULL) {
+
global $CONFIG;
if (!$from) {
- throw new NotificationException(sprintf(elgg_echo('NotificationException:MissingParameter'), 'from'));
+ $msg = elgg_echo('NotificationException:MissingParameter', array('from'));
+ throw new NotificationException($msg);
}
if (!$to) {
- throw new NotificationException(sprintf(elgg_echo('NotificationException:MissingParameter'), 'to'));
+ $msg = elgg_echo('NotificationException:MissingParameter', array('to'));
+ throw new NotificationException($msg);
}
- if ($to->email=="") {
- throw new NotificationException(sprintf(elgg_echo('NotificationException:NoEmailAddress'), $to->guid));
+ if ($to->email == "") {
+ $msg = elgg_echo('NotificationException:NoEmailAddress', array($to->guid));
+ throw new NotificationException($msg);
}
// To
$to = $to->email;
// From
- $site = get_entity($CONFIG->site_guid);
+ $site = elgg_get_site_entity();
// If there's an email address, use it - but only if its not from a user.
if (!($from instanceof ElggUser) && $from->email) {
$from = $from->email;
@@ -265,31 +286,39 @@ function email_notify_handler(ElggEntity $from, ElggUser $to, $subject, $message
/**
* Send an email to any email address
*
- * @param string $from Email address or string: "name <email>"
- * @param string $to Email address or string: "name <email>"
+ * @param string $from Email address or string: "name <email>"
+ * @param string $to Email address or string: "name <email>"
* @param string $subject The subject of the message
- * @param string $body The message body
- * @param array $params Optional parameters (none used in this function)
+ * @param string $body The message body
+ * @param array $params Optional parameters (none used in this function)
+ *
* @return bool
+ * @throws NotificationException
+ * @since 1.7.2
*/
function elgg_send_email($from, $to, $subject, $body, array $params = NULL) {
global $CONFIG;
if (!$from) {
- throw new NotificationException(sprintf(elgg_echo('NotificationException:NoEmailAddress'), 'from'));
+ $msg = elgg_echo('NotificationException:MissingParameter', array('from'));
+ throw new NotificationException($msg);
}
if (!$to) {
- throw new NotificationException(sprintf(elgg_echo('NotificationException:NoEmailAddress'), 'to'));
+ $msg = elgg_echo('NotificationException:MissingParameter', array('to'));
+ throw new NotificationException($msg);
}
// return TRUE/FALSE to stop elgg_send_email() from sending
- $mail_params = array( 'to' => $to,
+ $mail_params = array(
+ 'to' => $to,
'from' => $from,
'subject' => $subject,
'body' => $body,
- 'params' => $params);
- $result = trigger_plugin_hook('email', 'system', $mail_params, NULL);
+ 'params' => $params
+ );
+
+ $result = elgg_trigger_plugin_hook('email', 'system', $mail_params, NULL);
if ($result !== NULL) {
return $result;
}
@@ -301,7 +330,7 @@ function elgg_send_email($from, $to, $subject, $body, array $params = NULL) {
}
// Windows is somewhat broken, so we use just address for to and from
- if (strtolower(substr(PHP_OS, 0 , 3)) == 'win') {
+ if (strtolower(substr(PHP_OS, 0, 3)) == 'win') {
// strip name from to and from
if (strpos($to, '<')) {
preg_match('/<(.*)>/', $to, $matches);
@@ -321,13 +350,15 @@ function elgg_send_email($from, $to, $subject, $body, array $params = NULL) {
// Sanitise subject by stripping line endings
$subject = preg_replace("/(\r\n|\r|\n)/", " ", $subject);
+ // this is because Elgg encodes everything and matches what is done with body
+ $subject = html_entity_decode($subject, ENT_COMPAT, 'UTF-8'); // Decode any html entities
if (is_callable('mb_encode_mimeheader')) {
- $subject = mb_encode_mimeheader($subject,"UTF-8", "B");
+ $subject = mb_encode_mimeheader($subject, "UTF-8", "B");
}
// Format message
$body = html_entity_decode($body, ENT_COMPAT, 'UTF-8'); // Decode any html entities
- $body = strip_tags($body); // Strip tags from message
+ $body = elgg_strip_tags($body); // Strip tags from message
$body = preg_replace("/(\r\n|\r)/", "\n", $body); // Convert to unix line endings in body
$body = preg_replace("/^From/", ">From", $body); // Change lines starting with From to >From
@@ -337,32 +368,42 @@ function elgg_send_email($from, $to, $subject, $body, array $params = NULL) {
/**
* Correctly initialise notifications and register the email handler.
*
+ * @return void
+ * @access private
*/
function notification_init() {
// Register a notification handler for the default email method
register_notification_handler("email", "email_notify_handler");
// Add settings view to user settings & register action
- extend_elgg_settings_page('notifications/settings/usersettings', 'usersettings/user');
-
- register_plugin_hook('usersettings:save','user','notification_user_settings_save');
+ elgg_extend_view('forms/account/settings', 'core/settings/account/notifications');
- //register_action("notifications/settings/usersettings/save");
+ elgg_register_plugin_hook_handler('usersettings:save', 'user', 'notification_user_settings_save');
}
+/**
+ * Includes the action to save user notifications
+ *
+ * @return void
+ * @todo why can't this call action(...)?
+ * @access private
+ */
function notification_user_settings_save() {
global $CONFIG;
+ //@todo Wha??
include($CONFIG->path . "actions/notifications/settings/usersettings/save.php");
}
/**
* Register an entity type and subtype to be eligible for notifications
*
- * @param string $entity_type The type of entity
+ * @param string $entity_type The type of entity
* @param string $object_subtype Its subtype
- * @param string $english_name It's English notification string (eg "New blog post")
+ * @param string $language_name Its localized notification string (eg "New blog post")
+ *
+ * @return void
*/
-function register_notification_object($entity_type, $object_subtype, $english_name) {
+function register_notification_object($entity_type, $object_subtype, $language_name) {
global $CONFIG;
if ($entity_type == '') {
@@ -380,15 +421,16 @@ function register_notification_object($entity_type, $object_subtype, $english_na
$CONFIG->register_objects[$entity_type] = array();
}
- $CONFIG->register_objects[$entity_type][$object_subtype] = $english_name;
+ $CONFIG->register_objects[$entity_type][$object_subtype] = $language_name;
}
/**
* Establish a 'notify' relationship between the user and a content author
*
- * @param int $user_guid The GUID of the user who wants to follow a user's content
+ * @param int $user_guid The GUID of the user who wants to follow a user's content
* @param int $author_guid The GUID of the user whose content the user wants to follow
- * @return true|false Depending on success
+ *
+ * @return bool Depending on success
*/
function register_notification_interest($user_guid, $author_guid) {
return add_entity_relationship($user_guid, 'notify', $author_guid);
@@ -397,9 +439,10 @@ function register_notification_interest($user_guid, $author_guid) {
/**
* Remove a 'notify' relationship between the user and a content author
*
- * @param int $user_guid The GUID of the user who is following a user's content
+ * @param int $user_guid The GUID of the user who is following a user's content
* @param int $author_guid The GUID of the user whose content the user wants to unfollow
- * @return true|false Depending on success
+ *
+ * @return bool Depending on success
*/
function remove_notification_interest($user_guid, $author_guid) {
return remove_entity_relationship($user_guid, 'notify', $author_guid);
@@ -410,15 +453,23 @@ function remove_notification_interest($user_guid, $author_guid) {
* objects and attempts to send notifications to anybody who's interested
*
* @see register_notification_object
+ *
+ * @param string $event create
+ * @param string $object_type mixed
+ * @param mixed $object The object created
+ *
+ * @return bool
+ * @access private
*/
function object_notifications($event, $object_type, $object) {
// We only want to trigger notification events for ElggEntities
if ($object instanceof ElggEntity) {
+ /* @var ElggEntity $object */
// Get config data
global $CONFIG, $SESSION, $NOTIFICATION_HANDLERS;
- $hookresult = trigger_plugin_hook('object:notifications',$object_type,array(
+ $hookresult = elgg_trigger_plugin_hook('object:notifications', $object_type, array(
'event' => $event,
'object_type' => $object_type,
'object' => $object,
@@ -439,34 +490,37 @@ function object_notifications($event, $object_type, $object) {
}
if (isset($CONFIG->register_objects[$object_type][$object_subtype])) {
- $descr = $CONFIG->register_objects[$object_type][$object_subtype];
- $string = $descr . ": " . $object->getURL();
+ $subject = $CONFIG->register_objects[$object_type][$object_subtype];
+ $string = $subject . ": " . $object->getURL();
// Get users interested in content from this person and notify them
// (Person defined by container_guid so we can also subscribe to groups if we want)
- foreach($NOTIFICATION_HANDLERS as $method => $foo) {
+ foreach ($NOTIFICATION_HANDLERS as $method => $foo) {
$interested_users = elgg_get_entities_from_relationship(array(
+ 'site_guids' => ELGG_ENTITIES_ANY_VALUE,
'relationship' => 'notify' . $method,
- 'relationship_guid' => $object->container_guid,
+ 'relationship_guid' => $object->container_guid,
'inverse_relationship' => TRUE,
- 'types' => 'user',
- 'limit' => 99999
+ 'type' => 'user',
+ 'limit' => false
));
+ /* @var ElggUser[] $interested_users */
if ($interested_users && is_array($interested_users)) {
- foreach($interested_users as $user) {
+ foreach ($interested_users as $user) {
if ($user instanceof ElggUser && !$user->isBanned()) {
- if (($user->guid != $SESSION['user']->guid) && has_access_to_entity($object,$user)
+ if (($user->guid != $SESSION['user']->guid) && has_access_to_entity($object, $user)
&& $object->access_id != ACCESS_PRIVATE) {
- $methodstring = trigger_plugin_hook('notify:entity:message',$object->getType(),array(
+ $body = elgg_trigger_plugin_hook('notify:entity:message', $object->getType(), array(
'entity' => $object,
'to_entity' => $user,
- 'method' => $method),$string);
- if (empty($methodstring) && $methodstring !== false) {
- $methodstring = $string;
+ 'method' => $method), $string);
+ if (empty($body) && $body !== false) {
+ $body = $string;
}
- if ($methodstring !== false) {
- notify_user($user->guid,$object->container_guid,$descr,$methodstring,NULL,array($method));
+ if ($body !== false) {
+ notify_user($user->guid, $object->container_guid, $subject, $body,
+ null, array($method));
}
}
}
@@ -478,5 +532,5 @@ function object_notifications($event, $object_type, $object) {
}
// Register a startup event
-register_elgg_event_handler('init','system','notification_init',0);
-register_elgg_event_handler('create','object','object_notifications');
+elgg_register_event_handler('init', 'system', 'notification_init', 0);
+elgg_register_event_handler('create', 'object', 'object_notifications');
diff --git a/engine/lib/objects.php b/engine/lib/objects.php
index 6023a4805..ff3cc733f 100644
--- a/engine/lib/objects.php
+++ b/engine/lib/objects.php
@@ -1,217 +1,19 @@
<?php
-
/**
* Elgg objects
* Functions to manage multiple or single objects in an Elgg install
*
* @package Elgg
* @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
- */
-
-/**
- * ElggObject
- * Representation of an "object" in the system.
- *
- * @package Elgg
- * @subpackage Core
*/
-class ElggObject extends ElggEntity {
- /**
- * Initialise the attributes array.
- * This is vital to distinguish between metadata and base parameters.
- *
- * Place your base parameters here.
- */
- protected function initialise_attributes() {
- parent::initialise_attributes();
-
- $this->attributes['type'] = "object";
- $this->attributes['title'] = "";
- $this->attributes['description'] = "";
- $this->attributes['tables_split'] = 2;
- }
-
- /**
- * Construct a new object entity, optionally from a given id value.
- *
- * @param mixed $guid If an int, load that GUID.
- * If a db row then will attempt to load the rest of the data.
- * @throws Exception if there was a problem creating the object.
- */
- function __construct($guid = null) {
- $this->initialise_attributes();
-
- if (!empty($guid)) {
- // Is $guid is a DB row - either a entity row, or a object table row.
- if ($guid instanceof stdClass) {
- // Load the rest
- if (!$this->load($guid->guid)) {
- throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid->guid));
- }
- }
-
- // Is $guid is an ElggObject? Use a copy constructor
- else if ($guid instanceof ElggObject) {
- elgg_deprecated_notice('This type of usage of the ElggObject constructor was deprecated. Please use the clone method.', 1.7);
-
- foreach ($guid->attributes as $key => $value) {
- $this->attributes[$key] = $value;
- }
- }
-
- // Is this is an ElggEntity but not an ElggObject = ERROR!
- else if ($guid instanceof ElggEntity) {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggObject'));
- }
-
- // We assume if we have got this far, $guid is an int
- else if (is_numeric($guid)) {
- if (!$this->load($guid)) {
- throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid));
- }
- }
-
- else {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnrecognisedValue'));
- }
- }
- }
-
- /**
- * Override the load function.
- * This function will ensure that all data is loaded (were possible), so
- * if only part of the ElggObject is loaded, it'll load the rest.
- *
- * @param int $guid
- * @return true|false
- */
- protected function load($guid) {
- // Test to see if we have the generic stuff
- if (!parent::load($guid)) {
- return false;
- }
-
- // Check the type
- if ($this->attributes['type']!='object') {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class()));
- }
-
- // Load missing data
- $row = get_object_entity_as_row($guid);
- if (($row) && (!$this->isFullyLoaded())) {
- // If $row isn't a cached copy then increment the counter
- $this->attributes['tables_loaded'] ++;
- }
-
- // Now put these into the attributes array as core values
- $objarray = (array) $row;
- foreach($objarray as $key => $value) {
- $this->attributes[$key] = $value;
- }
-
- return true;
- }
-
- /**
- * Override the save function.
- * @return true|false
- */
- public function save() {
- // Save generic stuff
- if (!parent::save()) {
- return false;
- }
-
- // Now save specific stuff
- return create_object_entity($this->get('guid'), $this->get('title'), $this->get('description'), $this->get('container_guid'));
- }
-
- /**
- * Get sites that this object is a member of
- *
- * @param string $subtype Optionally, the subtype of result we want to limit to
- * @param int $limit The number of results to return
- * @param int $offset Any indexing offset
- */
- function getSites($subtype="", $limit = 10, $offset = 0) {
- return get_site_objects($this->getGUID(), $subtype, $limit, $offset);
- }
-
- /**
- * Add this object to a particular site
- *
- * @param int $site_guid The guid of the site to add it to
- * @return true|false
- */
- function addToSite($site_guid) {
- return add_site_object($this->getGUID(), $site_guid);
- }
-
- /**
- * Set the container for this object.
- *
- * @param int $container_guid The ID of the container.
- * @return bool
- */
- function setContainer($container_guid) {
- $container_guid = (int)$container_guid;
-
- return $this->set('container_guid', $container_guid);
- }
-
- /**
- * Return the container GUID of this object.
- *
- * @return int
- */
- function getContainer() {
- return $this->get('container_guid');
- }
-
- /**
- * As getContainer(), but returns the whole entity.
- *
- * @return mixed ElggGroup object or false.
- */
- function getContainerEntity() {
- $result = get_entity($this->getContainer());
-
- if (($result) && ($result instanceof ElggGroup)) {
- return $result;
- }
-
- return false;
- }
-
- /**
- * Get the collections associated with a object.
- *
- * @param string $subtype Optionally, the subtype of result we want to limit to
- * @param int $limit The number of results to return
- * @param int $offset Any indexing offset
- * @return unknown
- */
- //public function getCollections($subtype="", $limit = 10, $offset = 0) { get_object_collections($this->getGUID(), $subtype, $limit, $offset); }
-
- // EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * Return an array of fields which can be exported.
- */
- public function getExportableValues() {
- return array_merge(parent::getExportableValues(), array(
- 'title',
- 'description',
- ));
- }
-}
/**
* Return the object specific details of a object by a row.
*
- * @param int $guid
+ * @param int $guid The guid to retreive
+ *
+ * @return bool
+ * @access private
*/
function get_object_entity_as_row($guid) {
global $CONFIG;
@@ -224,9 +26,12 @@ function get_object_entity_as_row($guid) {
* Create or update the extras table for a given object.
* Call create_entity first.
*
- * @param int $guid The guid of the entity you're creating (as obtained by create_entity)
- * @param string $title The title of the object
+ * @param int $guid The guid of the entity you're creating (as obtained by create_entity)
+ * @param string $title The title of the object
* @param string $description The object's description
+ *
+ * @return bool
+ * @access private
*/
function create_object_entity($guid, $title, $description) {
global $CONFIG;
@@ -239,27 +44,30 @@ function create_object_entity($guid, $title, $description) {
if ($row) {
// Core entities row exists and we have access to it
- if ($exists = get_data_row("SELECT guid from {$CONFIG->dbprefix}objects_entity where guid = {$guid}")) {
- $result = update_data("UPDATE {$CONFIG->dbprefix}objects_entity set title='$title', description='$description' where guid=$guid");
- if ($result!=false) {
+ $query = "SELECT guid from {$CONFIG->dbprefix}objects_entity where guid = {$guid}";
+ if ($exists = get_data_row($query)) {
+ $query = "UPDATE {$CONFIG->dbprefix}objects_entity
+ set title='$title', description='$description' where guid=$guid";
+
+ $result = update_data($query);
+ if ($result != false) {
// Update succeeded, continue
$entity = get_entity($guid);
- if (trigger_elgg_event('update',$entity->type,$entity)) {
- return $guid;
- } else {
- $entity->delete();
- }
+ elgg_trigger_event('update', $entity->type, $entity);
+ return $guid;
}
} else {
// Update failed, attempt an insert.
- $result = insert_data("INSERT into {$CONFIG->dbprefix}objects_entity (guid, title, description) values ($guid, '$title','$description')");
- if ($result!==false) {
+ $query = "INSERT into {$CONFIG->dbprefix}objects_entity
+ (guid, title, description) values ($guid, '$title','$description')";
+
+ $result = insert_data($query);
+ if ($result !== false) {
$entity = get_entity($guid);
- if (trigger_elgg_event('create',$entity->type,$entity)) {
+ if (elgg_trigger_event('create', $entity->type, $entity)) {
return $guid;
} else {
$entity->delete();
- //delete_entity($guid);
}
}
}
@@ -269,72 +77,12 @@ function create_object_entity($guid, $title, $description) {
}
/**
- * THIS FUNCTION IS DEPRECATED.
- *
- * Delete a object's extra data.
- *
- * @param int $guid
- */
-function delete_object_entity($guid) {
- system_message(sprintf(elgg_echo('deprecatedfunction'), 'delete_user_entity'));
-
- return 1; // Always return that we have deleted one row in order to not break existing code.
-}
-
-/**
- * Searches for an object based on a complete or partial title or description using full text searching.
- *
- * IMPORTANT NOTE: With MySQL's default setup:
- * 1) $criteria must be 4 or more characters long
- * 2) If $criteria matches greater than 50% of results NO RESULTS ARE RETURNED!
- *
- * @param string $criteria The partial or full name or username.
- * @param int $limit Limit of the search.
- * @param int $offset Offset.
- * @param string $order_by The order.
- * @param boolean $count Whether to return the count of results or just the results.
- * @deprecated 1.7
- */
-function search_for_object($criteria, $limit = 10, $offset = 0, $order_by = "", $count = false) {
- elgg_deprecated_notice('search_for_object() was deprecated by new search plugin.', 1.7);
- global $CONFIG;
-
- $criteria = sanitise_string($criteria);
- $limit = (int)$limit;
- $offset = (int)$offset;
- $order_by = sanitise_string($order_by);
- $container_guid = (int)$container_guid;
-
- $access = get_access_sql_suffix("e");
-
- if ($order_by == "") {
- $order_by = "e.time_created desc";
- }
-
- if ($count) {
- $query = "SELECT count(e.guid) as total ";
- } else {
- $query = "SELECT e.* ";
- }
- $query .= "from {$CONFIG->dbprefix}entities e join {$CONFIG->dbprefix}objects_entity o on e.guid=o.guid where match(o.title,o.description) against ('$criteria') and $access";
-
- if (!$count) {
- $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
- return get_data($query, "entity_row_to_elggstar");
- } else {
- if ($count = get_data_row($query)) {
- return $count->total;
- }
- }
- return false;
-}
-
-/**
* Get the sites this object is part of
*
* @param int $object_guid The object's GUID
- * @param int $limit Number of results to return
- * @param int $offset Any indexing offset
+ * @param int $limit Number of results to return
+ * @param int $offset Any indexing offset
+ *
* @return false|array On success, an array of ElggSites
*/
function get_object_sites($object_guid, $limit = 10, $offset = 0) {
@@ -345,14 +93,22 @@ function get_object_sites($object_guid, $limit = 10, $offset = 0) {
return elgg_get_entities_from_relationship(array(
'relationship' => 'member_of_site',
'relationship_guid' => $object_guid,
- 'types' => 'site',
+ 'type' => 'site',
'limit' => $limit,
- 'offset' => $offset
+ 'offset' => $offset,
));
}
/**
* Runs unit tests for ElggObject
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
*/
function objects_test($hook, $type, $value, $params) {
global $CONFIG;
@@ -360,34 +116,5 @@ function objects_test($hook, $type, $value, $params) {
return $value;
}
-
-/**
- * Returns a formatted list of objects suitable for injecting into search.
- * @deprecated 1.7
- *
- */
-function search_list_objects_by_name($hook, $user, $returnvalue, $tag) {
- elgg_deprecated_notice('search_list_objects_by_name was deprecated by new search plugin.', 1.7);
-
- // Change this to set the number of users that display on the search page
- $threshold = 4;
-
- $object = get_input('object');
-
- if (!get_input('offset') && (empty($object) || $object == 'user')) {
- if ($users = search_for_user($tag,$threshold)) {
- $countusers = search_for_user($tag,0,0,"",true);
-
- $return = elgg_view('user/search/startblurb',array('count' => $countusers, 'tag' => $tag));
- foreach($users as $user) {
- $return .= elgg_view_entity($user);
- }
- $return .= elgg_view('user/search/finishblurb',array('count' => $countusers, 'threshold' => $threshold, 'tag' => $tag));
- return $return;
-
- }
- }
-}
-
-register_elgg_event_handler('init', 'system', 'objects_init', 0);
-register_plugin_hook('unit_test', 'system', 'objects_test');
+elgg_register_event_handler('init', 'system', 'objects_init', 0);
+elgg_register_plugin_hook_handler('unit_test', 'system', 'objects_test');
diff --git a/engine/lib/opendd.php b/engine/lib/opendd.php
index c582e6f77..7d635a295 100644
--- a/engine/lib/opendd.php
+++ b/engine/lib/opendd.php
@@ -2,316 +2,34 @@
/**
* OpenDD PHP Library.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
+ * @package Elgg.Core
+ * @subpackage ODD
* @version 0.4
- * @link http://elgg.org/
*/
-include_once("xml.php");
-
-/**
- * @class ODDDocument ODD Document container.
- * This class is used during import and export to construct.
- * @author Curverider Ltd
- */
-class ODDDocument implements Iterator {
- /**
- * ODD Version
- *
- * @var string
- */
- private $ODDSupportedVersion = "1.0";
-
- /**
- * Elements of the document.
- */
- private $elements;
-
- /**
- * Optional wrapper factory.
- */
- private $wrapperfactory;
-
- public function __construct(array $elements = NULL) {
- if ($elements) {
- if (is_array($elements)) {
- $this->elements = $elements;
- } else {
- $this->addElement($elements);
- }
- } else {
- $this->elements = array();
- }
- }
-
- /**
- * Return the version of ODD being used.
- *
- * @return string
- */
- public function getVersion() {
- return $this->ODDSupportedVersion;
- }
-
- public function getNumElements() {
- return count($this->elements);
- }
-
- public function addElement(ODD $element) {
- if (!is_array($this->elements)) {
- $this->elements = array();
- $this->elements[] = $element;
- }
- }
-
- public function addElements(array $elements) {
- foreach ($elements as $element) {
- $this->addElement($element);
- }
- }
-
- public function getElements() {
- return $this->elements;
- }
-
- /**
- * Set an optional wrapper factory to optionally embed the ODD document in another format.
- */
- public function setWrapperFactory(ODDWrapperFactory $factory) {
- $this->wrapperfactory = $factory;
- }
-
- /**
- * Magic function to generate valid ODD XML for this item.
- */
- public function __toString() {
- $xml = "";
-
- if ($this->wrapperfactory) {
- // A wrapper has been provided
- $wrapper = $this->wrapperfactory->getElementWrapper($this); // Get the wrapper for this element
-
- $xml = $wrapper->wrap($this); // Wrap this element (and subelements)
- } else {
- // Output begin tag
- $generated = date("r");
- $xml .= "<odd version=\"{$this->ODDSupportedVersion}\" generated=\"$generated\">\n";
-
- // Get XML for elements
- foreach ($this->elements as $element) {
- $xml .= "$element";
- }
-
- // Output end tag
- $xml .= "</odd>\n";
- }
-
- return $xml;
- }
-
- // 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->elements));
- }
-
- function current() {
- return current($this->elements);
- }
-
- function key() {
- return key($this->elements);
- }
-
- function next() {
- $this->valid = (FALSE !== next($this->elements));
- }
-
- function valid() {
- return $this->valid;
- }
-}
-
-/**
- * Open Data Definition (ODD) superclass.
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- */
-abstract class ODD {
- /**
- * Attributes.
- */
- private $attributes = array();
-
- /**
- * Optional body.
- */
- private $body;
-
- /**
- * Construct an ODD document with initial values.
- */
- public function __construct() {
- $this->body = "";
- }
-
- public function getAttributes() {
- return $this->attributes;
- }
-
- public function setAttribute($key, $value) {
- $this->attributes[$key] = $value;
- }
-
- public function getAttribute($key) {
- if (isset($this->attributes[$key])) {
- return $this->attributes[$key];
- }
-
- return NULL;
- }
-
- public function setBody($value) {
- $this->body = $value;
- }
-
- public function getBody() {
- return $this->body;
- }
-
- /**
- * Set the published time.
- *
- * @param int $time Unix timestamp
- */
- public function setPublished($time) {
- $this->attributes['published'] = date("r", $time);
- }
-
- /**
- * Return the published time as a unix timestamp.
- *
- * @return int or false on failure.
- */
- public function getPublishedAsTime() {
- return strtotime($this->attributes['published']);
- }
-
- /**
- * For serialisation, implement to return a string name of the tag eg "header" or "metadata".
- * @return string
- */
- abstract protected function getTagName();
-
- /**
- * Magic function to generate valid ODD XML for this item.
- */
- public function __toString() {
- // Construct attributes
- $attr = "";
- foreach ($this->attributes as $k => $v) {
- $attr .= ($v!="") ? "$k=\"$v\" " : "";
- }
-
- $body = $this->getBody();
- $tag = $this->getTagName();
-
- $end = "/>";
- if ($body!="") {
- $end = "><![CDATA[$body]]></{$tag}>";
- }
-
- return "<{$tag} $attr" . $end . "\n";
- }
-}
-
-/**
- * ODD Entity class.
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- */
-class ODDEntity extends ODD {
- function __construct($uuid, $class, $subclass = "") {
- parent::__construct();
-
- $this->setAttribute('uuid', $uuid);
- $this->setAttribute('class', $class);
- $this->setAttribute('subclass', $subclass);
- }
-
- protected function getTagName() { return "entity"; }
-}
-
-/**
- * ODD Metadata class.
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- */
-class ODDMetaData extends ODD {
- function __construct($uuid, $entity_uuid, $name, $value, $type = "", $owner_uuid = "") {
- parent::__construct();
-
- $this->setAttribute('uuid', $uuid);
- $this->setAttribute('entity_uuid', $entity_uuid);
- $this->setAttribute('name', $name);
- $this->setAttribute('type', $type);
- $this->setAttribute('owner_uuid', $owner_uuid);
- $this->setBody($value);
- }
-
- protected function getTagName() {
- return "metadata";
- }
-}
-
-/**
- * ODD Relationship class.
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- */
-class ODDRelationship extends ODD {
- function __construct($uuid1, $type, $uuid2) {
- parent::__construct();
-
- $this->setAttribute('uuid1', $uuid1);
- $this->setAttribute('type', $type);
- $this->setAttribute('uuid2', $uuid2);
- }
-
- protected function getTagName() { return "relationship"; }
-}
+// @codingStandardsIgnoreStart
/**
* Attempt to construct an ODD object out of a XmlElement or sub-elements.
*
* @param XmlElement $element The element(s)
+ *
* @return mixed An ODD object if the element can be handled, or false.
+ * @access private
*/
-function ODD_factory(XmlElement $element) {
+function ODD_factory (XmlElement $element) {
$name = $element->name;
$odd = false;
switch ($name) {
case 'entity' :
- $odd = new ODDEntity("","","");
+ $odd = new ODDEntity("", "", "");
break;
case 'metadata' :
- $odd = new ODDMetaData("","","","");
+ $odd = new ODDMetaData("", "", "", "");
break;
case 'relationship' :
- $odd = new ODDRelationship("","","");
+ $odd = new ODDRelationship("", "", "");
break;
}
@@ -319,15 +37,15 @@ function ODD_factory(XmlElement $element) {
if ($odd) {
// Attributes
foreach ($element->attributes as $k => $v) {
- $odd->setAttribute($k,$v);
+ $odd->setAttribute($k, $v);
}
// Body
$body = $element->content;
$a = stripos($body, "<![CDATA");
$b = strripos($body, "]]>");
- if (($body) && ($a!==false) && ($b!==false)) {
- $body = substr($body, $a+8, $b-($a+8));
+ if (($body) && ($a !== false) && ($b !== false)) {
+ $body = substr($body, $a + 8, $b - ($a + 8));
}
$odd->setBody($body);
@@ -340,7 +58,9 @@ function ODD_factory(XmlElement $element) {
* Import an ODD document.
*
* @param string $xml The XML ODD.
+ *
* @return ODDDocument
+ * @access private
*/
function ODD_Import($xml) {
// Parse XML to an array
@@ -378,8 +98,12 @@ function ODD_Import($xml) {
* Export an ODD Document.
*
* @param ODDDocument $document The Document.
- * @param ODDWrapperFactory $wrapper Optional wrapper permitting the export process to embed ODD in other document formats.
+ *
+ * @return string
+ * @access private
*/
function ODD_Export(ODDDocument $document) {
return "$document";
-} \ No newline at end of file
+}
+
+// @codingStandardsIgnoreEnd
diff --git a/engine/lib/output.php b/engine/lib/output.php
index 6e861e4ac..de4f911fb 100644
--- a/engine/lib/output.php
+++ b/engine/lib/output.php
@@ -1,41 +1,45 @@
<?php
/**
* Output functions
- * Processing text for output, formatting HTML,
+ * Processing text for output such as pulling out URLs and extracting excerpts
*
* @package Elgg
* @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
*/
/**
* Takes a string and turns any URLs into formatted links
*
* @param string $text The input string
- * @return string The output stirng with formatted links
- **/
+ *
+ * @return string The output string with formatted links
+ */
function parse_urls($text) {
+
+ // URI specification: http://www.ietf.org/rfc/rfc3986.txt
+ // This varies from the specification in the following ways:
+ // * Supports non-ascii characters
+ // * Does not allow parentheses and single quotes
+ // * Cuts off commas, exclamation points, and periods off as last character
+
// @todo this causes problems with <attr = "val">
- // must be ing <attr="val"> format (no space).
+ // must be in <attr="val"> format (no space).
// By default htmlawed rewrites tags to this format.
// if PHP supported conditional negative lookbehinds we could use this:
// $r = preg_replace_callback('/(?<!=)(?<![ ])?(?<!["\'])((ht|f)tps?:\/\/[^\s\r\n\t<>"\'\!\(\),]+)/i',
- //
- // we can put , in the list of excluded char but need to keep . because of domain names.
- // it is removed in the callback.
- $r = preg_replace_callback('/(?<!=)(?<!["\'])((ht|f)tps?:\/\/[^\s\r\n\t<>"\'\!\(\),]+)/i',
+ $r = preg_replace_callback('/(?<![=\/"\'])((ht|f)tps?:\/\/[^\s\r\n\t<>"\']+)/i',
create_function(
'$matches',
'
$url = $matches[1];
- $period = \'\';
- if (substr($url, -1, 1) == \'.\') {
- $period = \'.\';
- $url = trim($url, \'.\');
+ $punc = "";
+ $last = substr($url, -1, 1);
+ if (in_array($last, array(".", "!", ",", "(", ")"))) {
+ $punc = $last;
+ $url = rtrim($url, ".!,()");
}
$urltext = str_replace("/", "/<wbr />", $url);
- return "<a href=\"$url\" style=\"text-decoration:underline;\">$urltext</a>$period";
+ return "<a href=\"$url\" rel=\"nofollow\">$urltext</a>$punc";
'
), $text);
@@ -44,46 +48,26 @@ function parse_urls($text) {
/**
* Create paragraphs from text with line spacing
- * Borrowed from Wordpress.
*
+ * @param string $pee The string
+ * @deprecated Use elgg_autop instead
+ * @todo Add deprecation warning in 1.9
+ *
+ * @return string
**/
-function autop($pee, $br = 1) {
- $pee = $pee . "\n"; // just to make things a little easier, pad the end
- $pee = preg_replace('|<br />\s*<br />|', "\n\n", $pee);
- // Space things out a little
- $allblocks = '(?:table|thead|tfoot|caption|colgroup|tbody|tr|td|th|div|dl|dd|dt|ul|ol|li|pre|select|form|map|area|blockquote|address|math|style|input|p|h[1-6]|hr)';
- $pee = preg_replace('!(<' . $allblocks . '[^>]*>)!', "\n$1", $pee);
- $pee = preg_replace('!(</' . $allblocks . '>)!', "$1\n\n", $pee);
- $pee = str_replace(array("\r\n", "\r"), "\n", $pee); // cross-platform newlines
- if ( strpos($pee, '<object') !== false ) {
- $pee = preg_replace('|\s*<param([^>]*)>\s*|', "<param$1>", $pee); // no pee inside object/embed
- $pee = preg_replace('|\s*</embed>\s*|', '</embed>', $pee);
- }
- $pee = preg_replace("/\n\n+/", "\n\n", $pee); // take care of duplicates
- $pee = preg_replace('/\n?(.+?)(?:\n\s*\n|\z)/s', "<p>$1</p>\n", $pee); // make paragraphs, including one at the end
- $pee = preg_replace('|<p>\s*?</p>|', '', $pee); // under certain strange conditions it could create a P of entirely whitespace
- $pee = preg_replace('!<p>([^<]+)\s*?(</(?:div|address|form)[^>]*>)!', "<p>$1</p>$2", $pee);
- $pee = preg_replace( '|<p>|', "$1<p>", $pee );
- $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee); // don't pee all over a tag
- $pee = preg_replace("|<p>(<li.+?)</p>|", "$1", $pee); // problem with nested lists
- $pee = preg_replace('|<p><blockquote([^>]*)>|i', "<blockquote$1><p>", $pee);
- $pee = str_replace('</blockquote></p>', '</p></blockquote>', $pee);
- $pee = preg_replace('!<p>\s*(</?' . $allblocks . '[^>]*>)!', "$1", $pee);
- $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*</p>!', "$1", $pee);
- if ($br) {
- $pee = preg_replace_callback('/<(script|style).*?<\/\\1>/s', create_function('$matches', 'return str_replace("\n", "<WPPreserveNewline />", $matches[0]);'), $pee);
- $pee = preg_replace('|(?<!<br />)\s*\n|', "<br />\n", $pee); // optionally make line breaks
- $pee = str_replace('<WPPreserveNewline />', "\n", $pee);
- }
- $pee = preg_replace('!(</?' . $allblocks . '[^>]*>)\s*<br />!', "$1", $pee);
- $pee = preg_replace('!<br />(\s*</?(?:p|li|div|dl|dd|dt|th|pre|td|ul|ol)[^>]*>)!', '$1', $pee);
-// if (strpos($pee, '<pre') !== false) {
-// mind the space between the ? and >. Only there because of the comment.
-// $pee = preg_replace_callback('!(<pre.*? >)(.*?)</pre>!is', 'clean_pre', $pee );
-// }
- $pee = preg_replace( "|\n</p>$|", '</p>', $pee );
-
- return $pee;
+function autop($pee) {
+ return elgg_autop($pee);
+}
+
+/**
+ * Create paragraphs from text with line spacing
+ *
+ * @param string $string The string
+ *
+ * @return string
+ **/
+function elgg_autop($string) {
+ return ElggAutoP::getInstance()->process($string);
}
/**
@@ -92,15 +76,16 @@ function autop($pee, $br = 1) {
* If no spaces are found (like in Japanese) will crop off at the
* n char mark. Adds ... if any text was chopped.
*
- * @param string $text
- * @param int $num_chars Return a string up to $num_chars long
+ * @param string $text The full text to excerpt
+ * @param int $num_chars Return a string up to $num_chars long
+ *
* @return string
* @since 1.7.2
*/
-function elgg_make_excerpt($text, $num_chars = 250) {
- $text = trim(strip_tags($text));
+function elgg_get_excerpt($text, $num_chars = 250) {
+ $text = trim(elgg_strip_tags($text));
$string_length = elgg_strlen($text);
-
+
if ($string_length <= $num_chars) {
return $text;
}
@@ -116,7 +101,7 @@ function elgg_make_excerpt($text, $num_chars = 250) {
$excerpt = trim(elgg_substr($excerpt, 0, $space));
if ($string_length != elgg_strlen($excerpt)) {
- $excerpt .= '&#8230';
+ $excerpt .= '...';
}
return $excerpt;
@@ -125,7 +110,8 @@ function elgg_make_excerpt($text, $num_chars = 250) {
/**
* Handles formatting of ampersands in urls
*
- * @param string $url
+ * @param string $url The URL
+ *
* @return string
* @since 1.7.1
*/
@@ -134,21 +120,350 @@ function elgg_format_url($url) {
}
/**
+ * Converts an associative array into a string of well-formed attributes
+ *
+ * @note usually for HTML, but could be useful for XML too...
+ *
+ * @param array $attrs An associative array of attr => val pairs
+ *
+ * @return string HTML attributes to be inserted into a tag (e.g., <tag $attrs>)
+ */
+function elgg_format_attributes(array $attrs) {
+ $attrs = elgg_clean_vars($attrs);
+ $attributes = array();
+
+ if (isset($attrs['js'])) {
+ //@todo deprecated notice?
+
+ if (!empty($attrs['js'])) {
+ $attributes[] = $attrs['js'];
+ }
+
+ unset($attrs['js']);
+ }
+
+ foreach ($attrs as $attr => $val) {
+ $attr = strtolower($attr);
+
+ if ($val === TRUE) {
+ $val = $attr; //e.g. checked => TRUE ==> checked="checked"
+ }
+
+ // ignore $vars['entity'] => ElggEntity stuff
+ if ($val !== NULL && $val !== false && (is_array($val) || !is_object($val))) {
+
+ // allow $vars['class'] => array('one', 'two');
+ // @todo what about $vars['style']? Needs to be semi-colon separated...
+ if (is_array($val)) {
+ $val = implode(' ', $val);
+ }
+
+ $val = htmlspecialchars($val, ENT_QUOTES, 'UTF-8', false);
+ $attributes[] = "$attr=\"$val\"";
+ }
+ }
+
+ return implode(' ', $attributes);
+}
+
+/**
+ * Preps an associative array for use in {@link elgg_format_attributes()}.
+ *
+ * Removes all the junk that {@link elgg_view()} puts into $vars.
+ * Maintains backward compatibility with attributes like 'internalname' and 'internalid'
+ *
+ * @note This function is called automatically by elgg_format_attributes(). No need to
+ * call it yourself before using elgg_format_attributes().
+ *
+ * @param array $vars The raw $vars array with all it's dirtiness (config, url, etc.)
+ *
+ * @return array The array, ready to be used in elgg_format_attributes().
+ * @access private
+ */
+function elgg_clean_vars(array $vars = array()) {
+ unset($vars['config']);
+ unset($vars['url']);
+ unset($vars['user']);
+
+ // backwards compatibility code
+ if (isset($vars['internalname'])) {
+ $vars['name'] = $vars['internalname'];
+ unset($vars['internalname']);
+ }
+
+ if (isset($vars['internalid'])) {
+ $vars['id'] = $vars['internalid'];
+ unset($vars['internalid']);
+ }
+
+ if (isset($vars['__ignoreInternalid'])) {
+ unset($vars['__ignoreInternalid']);
+ }
+
+ if (isset($vars['__ignoreInternalname'])) {
+ unset($vars['__ignoreInternalname']);
+ }
+
+ return $vars;
+}
+
+/**
+ * Converts shorthand urls to absolute urls.
+ *
+ * If the url is already absolute or protocol-relative, no change is made.
+ *
+ * @example
+ * elgg_normalize_url(''); // 'http://my.site.com/'
+ * elgg_normalize_url('dashboard'); // 'http://my.site.com/dashboard'
+ * elgg_normalize_url('http://google.com/'); // no change
+ * elgg_normalize_url('//google.com/'); // no change
+ *
+ * @param string $url The URL to normalize
+ *
+ * @return string The absolute url
+ */
+function elgg_normalize_url($url) {
+ // see https://bugs.php.net/bug.php?id=51192
+ // from the bookmarks save action.
+ $php_5_2_13_and_below = version_compare(PHP_VERSION, '5.2.14', '<');
+ $php_5_3_0_to_5_3_2 = version_compare(PHP_VERSION, '5.3.0', '>=') &&
+ version_compare(PHP_VERSION, '5.3.3', '<');
+
+ if ($php_5_2_13_and_below || $php_5_3_0_to_5_3_2) {
+ $tmp_address = str_replace("-", "", $url);
+ $validated = filter_var($tmp_address, FILTER_VALIDATE_URL);
+ } else {
+ $validated = filter_var($url, FILTER_VALIDATE_URL);
+ }
+
+ // work around for handling absoluate IRIs (RFC 3987) - see #4190
+ if (!$validated && (strpos($url, 'http:') === 0) || (strpos($url, 'https:') === 0)) {
+ $validated = true;
+ }
+
+ if ($validated) {
+ // all normal URLs including mailto:
+ return $url;
+
+ } elseif (preg_match("#^(\#|\?|//)#i", $url)) {
+ // '//example.com' (Shortcut for protocol.)
+ // '?query=test', #target
+ return $url;
+
+ } elseif (stripos($url, 'javascript:') === 0 || stripos($url, 'mailto:') === 0) {
+ // 'javascript:' and 'mailto:'
+ // Not covered in FILTER_VALIDATE_URL
+ return $url;
+
+ } elseif (preg_match("#^[^/]*\.php(\?.*)?$#i", $url)) {
+ // 'install.php', 'install.php?step=step'
+ return elgg_get_site_url() . $url;
+
+ } elseif (preg_match("#^[^/]*\.#i", $url)) {
+ // 'example.com', 'example.com/subpage'
+ return "http://$url";
+
+ } else {
+ // 'page/handler', 'mod/plugin/file.php'
+
+ // trim off any leading / because the site URL is stored
+ // with a trailing /
+ return elgg_get_site_url() . ltrim($url, '/');
+ }
+}
+
+/**
* When given a title, returns a version suitable for inclusion in a URL
*
* @param string $title The title
+ *
* @return string The optimised title
+ * @since 1.7.2
*/
-function friendly_title($title) {
- return elgg_view('output/friendlytitle', array('title' => $title));
+function elgg_get_friendly_title($title) {
+
+ // return a URL friendly title to short circuit normal title formatting
+ $params = array('title' => $title);
+ $result = elgg_trigger_plugin_hook('format', 'friendly:title', $params, NULL);
+ if ($result) {
+ return $result;
+ }
+
+ // titles are often stored HTML encoded
+ $title = html_entity_decode($title, ENT_QUOTES, 'UTF-8');
+
+ $title = ElggTranslit::urlize($title);
+
+ return $title;
}
/**
- * Displays a UNIX timestamp in a friendly way (eg "less than a minute ago")
+ * Formats a UNIX timestamp in a friendly way (eg "less than a minute ago")
+ *
+ * @see elgg_view_friendly_time()
*
* @param int $time A UNIX epoch timestamp
- * @return string The friendly time
+ *
+ * @return string The friendly time string
+ * @since 1.7.2
+ */
+function elgg_get_friendly_time($time) {
+
+ // return a time string to short circuit normal time formatting
+ $params = array('time' => $time);
+ $result = elgg_trigger_plugin_hook('format', 'friendly:time', $params, NULL);
+ if ($result) {
+ return $result;
+ }
+
+ $diff = time() - (int)$time;
+
+ $minute = 60;
+ $hour = $minute * 60;
+ $day = $hour * 24;
+
+ if ($diff < $minute) {
+ return elgg_echo("friendlytime:justnow");
+ } else if ($diff < $hour) {
+ $diff = round($diff / $minute);
+ if ($diff == 0) {
+ $diff = 1;
+ }
+
+ if ($diff > 1) {
+ return elgg_echo("friendlytime:minutes", array($diff));
+ } else {
+ return elgg_echo("friendlytime:minutes:singular", array($diff));
+ }
+ } else if ($diff < $day) {
+ $diff = round($diff / $hour);
+ if ($diff == 0) {
+ $diff = 1;
+ }
+
+ if ($diff > 1) {
+ return elgg_echo("friendlytime:hours", array($diff));
+ } else {
+ return elgg_echo("friendlytime:hours:singular", array($diff));
+ }
+ } else {
+ $diff = round($diff / $day);
+ if ($diff == 0) {
+ $diff = 1;
+ }
+
+ if ($diff > 1) {
+ return elgg_echo("friendlytime:days", array($diff));
+ } else {
+ return elgg_echo("friendlytime:days:singular", array($diff));
+ }
+ }
+}
+
+/**
+ * Strip tags and offer plugins the chance.
+ * Plugins register for output:strip_tags plugin hook.
+ * Original string included in $params['original_string']
+ *
+ * @param string $string Formatted string
+ *
+ * @return string String run through strip_tags() and any plugin hooks.
*/
-function friendly_time($time) {
- return elgg_view('output/friendlytime', array('time' => $time));
+function elgg_strip_tags($string) {
+ $params['original_string'] = $string;
+
+ $string = strip_tags($string);
+ $string = elgg_trigger_plugin_hook('format', 'strip_tags', $params, $string);
+
+ return $string;
}
+
+/**
+ * Apply html_entity_decode() to a string while re-entitising HTML
+ * special char entities to prevent them from being decoded back to their
+ * unsafe original forms.
+ *
+ * This relies on html_entity_decode() not translating entities when
+ * doing so leaves behind another entity, e.g. &amp;gt; if decoded would
+ * create &gt; which is another entity itself. This seems to escape the
+ * usual behaviour where any two paired entities creating a HTML tag are
+ * usually decoded, i.e. a lone &gt; is not decoded, but &lt;foo&gt; would
+ * be decoded to <foo> since it creates a full tag.
+ *
+ * Note: This function is poorly explained in the manual - which is really
+ * bad given its potential for misuse on user input already escaped elsewhere.
+ * Stackoverflow is littered with advice to use this function in the precise
+ * way that would lead to user input being capable of injecting arbitrary HTML.
+ *
+ * @param string $string
+ *
+ * @return string
+ *
+ * @author Pádraic Brady
+ * @copyright Copyright (c) 2010 Pádraic Brady (http://blog.astrumfutura.com)
+ * @license Released under dual-license GPL2/MIT by explicit permission of Pádraic Brady
+ *
+ * @access private
+ */
+function _elgg_html_decode($string) {
+ $string = str_replace(
+ array('&gt;', '&lt;', '&amp;', '&quot;', '&#039;'),
+ array('&amp;gt;', '&amp;lt;', '&amp;amp;', '&amp;quot;', '&amp;#039;'),
+ $string
+ );
+ $string = html_entity_decode($string, ENT_NOQUOTES, 'UTF-8');
+ $string = str_replace(
+ array('&amp;gt;', '&amp;lt;', '&amp;amp;', '&amp;quot;', '&amp;#039;'),
+ array('&gt;', '&lt;', '&amp;', '&quot;', '&#039;'),
+ $string
+ );
+ return $string;
+}
+
+/**
+ * Prepares query string for output to prevent CSRF attacks.
+ *
+ * @param string $string
+ * @return string
+ *
+ * @access private
+ */
+function _elgg_get_display_query($string) {
+ //encode <,>,&, quotes and characters above 127
+ if (function_exists('mb_convert_encoding')) {
+ $display_query = mb_convert_encoding($string, 'HTML-ENTITIES', 'UTF-8');
+ } else {
+ // if no mbstring extension, we just strip characters
+ $display_query = preg_replace("/[^\x01-\x7F]/", "", $string);
+ }
+ return htmlspecialchars($display_query, ENT_QUOTES, 'UTF-8', false);
+}
+
+/**
+ * Unit tests for Output
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
+ */
+function output_unit_test($hook, $type, $value, $params) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/output.php';
+ return $value;
+}
+
+/**
+ * Initialise the Output subsystem.
+ *
+ * @return void
+ * @access private
+ */
+function output_init() {
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'output_unit_test');
+}
+
+elgg_register_event_handler('init', 'system', 'output_init');
diff --git a/engine/lib/pagehandler.php b/engine/lib/pagehandler.php
index 5f60eefae..0cf99b6fe 100644
--- a/engine/lib/pagehandler.php
+++ b/engine/lib/pagehandler.php
@@ -2,82 +2,92 @@
/**
* Elgg page handler functions
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Routing
*/
/**
- * Turns the current page over to the page handler, allowing registered handlers to take over.
+ * Routes the request to a registered page handler
*
- * If a page handler returns FALSE, the request is handed over to the default_page_handler.
+ * This function sets the context based on the handler name (first segment of the
+ * URL). It also triggers a plugin hook 'route', $handler so that plugins can
+ * modify the routing or handle a request.
*
* @param string $handler The name of the handler type (eg 'blog')
- * @param array $page The parameters to the page, as an array (exploded by '/' slashes)
- * @return true|false Depending on whether a registered page handler was found
+ * @param array $page The parameters to the page, as an array (exploded by '/' slashes)
+ *
+ * @return bool
+ * @access private
*/
function page_handler($handler, $page) {
global $CONFIG;
- set_context($handler);
+ elgg_set_context($handler);
- $page = explode('/',$page);
+ $page = explode('/', $page);
// remove empty array element when page url ends in a / (see #1480)
if ($page[count($page) - 1] === '') {
array_pop($page);
}
- if (!isset($CONFIG->pagehandler) || empty($handler)) {
- $result = false;
- } else if (isset($CONFIG->pagehandler[$handler]) && is_callable($CONFIG->pagehandler[$handler])) {
- $function = $CONFIG->pagehandler[$handler];
- $result = $function($page, $handler);
- if ($result !== false) {
- $result = true;
- }
- } else {
- $result = false;
+ // return false to stop processing the request (because you handled it)
+ // return a new $request array if you want to route the request differently
+ $request = array(
+ 'handler' => $handler,
+ 'segments' => $page,
+ );
+ $request = elgg_trigger_plugin_hook('route', $handler, null, $request);
+ if ($request === false) {
+ return true;
}
- if (!$result) {
- $result = default_page_handler($page, $handler);
- }
- if ($result !== false) {
- $result = true;
+ $handler = $request['handler'];
+ $page = $request['segments'];
+
+ $result = false;
+ if (isset($CONFIG->pagehandler)
+ && !empty($handler)
+ && isset($CONFIG->pagehandler[$handler])
+ && is_callable($CONFIG->pagehandler[$handler])) {
+ $function = $CONFIG->pagehandler[$handler];
+ $result = call_user_func($function, $page, $handler);
}
- return $result;
+ return $result || headers_sent();
}
/**
* Registers a page handler for a particular identifier
*
* For example, you can register a function called 'blog_page_handler' for handler type 'blog'
- * Now for all URLs of type http://yoururl/pg/blog/*, the blog_page_handler() function will be called.
+ * For all URLs http://yoururl/blog/*, the blog_page_handler() function will be called.
* The part of the URL marked with * above will be exploded on '/' characters and passed as an
* array to that function.
* For example, the URL http://yoururl/blog/username/friends/ would result in the call:
* blog_page_handler(array('username','friends'), blog);
*
- * Page handler functions should return true or the default page handler will be called.
- *
* A request to register a page handler with the same identifier as previously registered
* handler will replace the previous one.
*
* The context is set to the page handler identifier before the registered
* page handler function is called. For the above example, the context is set to 'blog'.
*
- * @param string $handler The page type to handle
+ * Page handlers should return true to indicate that they handled the request.
+ * Requests not handled are forwarded to the front page with a reason of 404.
+ * Plugins can register for the 'forward', '404' plugin hook. @see forward()
+ *
+ * @param string $handler The page type to handle
* @param string $function Your function name
- * @return true|false Depending on success
+ *
+ * @return bool Depending on success
*/
-function register_page_handler($handler, $function) {
+function elgg_register_page_handler($handler, $function) {
global $CONFIG;
+
if (!isset($CONFIG->pagehandler)) {
$CONFIG->pagehandler = array();
}
- if (is_callable($function)) {
+ if (is_callable($function, true)) {
$CONFIG->pagehandler[$handler] = $function;
return true;
}
@@ -88,14 +98,16 @@ function register_page_handler($handler, $function) {
/**
* Unregister a page handler for an identifier
*
- * Note: to replace a page handler, call register_page_handler()
- *
+ * Note: to replace a page handler, call elgg_register_page_handler()
+ *
* @param string $handler The page type identifier
+ *
* @since 1.7.2
+ * @return void
*/
-function unregister_page_handler($handler) {
+function elgg_unregister_page_handler($handler) {
global $CONFIG;
-
+
if (!isset($CONFIG->pagehandler)) {
return;
}
@@ -104,34 +116,35 @@ function unregister_page_handler($handler) {
}
/**
- * A default page handler
- * Tries to locate a suitable file to include. Only works for core pages, not plugins.
+ * Serve an error page
+ *
+ * @todo not sending status codes yet
*
- * @param array $page The page URL elements
- * @param string $handler The base handler
- * @return true|false Depending on success
+ * @param string $hook The name of the hook
+ * @param string $type The type of the hook
+ * @param bool $result The current value of the hook
+ * @param array $params Parameters related to the hook
+ * @return void
*/
-function default_page_handler($page, $handler) {
- global $CONFIG;
-
- $page = implode('/', $page);
-
- // protect against including arbitary files
- $page = str_replace("..", "", $page);
-
- $callpath = $CONFIG->path . $handler . "/" . $page;
- if (is_dir($callpath)) {
- $callpath = sanitise_filepath($callpath);
- $callpath .= "index.php";
- if (file_exists($callpath)) {
- if (include($callpath)) {
- return TRUE;
- }
- }
- } else if (file_exists($callpath)) {
- include($callpath);
- return TRUE;
+function elgg_error_page_handler($hook, $type, $result, $params) {
+ if (elgg_view_exists("errors/$type")) {
+ $content = elgg_view("errors/$type", $params);
+ } else {
+ $content = elgg_view("errors/default", $params);
}
+ $body = elgg_view_layout('error', array('content' => $content));
+ echo elgg_view_page('', $body, 'error');
+ exit;
+}
- return FALSE;
+/**
+ * Initializes the page handler/routing system
+ *
+ * @return void
+ * @access private
+ */
+function page_handler_init() {
+ elgg_register_plugin_hook_handler('forward', '404', 'elgg_error_page_handler');
}
+
+elgg_register_event_handler('init', 'system', 'page_handler_init');
diff --git a/engine/lib/pageowner.php b/engine/lib/pageowner.php
index 32c431632..bd63d08c6 100644
--- a/engine/lib/pageowner.php
+++ b/engine/lib/pageowner.php
@@ -1,169 +1,297 @@
<?php
/**
* Elgg page owner library
- * Contains functions for managing page ownership
+ * Contains functions for managing page ownership and context
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage PageOwner
*/
/**
- * Gets the page owner for the current page.
- * @uses $CONFIG
- * @return int|false The current page owner guid (0 if none).
+ * Gets the guid of the entity that owns the current page.
+ *
+ * @param int $guid Optional parameter used by elgg_set_page_owner_guid().
+ *
+ * @return int The current page owner guid (0 if none).
+ * @since 1.8.0
*/
+function elgg_get_page_owner_guid($guid = 0) {
+ static $page_owner_guid;
-function page_owner() {
- global $CONFIG;
+ if ($guid) {
+ $page_owner_guid = $guid;
+ }
+
+ if (isset($page_owner_guid)) {
+ return $page_owner_guid;
+ }
+
+ // return guid of page owner entity
+ $guid = elgg_trigger_plugin_hook('page_owner', 'system', NULL, 0);
+
+ if ($guid) {
+ $page_owner_guid = $guid;
+ }
+
+ return $guid;
+}
+
+/**
+ * Gets the owner entity for the current page.
+ *
+ * @note Access is disabled when getting the page owner entity.
+ *
+ * @return ElggUser|ElggGroup|false The current page owner or false if none.
+ *
+ * @since 1.8.0
+ */
+function elgg_get_page_owner_entity() {
+ $guid = elgg_get_page_owner_guid();
+ if ($guid > 0) {
+ $ia = elgg_set_ignore_access(true);
+ $owner = get_entity($guid);
+ elgg_set_ignore_access($ia);
+
+ return $owner;
+ }
+
+ return false;
+}
+
+/**
+ * Set the guid of the entity that owns this page
+ *
+ * @param int $guid The guid of the page owner
+ * @return void
+ * @since 1.8.0
+ */
+function elgg_set_page_owner_guid($guid) {
+ elgg_get_page_owner_guid($guid);
+}
- $returnval = NULL;
+/**
+ * Sets the page owner based on request
+ *
+ * Tries to figure out the page owner by looking at the URL or a request
+ * parameter. The request parameters used are 'username' and 'owner_guid'. If
+ * the page request is going through the page handling system, this function
+ * attempts to figure out the owner if the url fits the patterns of:
+ * <handler>/owner/<username>
+ * <handler>/friends/<username>
+ * <handler>/view/<entity guid>
+ * <handler>/add/<container guid>
+ * <handler>/edit/<entity guid>
+ * <handler>/group/<group guid>
+ *
+ * @note Access is disabled while finding the page owner for the group gatekeeper functions.
+ *
+ *
+ * @param string $hook 'page_owner'
+ * @param string $entity_type 'system'
+ * @param int $returnvalue Previous function's return value
+ * @param array $params no parameters
+ *
+ * @return int GUID
+ * @access private
+ */
+function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) {
- $setpageowner = set_page_owner();
- if ($setpageowner !== false) {
- return $setpageowner;
+ if ($returnvalue) {
+ return $returnvalue;
}
- if ((!isset($returnval)) && ($username = get_input("username"))) {
- if (substr_count($username,'group:')) {
- preg_match('/group\:([0-9]+)/i',$username,$matches);
+ $ia = elgg_set_ignore_access(true);
+
+ $username = get_input("username");
+ if ($username) {
+ // @todo using a username of group:<guid> is deprecated
+ if (substr_count($username, 'group:')) {
+ preg_match('/group\:([0-9]+)/i', $username, $matches);
$guid = $matches[1];
if ($entity = get_entity($guid)) {
- $returnval = $entity->getGUID();
+ elgg_set_ignore_access($ia);
+ return $entity->getGUID();
}
}
- if ((!isset($returnval)) && ($user = get_user_by_username($username))) {
- $returnval = $user->getGUID();
+
+ if ($user = get_user_by_username($username)) {
+ elgg_set_ignore_access($ia);
+ return $user->getGUID();
}
}
-
- if ((!isset($returnval)) && ($owner = get_input("owner_guid"))) {
+ $owner = get_input("owner_guid");
+ if ($owner) {
if ($user = get_entity($owner)) {
- $returnval = $user->getGUID();
+ elgg_set_ignore_access($ia);
+ return $user->getGUID();
}
}
-
- if ((!isset($returnval)) && (!empty($CONFIG->page_owner_handlers) && is_array($CONFIG->page_owner_handlers))) {
- foreach($CONFIG->page_owner_handlers as $handler) {
- if ((!isset($returnval)) && ($guid = $handler())) {
- $returnval = $guid;
- }
- }
+ // ignore root and query
+ $uri = current_page_url();
+ $path = str_replace(elgg_get_site_url(), '', $uri);
+ $path = trim($path, "/");
+ if (strpos($path, "?")) {
+ $path = substr($path, 0, strpos($path, "?"));
}
- if (isset($returnval)) {
- // Check if this is obtainable, forwarding if not.
- /*
- * If the owner entity has been set, but is inaccessible then we forward to the dashboard. This
- * catches a bunch of WSoDs. It doesn't have much of a performance hit since 99.999% of the time the next thing
- * a page does after calling this function is to retrieve the owner entity - which is of course cashed.
- */
- $owner_entity = get_entity($returnval);
- if (!$owner_entity) {
-
- // Log an error
- error_log(sprintf(elgg_echo('pageownerunavailable'), $returnval));
-
- // Forward
- forward();
+ // @todo feels hacky
+ if (get_input('page', FALSE)) {
+ $segments = explode('/', $path);
+ if (isset($segments[1]) && isset($segments[2])) {
+ switch ($segments[1]) {
+ case 'owner':
+ case 'friends':
+ $user = get_user_by_username($segments[2]);
+ if ($user) {
+ elgg_set_ignore_access($ia);
+ return $user->getGUID();
+ }
+ break;
+ case 'view':
+ case 'edit':
+ $entity = get_entity($segments[2]);
+ if ($entity) {
+ elgg_set_ignore_access($ia);
+ return $entity->getContainerGUID();
+ }
+ break;
+ case 'add':
+ case 'group':
+ $entity = get_entity($segments[2]);
+ if ($entity) {
+ elgg_set_ignore_access($ia);
+ return $entity->getGUID();
+ }
+ break;
+ }
}
-
- // set the page owner so if we're called again we don't have to think.
- set_page_owner($returnval);
- return $returnval;
}
- return 0;
+ elgg_set_ignore_access($ia);
}
/**
- * Gets the page owner for the current page.
- * @uses $CONFIG
- * @return ElggUser|false The current page owner (false if none).
+ * Sets the page context
+ *
+ * Views can modify their output based on the local context. You may want to
+ * display a list of blogs on a blog page or in a small widget. The rendered
+ * output could be different for those two contexts ('blog' vs 'widget').
+ *
+ * Pages that pass through the page handling system set the context to the
+ * first string after the root url. Example: http://example.org/elgg/bookmarks/
+ * results in the initial context being set to 'bookmarks'.
+ *
+ * The context is a stack so that for a widget on a profile, the context stack
+ * may contain first 'profile' and then 'widget'.
+ *
+ * If no context was been set, the default context returned is 'main'.
+ *
+ * @warning The context is not available until the page_handler runs (after
+ * the 'init, system' event processing has completed).
+ *
+ * @param string $context The context of the page
+ * @return bool
+ * @since 1.8.0
*/
-function page_owner_entity() {
+function elgg_set_context($context) {
global $CONFIG;
- $page_owner = page_owner();
- if ($page_owner > 0) {
- return get_entity($page_owner);
+
+ $context = trim($context);
+
+ if (empty($context)) {
+ return false;
}
- return false;
+ $context = strtolower($context);
+
+ array_pop($CONFIG->context);
+ array_push($CONFIG->context, $context);
+
+ return true;
}
/**
- * Adds a page owner handler - a function that will
- * return the page owner if required
- * (Such functions are required to return false if they don't know)
- * @uses $CONFIG
- * @param string $functionname The name of the function to call
- * @return mixed The guid of the owner or false
+ * Get the current context.
+ *
+ * Since context is a stack, this is equivalent to a peek.
+ *
+ * @return string|NULL
+ * @since 1.8.0
*/
-
-function add_page_owner_handler($functionname) {
+function elgg_get_context() {
global $CONFIG;
- if (empty($CONFIG->page_owner_handlers)) {
- $CONFIG->page_owner_handlers = array();
- }
- if (is_callable($functionname)) {
- $CONFIG->page_owner_handlers[] = $functionname;
+
+ if (!$CONFIG->context) {
+ return null;
}
+
+ return $CONFIG->context[count($CONFIG->context) - 1];
}
/**
- * Allows a page to manually set a page owner
+ * Push a context onto the top of the stack
*
- * @param int $entitytoset The GUID of the page owner
- * @return int|false Either the page owner we've just set, or false if unset
+ * @param string $context The context string to add to the context stack
+ * @return void
+ * @since 1.8.0
*/
-function set_page_owner($entitytoset = -1) {
- static $entity;
-
- if (!isset($entity)) {
- $entity = false;
- }
+function elgg_push_context($context) {
+ global $CONFIG;
- if ($entitytoset > -1) {
- $entity = $entitytoset;
- }
+ array_push($CONFIG->context, $context);
+}
- return $entity;
+/**
+ * Removes and returns the top context string from the stack
+ *
+ * @return string|NULL
+ * @since 1.8.0
+ */
+function elgg_pop_context() {
+ global $CONFIG;
+ return array_pop($CONFIG->context);
}
/**
- * Sets the functional context of a page
+ * Check if this context exists anywhere in the stack
*
- * @param string $context The context of the page
- * @return string|false Either the context string, or false on failure
+ * This is useful for situations with more than one element in the stack. For
+ * example, a widget has a context of 'widget'. If a widget view needs to render
+ * itself differently based on being on the dashboard or profile pages, it
+ * can check the stack.
+ *
+ * @param string $context The context string to check for
+ * @return bool
+ * @since 1.8.0
*/
-function set_context($context) {
+function elgg_in_context($context) {
global $CONFIG;
- if (!empty($context)) {
- $context = trim($context);
- $context = strtolower($context);
- $CONFIG->context = $context;
- return $context;
- } else {
- return false;
- }
+
+ return in_array($context, $CONFIG->context);
}
/**
- * Returns the functional context of a page
+ * Initializes the page owner functions
*
- * @return string The context, or 'main' if no context has been provided
+ * @note This is on the 'boot, system' event so that the context is set up quickly.
+ *
+ * @return void
+ * @access private
*/
-function get_context() {
- global $CONFIG;
- if (isset($CONFIG->context) && !empty($CONFIG->context)) {
- return $CONFIG->context;
- }
- if ($context = get_plugin_name(true)) {
- return $context;
+function page_owner_boot() {
+
+ elgg_register_plugin_hook_handler('page_owner', 'system', 'default_page_owner_handler');
+
+ // Bootstrap the context stack by setting its first entry to the handler.
+ // This is the first segment of the URL and the handler is set by the rewrite rules.
+ // @todo this does not work for actions
+ $handler = get_input('handler', FALSE);
+ if ($handler) {
+ elgg_set_context($handler);
}
- return "main";
}
+
+elgg_register_event_handler('boot', 'system', 'page_owner_boot');
diff --git a/engine/lib/pam.php b/engine/lib/pam.php
index 590ef9fde..1c9c3bfe1 100644
--- a/engine/lib/pam.php
+++ b/engine/lib/pam.php
@@ -2,35 +2,42 @@
/**
* Elgg Simple PAM library
* Contains functions for managing authentication.
- * This is not a full implementation of PAM. It supports a single facility
+ * This is not a full implementation of PAM. It supports a single facility
* (authentication) and allows multiple policies (user authentication is the
- * default). There are two control flags possible for each module: sufficient
- * or required. The entire chain for a policy is processed (or until a
- * required module fails). A module fails by returning false or throwing an
- * exception. The order that modules are processed is determined by the order
- * they are registered. For an example of a PAM, see pam_auth_userpass() in
+ * default). There are two control flags possible for each module: sufficient
+ * or required. The entire chain for a policy is processed (or until a
+ * required module fails). A module fails by returning false or throwing an
+ * exception. The order that modules are processed is determined by the order
+ * they are registered. For an example of a PAM, see pam_auth_userpass() in
* sessions.php.
- *
+ *
* For more information on PAMs see:
* http://www.freebsd.org/doc/en/articles/pam/index.html
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @see ElggPAM
+ *
+ * @package Elgg.Core
+ * @subpackage Authentication.PAM
*/
+global $_PAM_HANDLERS;
$_PAM_HANDLERS = array();
-$_PAM_HANDLERS_MSG = array();
/**
* Register a PAM handler.
*
- * @param string $handler The handler function in the format
- * pam_handler($credentials = NULL);
+ * A PAM handler should return true if the authentication attempt passed. For a
+ * failure, return false or throw an exception. Returning nothing indicates that
+ * the handler wants to be skipped.
+ *
+ * Note, $handler must be string callback (not an array/Closure).
+ *
+ * @param string $handler Callable global handler function in the format ()
+ * pam_handler($credentials = NULL);
* @param string $importance The importance - "sufficient" (default) or "required"
- * @param string $policy - the policy type, default is "user"
- * @return boolean
+ * @param string $policy The policy type, default is "user"
+ *
+ * @return bool
*/
function register_pam_handler($handler, $importance = "sufficient", $policy = "user") {
global $_PAM_HANDLERS;
@@ -39,8 +46,9 @@ function register_pam_handler($handler, $importance = "sufficient", $policy = "u
if (!isset($_PAM_HANDLERS[$policy])) {
$_PAM_HANDLERS[$policy] = array();
}
-
- if (is_callable($handler)) {
+
+ // @todo remove requirement that $handle be a global function
+ if (is_string($handler) && is_callable($handler, true)) {
$_PAM_HANDLERS[$policy][$handler] = new stdClass;
$_PAM_HANDLERS[$policy][$handler]->handler = $handler;
@@ -56,66 +64,13 @@ function register_pam_handler($handler, $importance = "sufficient", $policy = "u
* Unregisters a PAM handler.
*
* @param string $handler The PAM handler function name
- * @param string $policy - the policy type, default is "user"
+ * @param string $policy The policy type, default is "user"
+ *
+ * @return void
+ * @since 1.7.0
*/
function unregister_pam_handler($handler, $policy = "user") {
global $_PAM_HANDLERS;
unset($_PAM_HANDLERS[$policy][$handler]);
}
-
-/**
- * Attempt to authenticate.
- * This function will process all registered PAM handlers or stop when the first
- * handler fails. A handler fails by either returning false or throwing an
- * exception. The advantage of throwing an exception is that it returns a message
- * through the global $_PAM_HANDLERS_MSG which can be used in communication with
- * a user. The order that handlers are processed is determined by the order that
- * they were registered.
- *
- * If $credentials are provided the PAM handler should authenticate using the
- * provided credentials, if not then credentials should be prompted for or
- * otherwise retrieved (eg from the HTTP header or $_SESSION).
- *
- * @param mixed $credentials Mixed PAM handler specific credentials (e.g. username, password)
- * @param string $policy - the policy type, default is "user"
- * @return bool true if authenticated, false if not.
- */
-function pam_authenticate($credentials = NULL, $policy = "user") {
- global $_PAM_HANDLERS, $_PAM_HANDLERS_MSG;
-
- $_PAM_HANDLERS_MSG = array();
-
- $authenticated = false;
-
- foreach ($_PAM_HANDLERS[$policy] as $k => $v) {
- $handler = $v->handler;
- $importance = $v->importance;
-
- try {
- // Execute the handler
- if ($handler($credentials)) {
- // Explicitly returned true
- $_PAM_HANDLERS_MSG[$k] = "Authenticated!";
-
- $authenticated = true;
- } else {
- $_PAM_HANDLERS_MSG[$k] = "Not Authenticated.";
-
- // If this is required then abort.
- if ($importance == 'required') {
- return false;
- }
- }
- } catch (Exception $e) {
- $_PAM_HANDLERS_MSG[$k] = "$e";
-
- // If this is required then abort.
- if ($importance == 'required') {
- return false;
- }
- }
- }
-
- return $authenticated;
-} \ No newline at end of file
diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php
index b8cf5c2d2..d5d3db466 100644
--- a/engine/lib/plugins.php
+++ b/engine/lib/plugins.php
@@ -3,304 +3,562 @@
* Elgg plugins library
* Contains functions for managing plugins
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Plugins
*/
+/**
+ * Tells ElggPlugin::start() to include the start.php file.
+ */
+define('ELGG_PLUGIN_INCLUDE_START', 1);
-/// Cache enabled plugins per page
-$ENABLED_PLUGINS_CACHE = NULL;
+/**
+ * Tells ElggPlugin::start() to automatically register the plugin's views.
+ */
+define('ELGG_PLUGIN_REGISTER_VIEWS', 2);
/**
- * PluginException
- *
- * A plugin Exception, thrown when an Exception occurs relating to the plugin mechanism. Subclass for specific plugin Exceptions.
+ * Tells ElggPlugin::start() to automatically register the plugin's languages.
+ */
+define('ELGG_PLUGIN_REGISTER_LANGUAGES', 4);
+
+/**
+ * Tells ElggPlugin::start() to automatically register the plugin's classes.
+ */
+define('ELGG_PLUGIN_REGISTER_CLASSES', 8);
+
+/**
+ * Prefix for plugin setting names
*
- * @package Elgg
- * @subpackage Exceptions
+ * @todo Can't namespace these because many plugins directly call
+ * private settings via $entity->$name.
*/
-class PluginException extends Exception {}
+//define('ELGG_PLUGIN_SETTING_PREFIX', 'plugin:setting:');
/**
- * @class ElggPlugin Object representing a plugin's settings for a given site.
- * This class is currently a stub, allowing a plugin to saving settings in an object's metadata for each site.
- * @author Curverider Ltd
+ * Prefix for plugin user setting names
*/
-class ElggPlugin extends ElggObject {
- protected function initialise_attributes() {
- parent::initialise_attributes();
+define('ELGG_PLUGIN_USER_SETTING_PREFIX', 'plugin:user_setting:');
+
+/**
+ * Internal settings prefix
+ *
+ * @todo This could be resolved by promoting ElggPlugin to a 5th type.
+ */
+define('ELGG_PLUGIN_INTERNAL_PREFIX', 'elgg:internal:');
- $this->attributes['subtype'] = "plugin";
- }
- public function __construct($guid = null) {
- parent::__construct($guid);
+/**
+ * Returns a list of plugin IDs (dir names) from a dir.
+ *
+ * @param string $dir A dir to scan for plugins. Defaults to config's plugins_path.
+ *
+ * @return array
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_get_plugin_ids_in_dir($dir = null) {
+ if (!$dir) {
+ $dir = elgg_get_plugins_path();
}
- /**
- * Override entity get and sets in order to save data to private data store.
- */
- public function get($name) {
- // See if its in our base attribute
- if (isset($this->attributes[$name])) {
- return $this->attributes[$name];
+ $plugin_ids = array();
+ $handle = opendir($dir);
+
+ if ($handle) {
+ while ($plugin_id = readdir($handle)) {
+ // must be directory and not begin with a .
+ if (substr($plugin_id, 0, 1) !== '.' && is_dir($dir . $plugin_id)) {
+ $plugin_ids[] = $plugin_id;
+ }
}
+ }
+
+ sort($plugin_ids);
- // No, so see if its in the private data store.
- // get_private_setting() returns false if it doesn't exist
- $meta = get_private_setting($this->guid, $name);
+ return $plugin_ids;
+}
- if ($meta === false) {
- // Can't find it, so return null
- return NULL;
+/**
+ * Discovers plugins in the plugins_path setting and creates ElggPlugin
+ * entities for them if they don't exist. If there are plugins with entities
+ * but not actual files, will disable the ElggPlugin entities and mark as inactive.
+ * The ElggPlugin object holds config data, so don't delete.
+ *
+ * @todo Crappy name?
+ * @return bool
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_generate_plugin_entities() {
+ // @todo $site unused, can remove?
+ $site = get_config('site');
+
+ $dir = elgg_get_plugins_path();
+ $db_prefix = elgg_get_config('dbprefix');
+
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'plugin',
+ 'selects' => array('plugin_oe.*'),
+ 'joins' => array("JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid"),
+ 'limit' => ELGG_ENTITIES_NO_VALUE
+ );
+
+ $old_ia = elgg_set_ignore_access(true);
+ $old_access = access_get_show_hidden_status();
+ access_show_hidden_entities(true);
+ $known_plugins = elgg_get_entities_from_relationship($options);
+ /* @var ElggPlugin[] $known_plugins */
+
+ if (!$known_plugins) {
+ $known_plugins = array();
+ }
+
+ // map paths to indexes
+ $id_map = array();
+ foreach ($known_plugins as $i => $plugin) {
+ // if the ID is wrong, delete the plugin because we can never load it.
+ $id = $plugin->getID();
+ if (!$id) {
+ $plugin->delete();
+ unset($known_plugins[$i]);
+ continue;
}
+ $id_map[$plugin->getID()] = $i;
+ }
+
+ $physical_plugins = elgg_get_plugin_ids_in_dir($dir);
- return $meta;
+ if (!$physical_plugins) {
+ return false;
}
- /**
- * Override entity get and sets in order to save data to private data store.
- */
- 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;
+ // check real plugins against known ones
+ foreach ($physical_plugins as $plugin_id) {
+ // is this already in the db?
+ if (array_key_exists($plugin_id, $id_map)) {
+ $index = $id_map[$plugin_id];
+ $plugin = $known_plugins[$index];
+ // was this plugin deleted and its entity disabled?
+ if (!$plugin->isEnabled()) {
+ $plugin->enable();
+ $plugin->deactivate();
+ $plugin->setPriority('last');
}
- $this->attributes[$name] = $value;
+ // remove from the list of plugins to disable
+ unset($known_plugins[$index]);
} else {
- return set_private_setting($this->guid, $name, $value);
+ // add new plugins
+ // priority is force to last in save() if not set.
+ $plugin = new ElggPlugin($plugin_id);
+ $plugin->save();
}
+ }
- return true;
+ // everything remaining in $known_plugins needs to be disabled
+ // because they are entities, but their dirs were removed.
+ // don't delete the entities because they hold settings.
+ foreach ($known_plugins as $plugin) {
+ if ($plugin->isActive()) {
+ $plugin->deactivate();
+ }
+ // remove the priority.
+ $name = elgg_namespace_plugin_private_setting('internal', 'priority');
+ remove_private_setting($plugin->guid, $name);
+ $plugin->disable();
}
+
+ access_show_hidden_entities($old_access);
+ elgg_set_ignore_access($old_ia);
+
+ elgg_reindex_plugin_priorities();
+
+ return true;
}
/**
- * Returns a list of plugins to load, in the order that they should be loaded.
- *
- * @return array List of plugins
+ * Cache a reference to this plugin by its ID
+ *
+ * @param ElggPlugin $plugin
+ *
+ * @access private
*/
-function get_plugin_list() {
- global $CONFIG;
+function _elgg_cache_plugin_by_id(ElggPlugin $plugin) {
+ $map = (array) elgg_get_config('plugins_by_id_map');
+ $map[$plugin->getID()] = $plugin;
+ elgg_set_config('plugins_by_id_map', $map);
+}
- if (!empty($CONFIG->pluginlistcache)) {
- return $CONFIG->pluginlistcache;
+/**
+ * Returns an ElggPlugin object with the path $path.
+ *
+ * @param string $plugin_id The id (dir name) of the plugin. NOT the guid.
+ * @return ElggPlugin|false
+ * @since 1.8.0
+ */
+function elgg_get_plugin_from_id($plugin_id) {
+ $map = (array) elgg_get_config('plugins_by_id_map');
+ if (isset($map[$plugin_id])) {
+ return $map[$plugin_id];
}
- if ($site = get_entity($CONFIG->site_guid)) {
- $pluginorder = $site->pluginorder;
- if (!empty($pluginorder)) {
- $plugins = unserialize($pluginorder);
-
- $CONFIG->pluginlistcache = $plugins;
- return $plugins;
- } else {
- $plugins = array();
+ $plugin_id = sanitize_string($plugin_id);
+ $db_prefix = get_config('dbprefix');
- if ($handle = opendir($CONFIG->pluginspath)) {
- while ($mod = readdir($handle)) {
- if (!in_array($mod,array('.','..','.svn','CVS')) && is_dir($CONFIG->pluginspath . "/" . $mod)) {
- $plugins[] = $mod;
- }
- }
- }
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'plugin',
+ 'joins' => array("JOIN {$db_prefix}objects_entity oe on oe.guid = e.guid"),
+ 'selects' => array("oe.title", "oe.description"),
+ 'wheres' => array("oe.title = '$plugin_id'"),
+ 'limit' => 1
+ );
- sort($plugins);
+ $plugins = elgg_get_entities($options);
- $CONFIG->pluginlistcache = $plugins;
- return $plugins;
- }
+ if ($plugins) {
+ return $plugins[0];
}
return false;
}
/**
- * Regenerates the list of known plugins and saves it to the current site
+ * Returns if a plugin exists in the system.
*
- * Important: You should regenerate simplecache and the viewpath cache after executing this function
- * otherwise you may experience view display artifacts. Do this with the following code:
+ * @warning This checks only plugins that are registered in the system!
+ * If the plugin cache is outdated, be sure to regenerate it with
+ * {@link elgg_generate_plugin_objects()} first.
*
- * elgg_view_regenerate_simplecache();
- * elgg_filepath_cache_reset();
+ * @param string $id The plugin ID.
+ * @since 1.8.0
+ * @return bool
+ */
+function elgg_plugin_exists($id) {
+ $plugin = elgg_get_plugin_from_id($id);
+
+ return ($plugin) ? true : false;
+}
+
+/**
+ * Returns the highest priority of the plugins
*
- * @param array $pluginorder Optionally, a list of existing plugins and their orders
- * @return array The new list of plugins and their orders
+ * @return int
+ * @since 1.8.0
+ * @access private
*/
-function regenerate_plugin_list($pluginorder = false) {
- global $CONFIG;
+function elgg_get_max_plugin_priority() {
+ $db_prefix = get_config('dbprefix');
+ $priority = elgg_namespace_plugin_private_setting('internal', 'priority');
+ $plugin_subtype = get_subtype_id('object', 'plugin');
+
+ $q = "SELECT MAX(CAST(ps.value AS unsigned)) as max
+ FROM {$db_prefix}entities e, {$db_prefix}private_settings ps
+ WHERE ps.name = '$priority'
+ AND ps.entity_guid = e.guid
+ AND e.type = 'object' and e.subtype = $plugin_subtype";
+
+ $data = get_data($q);
+ if ($data) {
+ $max = $data[0]->max;
+ } else {
+ $max = 1;
+ }
- $CONFIG->pluginlistcache = null;
+ // can't have a priority of 0.
+ return ($max) ? $max : 1;
+}
- if ($site = get_entity($CONFIG->site_guid)) {
- if (empty($pluginorder)) {
- $pluginorder = $site->pluginorder;
- $pluginorder = unserialize($pluginorder);
- } else {
- ksort($pluginorder);
- }
+/**
+ * Returns if a plugin is active for a current site.
+ *
+ * @param string $plugin_id The plugin ID
+ * @param int $site_guid The site guid
+ * @since 1.8.0
+ * @return bool
+ */
+function elgg_is_active_plugin($plugin_id, $site_guid = null) {
+ if ($site_guid) {
+ $site = get_entity($site_guid);
+ } else {
+ $site = elgg_get_site_entity();
+ }
- if (empty($pluginorder)) {
- $pluginorder = array();
- }
+ if (!($site instanceof ElggSite)) {
+ return false;
+ }
- $max = 0;
- if (sizeof($pluginorder)) {
- foreach($pluginorder as $key => $plugin) {
- if (is_dir($CONFIG->pluginspath . "/" . $plugin)) {
- if ($key > $max)
- $max = $key;
- } else {
- unset($pluginorder[$key]);
- }
- }
- }
- // Add new plugins to the end
- if ($handle = opendir($CONFIG->pluginspath)) {
- while ($mod = readdir($handle)) {
- if (!in_array($mod,array('.','..','.svn','CVS')) && is_dir($CONFIG->pluginspath . "/" . $mod)) {
- if (!in_array($mod, $pluginorder)) {
- $max = $max + 10;
- $pluginorder[$max] = $mod;
- }
- }
- }
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+
+ if (!$plugin) {
+ return false;
+ }
+
+ return $plugin->isActive($site->guid);
+}
+
+/**
+ * Loads all active plugins in the order specified in the tool admin panel.
+ *
+ * @note This is called on every page load. If a plugin is active and problematic, it
+ * will be disabled and a visible error emitted. This does not check the deps system because
+ * that was too slow.
+ *
+ * @return bool
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_load_plugins() {
+ $plugins_path = elgg_get_plugins_path();
+ $start_flags = ELGG_PLUGIN_INCLUDE_START |
+ ELGG_PLUGIN_REGISTER_VIEWS |
+ ELGG_PLUGIN_REGISTER_LANGUAGES |
+ ELGG_PLUGIN_REGISTER_CLASSES;
+
+ if (!$plugins_path) {
+ return false;
+ }
+
+ // temporary disable all plugins if there is a file called 'disabled' in the plugin dir
+ if (file_exists("$plugins_path/disabled")) {
+ if (elgg_is_admin_logged_in() && elgg_in_context('admin')) {
+ system_message(elgg_echo('plugins:disabled'));
}
+ return false;
+ }
- ksort($pluginorder);
+ if (elgg_get_config('system_cache_loaded')) {
+ $start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_VIEWS;
+ }
+
+ if (elgg_get_config('i18n_loaded_from_cache')) {
+ $start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_LANGUAGES;
+ }
+
+ $return = true;
+ $plugins = elgg_get_plugins('active');
+ if ($plugins) {
+ foreach ($plugins as $plugin) {
+ try {
+ $plugin->start($start_flags);
+ } catch (Exception $e) {
+ $plugin->deactivate();
+ $msg = elgg_echo('PluginException:CannotStart',
+ array($plugin->getID(), $plugin->guid, $e->getMessage()));
+ elgg_add_admin_notice('cannot_start' . $plugin->getID(), $msg);
+ $return = false;
- // Now reorder the keys ..
- $key = 10;
- $plugins = array();
- if (sizeof($pluginorder)) {
- foreach($pluginorder as $plugin) {
- $plugins[$key] = $plugin;
- $key = $key + 10;
+ continue;
}
}
+ }
- $plugins = serialize($plugins);
-
- $site->pluginorder = $plugins;
+ return $return;
+}
- // Regenerate caches
- elgg_view_regenerate_simplecache();
- elgg_filepath_cache_reset();
+/**
+ * Returns an ordered list of plugins
+ *
+ * @param string $status The status of the plugins. active, inactive, or all.
+ * @param mixed $site_guid Optional site guid
+ * @return ElggPlugin[]
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_get_plugins($status = 'active', $site_guid = null) {
+ $db_prefix = get_config('dbprefix');
+ $priority = elgg_namespace_plugin_private_setting('internal', 'priority');
- return $plugins;
+ if (!$site_guid) {
+ $site = get_config('site');
+ $site_guid = $site->guid;
+ }
+ // grab plugins
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'plugin',
+ 'limit' => ELGG_ENTITIES_NO_VALUE,
+ 'selects' => array('plugin_oe.*'),
+ 'joins' => array(
+ "JOIN {$db_prefix}private_settings ps on ps.entity_guid = e.guid",
+ "JOIN {$db_prefix}objects_entity plugin_oe on plugin_oe.guid = e.guid"
+ ),
+ 'wheres' => array("ps.name = '$priority'"),
+ 'order_by' => "CAST(ps.value as unsigned), e.guid"
+ );
+
+ switch ($status) {
+ case 'active':
+ $options['relationship'] = 'active_plugin';
+ $options['relationship_guid'] = $site_guid;
+ $options['inverse_relationship'] = true;
+ break;
+
+ case 'inactive':
+ $options['wheres'][] = "NOT EXISTS (
+ SELECT 1 FROM {$db_prefix}entity_relationships active_er
+ WHERE active_er.guid_one = e.guid
+ AND active_er.relationship = 'active_plugin'
+ AND active_er.guid_two = $site_guid)";
+ break;
+
+ case 'all':
+ default:
+ break;
}
- return false;
-}
+ $old_ia = elgg_set_ignore_access(true);
+ $plugins = elgg_get_entities_from_relationship($options);
+ elgg_set_ignore_access($old_ia);
+ return $plugins;
+}
/**
- * For now, loads plugins directly
+ * Reorder plugins to an order specified by the array.
+ * Plugins not included in this array will be appended to the end.
+ *
+ * @note This doesn't use the ElggPlugin->setPriority() method because
+ * all plugins are being changed and we don't want it to automatically
+ * reorder plugins.
*
- * @todo Add proper plugin handler that launches plugins in an admin-defined order and activates them on admin request
- * @package Elgg
- * @subpackage Core
+ * @param array $order An array of plugin ids in the order to set them
+ * @return bool
+ * @since 1.8.0
+ * @access private
*/
-function load_plugins() {
- global $CONFIG;
+function elgg_set_plugin_priorities(array $order) {
+ $name = elgg_namespace_plugin_private_setting('internal', 'priority');
- if (!empty($CONFIG->pluginspath)) {
- // See if we have cached values for things
- $cached_view_paths = elgg_filepath_cache_load();
- if ($cached_view_paths) {
- $CONFIG->views = unserialize($cached_view_paths);
+ $plugins = elgg_get_plugins('any');
+ if (!$plugins) {
+ return false;
+ }
+
+ $return = true;
+
+ // reindex to get standard counting. no need to increment by 10.
+ // though we do start with 1
+ $order = array_values($order);
+
+ $missing_plugins = array();
+ foreach ($plugins as $plugin) {
+ $plugin_id = $plugin->getID();
+
+ if (!in_array($plugin_id, $order)) {
+ $missing_plugins[] = $plugin;
+ continue;
}
- // temporary disable all plugins if there is a file called 'disabled' in the plugin dir
- if (file_exists($CONFIG->pluginspath . "disabled")) {
- return;
+ $priority = array_search($plugin_id, $order) + 1;
+
+ if (!$plugin->set($name, $priority)) {
+ $return = false;
+ break;
}
+ }
- $plugins = get_plugin_list();
-
- if (sizeof($plugins)) {
- foreach($plugins as $mod) {
- if (is_plugin_enabled($mod)) {
- if (file_exists($CONFIG->pluginspath . $mod)) {
- if (!include($CONFIG->pluginspath . $mod . "/start.php")) {
- // automatically disable the bad plugin
- disable_plugin($mod);
-
- // register error rather than rendering the site unusable with exception
- register_error(sprintf(elgg_echo('PluginException:MisconfiguredPlugin'), $mod));
-
- // continue loading remaining plugins
- continue;
- }
-
- if (!$cached_view_paths) {
- $view_dir = $CONFIG->pluginspath . $mod . '/views/';
-
- if (is_dir($view_dir) && ($handle = opendir($view_dir))) {
- while (FALSE !== ($view_type = readdir($handle))) {
- $view_type_dir = $view_dir . $view_type;
-
- if ('.' !== substr($view_type, 0, 1) && is_dir($view_type_dir)) {
- if (autoregister_views('', $view_type_dir, $view_dir, $view_type)) {
- // add the valid view type.
- if (!in_array($view_type, $CONFIG->view_types)) {
- $CONFIG->view_types[] = $view_type;
- }
- }
- }
- }
- }
- }
-
- if (is_dir($CONFIG->pluginspath . $mod . "/languages")) {
- register_translations($CONFIG->pluginspath . $mod . "/languages/");
- }
- }
- }
+ // set the missing plugins' priorities
+ if ($return && $missing_plugins) {
+ if (!isset($priority)) {
+ $priority = 0;
+ }
+ foreach ($missing_plugins as $plugin) {
+ $priority++;
+ if (!$plugin->set($name, $priority)) {
+ $return = false;
+ break;
}
}
+ }
- // Cache results
- if (!$cached_view_paths) {
- elgg_filepath_cache_save(serialize($CONFIG->views));
- }
+ return $return;
+}
+
+/**
+ * Reindexes all plugin priorities starting at 1.
+ *
+ * @todo Can this be done in a single sql command?
+ * @return bool
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_reindex_plugin_priorities() {
+ return elgg_set_plugin_priorities(array());
+}
+
+/**
+ * Namespaces a string to be used as a private setting for a plugin.
+ *
+ * @param string $type The type of value: user_setting or internal.
+ * @param string $name The name to namespace.
+ * @param string $id The plugin's ID to namespace with. Required for user_setting.
+ * @return string
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_namespace_plugin_private_setting($type, $name, $id = null) {
+ switch ($type) {
+ // commented out because it breaks $plugin->$name access to variables
+ //case 'setting':
+ // $name = ELGG_PLUGIN_SETTING_PREFIX . $name;
+ // break;
+
+ case 'user_setting':
+ if (!$id) {
+ $id = elgg_get_calling_plugin_id();
+ }
+ $name = ELGG_PLUGIN_USER_SETTING_PREFIX . "$id:$name";
+ break;
+
+ case 'internal':
+ $name = ELGG_PLUGIN_INTERNAL_PREFIX . $name;
+ break;
}
+
+ return $name;
}
/**
- * Get the name of the most recent plugin to be called in the call stack (or the plugin that owns the current page, if any).
+ * Get the name of the most recent plugin to be called in the
+ * call stack (or the plugin that owns the current page, if any).
+ *
+ * i.e., if the last plugin was in /mod/foobar/, this would return foo_bar.
*
- * i.e., if the last plugin was in /mod/foobar/, get_plugin_name would return foo_bar.
+ * @param boolean $mainfilename If set to true, this will instead determine the
+ * context from the main script filename called by
+ * the browser. Default = false.
*
- * @param boolean $mainfilename If set to true, this will instead determine the context from the main script filename called by the browser. Default = false.
* @return string|false Plugin name, or false if no plugin name was called
+ * @since 1.8.0
+ * @access private
+ *
+ * @todo get rid of this
*/
-function get_plugin_name($mainfilename = false) {
+function elgg_get_calling_plugin_id($mainfilename = false) {
if (!$mainfilename) {
if ($backtrace = debug_backtrace()) {
- foreach($backtrace as $step) {
+ foreach ($backtrace as $step) {
$file = $step['file'];
- $file = str_replace("\\","/",$file);
- $file = str_replace("//","/",$file);
- if (preg_match("/mod\/([a-zA-Z0-9\-\_]*)\/start\.php$/",$file,$matches)) {
+ $file = str_replace("\\", "/", $file);
+ $file = str_replace("//", "/", $file);
+ if (preg_match("/mod\/([a-zA-Z0-9\-\_]*)\/start\.php$/", $file, $matches)) {
return $matches[1];
}
}
}
} else {
- //if (substr_count($file,'handlers/pagehandler')) {
- if (preg_match("/pg\/([a-zA-Z0-9\-\_]*)\//",$_SERVER['REQUEST_URI'],$matches)) {
- return $matches[1];
+ //@todo this is a hack -- plugins do not have to match their page handler names!
+ if ($handler = get_input('handler', FALSE)) {
+ return $handler;
} else {
$file = $_SERVER["SCRIPT_NAME"];
- $file = str_replace("\\","/",$file);
- $file = str_replace("//","/",$file);
- if (preg_match("/mod\/([a-zA-Z0-9\-\_]*)\//",$file,$matches)) {
+ $file = str_replace("\\", "/", $file);
+ $file = str_replace("//", "/", $file);
+ if (preg_match("/mod\/([a-zA-Z0-9\-\_]*)\//", $file, $matches)) {
return $matches[1];
}
}
@@ -309,589 +567,613 @@ function get_plugin_name($mainfilename = false) {
}
/**
- * Load and parse a plugin manifest from a plugin XML file.
- *
- * Example file:
+ * Returns an array of all provides from all active plugins.
*
- * <plugin_manifest>
- * <!-- Basic information -->
- * <field key="name" value="My Plugin" />
- * <field key="description" value="My Plugin's concise description" />
- * <field key="version" value="1.0" />
- * <field key="category" value="theme" />
- * <field key="category" value="bundled" />
- * <field key="screenshot" value="path/relative/to/my_plugin.jpg" />
- * <field key="screenshot" value="path/relative/to/my_plugin_2.jpg" />
+ * Array in the form array(
+ * 'provide_type' => array(
+ * 'provided_name' => array(
+ * 'version' => '1.8',
+ * 'provided_by' => 'provider_plugin_id'
+ * )
+ * )
+ * )
*
- * <field key="author" value="Curverider Ltd" />
- * <field key="website" value="http://www.elgg.org/" />
- * <field key="copyright" value="(C) Curverider 2008-2010" />
- * <field key="licence" value="GNU Public License version 2" />
- * </plugin_manifest>
+ * @param string $type The type of provides to return
+ * @param string $name A specific provided name to return. Requires $provide_type.
*
- * @param string $plugin Plugin name.
- * @return array of values
+ * @return array
+ * @since 1.8.0
+ * @access private
*/
-function load_plugin_manifest($plugin) {
- global $CONFIG;
-
- $xml = xml_to_object(file_get_contents($CONFIG->pluginspath . $plugin. "/manifest.xml"));
-
- if ($xml) {
- // set up some defaults to normalize expected values to arrays
- $elements = array(
- 'screenshot' => array(),
- 'category' => array()
- );
-
- foreach ($xml->children as $element) {
- $key = $element->attributes['key'];
- $value = $element->attributes['value'];
-
- // create arrays if multiple fields are set
- if (array_key_exists($key, $elements)) {
- if (!is_array($elements[$key])) {
- $orig = $elements[$key];
- $elements[$key] = array($orig);
+function elgg_get_plugins_provides($type = null, $name = null) {
+ static $provides = null;
+ $active_plugins = elgg_get_plugins('active');
+
+ if (!isset($provides)) {
+ $provides = array();
+
+ foreach ($active_plugins as $plugin) {
+ $plugin_provides = array();
+ $manifest = $plugin->getManifest();
+ if ($manifest instanceof ElggPluginManifest) {
+ $plugin_provides = $plugin->getManifest()->getProvides();
+ }
+ if ($plugin_provides) {
+ foreach ($plugin_provides as $provided) {
+ $provides[$provided['type']][$provided['name']] = array(
+ 'version' => $provided['version'],
+ 'provided_by' => $plugin->getID()
+ );
}
-
- $elements[$key][] = $value;
- } else {
- $elements[$key] = $value;
}
}
+ }
- // handle plugins that don't define a name
- if (!isset($elements['name'])) {
- $elements['name'] = ucwords($plugin);
+ if ($type && $name) {
+ if (isset($provides[$type][$name])) {
+ return $provides[$type][$name];
+ } else {
+ return false;
+ }
+ } elseif ($type) {
+ if (isset($provides[$type])) {
+ return $provides[$type];
+ } else {
+ return false;
}
-
- return $elements;
}
- return false;
+ return $provides;
}
/**
- * This function checks a plugin manifest 'elgg_version' value against the current install
- * returning TRUE if the elgg_version is >= the current install's version.
- * @param $manifest_elgg_version_string The build version (eg 2009010201).
- * @return bool
+ * Checks if a plugin is currently providing $type and $name, and optionally
+ * checking a version.
+ *
+ * @param string $type The type of the provide
+ * @param string $name The name of the provide
+ * @param string $version A version to check against
+ * @param string $comparison The comparison operator to use in version_compare()
+ *
+ * @return array An array in the form array(
+ * 'status' => bool Does the provide exist?,
+ * 'value' => string The version provided
+ * )
+ * @since 1.8.0
+ * @access private
*/
-function check_plugin_compatibility($manifest_elgg_version_string) {
- $version = get_version();
-
- if (strpos($manifest_elgg_version_string, '.') === false) {
- // Using version
- $req_version = (int)$manifest_elgg_version_string;
+function elgg_check_plugins_provides($type, $name, $version = null, $comparison = 'ge') {
+ $provided = elgg_get_plugins_provides($type, $name);
+ if (!$provided) {
+ return array(
+ 'status' => false,
+ 'version' => ''
+ );
+ }
- return ($version >= $req_version);
+ if ($version) {
+ $status = version_compare($provided['version'], $version, $comparison);
+ } else {
+ $status = true;
}
- return false;
+ return array(
+ 'status' => $status,
+ 'value' => $provided['version']
+ );
}
/**
- * Shorthand function for finding the plugin settings.
+ * Returns an array of parsed strings for a dependency in the
+ * format: array(
+ * 'type' => requires, conflicts, or provides.
+ * 'name' => The name of the requirement / conflict
+ * 'value' => A string representing the expected value: <1, >=3, !=enabled
+ * 'local_value' => The current value, ("Not installed")
+ * 'comment' => Free form text to help resovle the problem ("Enable / Search for plugin <link>")
+ * )
*
- * @param string $plugin_name Optional plugin name, if not specified then it is detected from where you
- * are calling from.
+ * @param array $dep An ElggPluginPackage dependency array
+ * @return array
+ * @since 1.8.0
+ * @access private
*/
-function find_plugin_settings($plugin_name = "") {
- $options = array('type' => 'object', 'subtype' => 'plugin', 'limit' => 9999);
- $plugins = elgg_get_entities($options);
- $plugin_name = sanitise_string($plugin_name);
- if (!$plugin_name) {
- $plugin_name = get_plugin_name();
+function elgg_get_plugin_dependency_strings($dep) {
+ $dep_system = elgg_extract('type', $dep);
+ $info = elgg_extract('dep', $dep);
+ $type = elgg_extract('type', $info);
+
+ if (!$dep_system || !$info || !$type) {
+ return false;
}
- if ($plugins) {
- foreach ($plugins as $plugin) {
- if (strcmp($plugin->title, $plugin_name)==0) {
- return $plugin;
+ // rewrite some of these to be more readable
+ switch($info['comparison']) {
+ case 'lt':
+ $comparison = '<';
+ break;
+ case 'gt':
+ $comparison = '>';
+ break;
+ case 'ge':
+ $comparison = '>=';
+ break;
+ case 'le':
+ $comparison = '<=';
+ break;
+ default;
+ $comparison = $info['comparison'];
+ break;
+ }
+
+ /*
+ 'requires' 'plugin oauth_lib' <1.3 1.3 'downgrade'
+ 'requires' 'php setting bob' >3 3 'change it'
+ 'conflicts' 'php setting' >3 4 'change it'
+ 'conflicted''plugin profile' any 1.8 'disable profile'
+ 'provides' 'plugin oauth_lib' 1.3 -- --
+ 'priority' 'before blog' -- after 'move it'
+ */
+ $strings = array();
+ $strings['type'] = elgg_echo('ElggPlugin:Dependencies:' . ucwords($dep_system));
+
+ switch ($type) {
+ case 'elgg_version':
+ case 'elgg_release':
+ // 'Elgg Version'
+ $strings['name'] = elgg_echo('ElggPlugin:Dependencies:Elgg');
+ $strings['expected_value'] = "$comparison {$info['version']}";
+ $strings['local_value'] = $dep['value'];
+ $strings['comment'] = '';
+ break;
+
+ case 'php_extension':
+ // PHP Extension %s [version]
+ $strings['name'] = elgg_echo('ElggPlugin:Dependencies:PhpExtension', array($info['name']));
+ if ($info['version']) {
+ $strings['expected_value'] = "$comparison {$info['version']}";
+ $strings['local_value'] = $dep['value'];
+ } else {
+ $strings['expected_value'] = '';
+ $strings['local_value'] = '';
}
+ $strings['comment'] = '';
+ break;
+
+ case 'php_ini':
+ $strings['name'] = elgg_echo('ElggPlugin:Dependencies:PhpIni', array($info['name']));
+ $strings['expected_value'] = "$comparison {$info['value']}";
+ $strings['local_value'] = $dep['value'];
+ $strings['comment'] = '';
+ break;
+
+ case 'plugin':
+ $strings['name'] = elgg_echo('ElggPlugin:Dependencies:Plugin', array($info['name']));
+ $expected = $info['version'] ? "$comparison {$info['version']}" : elgg_echo('any');
+ $strings['expected_value'] = $expected;
+ $strings['local_value'] = $dep['value'] ? $dep['value'] : '--';
+ $strings['comment'] = '';
+ break;
+
+ case 'priority':
+ $expected_priority = ucwords($info['priority']);
+ $real_priority = ucwords($dep['value']);
+ $strings['name'] = elgg_echo('ElggPlugin:Dependencies:Priority');
+ $strings['expected_value'] = elgg_echo("ElggPlugin:Dependencies:Priority:$expected_priority", array($info['plugin']));
+ $strings['local_value'] = elgg_echo("ElggPlugin:Dependencies:Priority:$real_priority", array($info['plugin']));
+ $strings['comment'] = '';
+ break;
+ }
+
+ if ($dep['type'] == 'suggests') {
+ if ($dep['status']) {
+ $strings['comment'] = elgg_echo('ok');
+ } else {
+ $strings['comment'] = elgg_echo('ElggPlugin:Dependencies:Suggests:Unsatisfied');
+ }
+ } else {
+ if ($dep['status']) {
+ $strings['comment'] = elgg_echo('ok');
+ } else {
+ $strings['comment'] = elgg_echo('error');
}
}
- return false;
+ return $strings;
}
/**
- * Find the plugin settings for a user.
+ * Returns the ElggPlugin entity of the last plugin called.
*
- * @param string $plugin_name Plugin name.
- * @param int $user_guid The guid who's settings to retrieve.
- * @return array of settings in an associative array minus prefix.
+ * @return mixed ElggPlugin or false
+ * @since 1.8.0
+ * @access private
*/
-function find_plugin_usersettings($plugin_name = "", $user_guid = 0) {
- $plugin_name = sanitise_string($plugin_name);
- $user_guid = (int)$user_guid;
+function elgg_get_calling_plugin_entity() {
+ $plugin_id = elgg_get_calling_plugin_id();
- if (!$plugin_name) {
- $plugin_name = get_plugin_name();
+ if ($plugin_id) {
+ return elgg_get_plugin_from_id($plugin_id);
}
- if ($user_guid == 0) {
- $user_guid = get_loggedin_userid();
+ return false;
+}
+
+/**
+ * Returns an array of all plugin settings for a user.
+ *
+ * @param mixed $user_guid The user GUID or null for the currently logged in user.
+ * @param string $plugin_id The plugin ID
+ * @param bool $return_obj Return settings as an object? This can be used to in reusable
+ * views where the settings are passed as $vars['entity'].
+ * @return array
+ * @since 1.8.0
+ */
+function elgg_get_all_plugin_user_settings($user_guid = null, $plugin_id = null, $return_obj = false) {
+ if ($plugin_id) {
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ } else {
+ $plugin = elgg_get_calling_plugin_entity();
}
- // Get metadata for user
- $all_metadata = get_all_private_settings($user_guid); //get_metadata_for_entity($user_guid);
- if ($all_metadata) {
- $prefix = "plugin:settings:$plugin_name:";
- $return = new stdClass;
+ if (!$plugin instanceof ElggPlugin) {
+ return false;
+ }
- foreach ($all_metadata as $key => $meta) {
- $name = substr($key, strlen($prefix));
- $value = $meta;
+ $settings = $plugin->getAllUserSettings($user_guid);
- if (strpos($key, $prefix) === 0) {
- $return->$name = $value;
- }
+ if ($settings && $return_obj) {
+ $return = new stdClass;
+
+ foreach ($settings as $k => $v) {
+ $return->$k = $v;
}
return $return;
+ } else {
+ return $settings;
}
-
- return false;
}
/**
* Set a user specific setting for a plugin.
*
- * @param string $name The name - note, can't be "title".
- * @param mixed $value The value.
- * @param int $user_guid Optional user.
- * @param string $plugin_name Optional plugin name, if not specified then it is detected from where you are calling from.
+ * @param string $name The name - note, can't be "title".
+ * @param mixed $value The value.
+ * @param int $user_guid Optional user.
+ * @param string $plugin_id Optional plugin name, if not specified then it
+ * is detected from where you are calling from.
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function set_plugin_usersetting($name, $value, $user_guid = 0, $plugin_name = "") {
- $plugin_name = sanitise_string($plugin_name);
- $user_guid = (int)$user_guid;
- $name = sanitise_string($name);
-
- if (!$plugin_name) {
- $plugin_name = get_plugin_name();
- }
-
- $user = get_entity($user_guid);
- if (!$user) {
- $user = get_loggedin_user();
+function elgg_set_plugin_user_setting($name, $value, $user_guid = null, $plugin_id = null) {
+ if ($plugin_id) {
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ } else {
+ $plugin = elgg_get_calling_plugin_entity();
}
- if (($user) && ($user instanceof ElggUser)) {
- $prefix = "plugin:settings:$plugin_name:$name";
- //$user->$prefix = $value;
- //$user->save();
-
- // Hook to validate setting
- $value = trigger_plugin_hook('plugin:usersetting', 'user', array(
- 'user' => $user,
- 'plugin' => $plugin_name,
- 'name' => $name,
- 'value' => $value
- ), $value);
-
- return set_private_setting($user->guid, $prefix, $value);
+ if (!$plugin) {
+ return false;
}
- return false;
+ return $plugin->setUserSetting($name, $value, $user_guid);
}
/**
- * Clears a user-specific plugin setting
+ * Unsets a user-specific plugin setting
*
- * @param str $name Name of the plugin setting
- * @param int $user_guid Defaults to logged in user
- * @param str $plugin_name Defaults to contextual plugin name
- * @return bool Success
+ * @param string $name Name of the setting
+ * @param int $user_guid Defaults to logged in user
+ * @param string $plugin_id Defaults to contextual plugin name
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function clear_plugin_usersetting($name, $user_guid=0, $plugin_name='') {
- $plugin_name = sanitise_string($plugin_name);
- $name = sanitise_string($name);
-
- if (!$plugin_name) {
- $plugin_name = get_plugin_name();
- }
-
- $user = get_entity((int) $user_guid);
- if (!$user) {
- $user = get_loggedin_user();
+function elgg_unset_plugin_user_setting($name, $user_guid = null, $plugin_id = null) {
+ if ($plugin_id) {
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ } else {
+ $plugin = elgg_get_calling_plugin_entity();
}
- if (($user) && ($user instanceof ElggUser)) {
- $prefix = "plugin:settings:$plugin_name:$name";
-
- return remove_private_setting($user->getGUID(), $prefix);
+ if (!$plugin) {
+ return false;
}
- return FALSE;
+ return $plugin->unsetUserSetting($name, $user_guid);
}
/**
* Get a user specific setting for a plugin.
*
- * @param string $name The name.
- * @param string $plugin_name Optional plugin name, if not specified then it is detected from where you are calling from.
+ * @param string $name The name of the setting.
+ * @param int $user_guid Guid of owning user
+ * @param string $plugin_id Optional plugin name, if not specified
+ * it is detected from where you are calling.
+ *
+ * @return mixed
+ * @since 1.8.0
*/
-function get_plugin_usersetting($name, $user_guid = 0, $plugin_name = "") {
- $plugin_name = sanitise_string($plugin_name);
- $user_guid = (int)$user_guid;
- $name = sanitise_string($name);
-
- if (!$plugin_name) {
- $plugin_name = get_plugin_name();
- }
-
- $user = get_entity($user_guid);
- if (!$user) {
- $user = get_loggedin_user();
+function elgg_get_plugin_user_setting($name, $user_guid = null, $plugin_id = null) {
+ if ($plugin_id) {
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ } else {
+ $plugin = elgg_get_calling_plugin_entity();
}
- if (($user) && ($user instanceof ElggUser)) {
- $prefix = "plugin:settings:$plugin_name:$name";
- return get_private_setting($user->guid, $prefix); //$user->$prefix;
+ if (!$plugin) {
+ return false;
}
- return false;
+ return $plugin->getUserSetting($name, $user_guid);
}
/**
* Set a setting for a plugin.
*
- * @param string $name The name - note, can't be "title".
- * @param mixed $value The value.
- * @param string $plugin_name Optional plugin name, if not specified then it is detected from where you are calling from.
+ * @param string $name The name of the setting - note, can't be "title".
+ * @param mixed $value The value.
+ * @param string $plugin_id Optional plugin name, if not specified
+ * then it is detected from where you are calling from.
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function set_plugin_setting($name, $value, $plugin_name = "") {
- if (!$plugin_name) {
- $plugin_name = get_plugin_name();
+function elgg_set_plugin_setting($name, $value, $plugin_id = null) {
+ if ($plugin_id) {
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ } else {
+ $plugin = elgg_get_calling_plugin_entity();
}
- $plugin = find_plugin_settings($plugin_name);
if (!$plugin) {
- $plugin = new ElggPlugin();
- }
-
- if ($name!='title') {
- // Hook to validate setting
- $value = trigger_plugin_hook('plugin:setting', 'plugin', array(
- 'plugin' => $plugin_name,
- 'name' => $name,
- 'value' => $value
- ), $value);
-
- $plugin->title = $plugin_name;
- $plugin->access_id = ACCESS_PUBLIC;
- $plugin->save();
- $plugin->$name = $value;
-
- return $plugin->getGUID();
+ return false;
}
- return false;
+ return $plugin->setSetting($name, $value);
}
/**
* Get setting for a plugin.
*
- * @param string $name The name.
- * @param string $plugin_name Optional plugin name, if not specified then it is detected from where you are calling from.
+ * @param string $name The name of the setting.
+ * @param string $plugin_id Optional plugin name, if not specified
+ * then it is detected from where you are calling from.
+ *
+ * @return mixed
+ * @since 1.8.0
+ * @todo make $plugin_id required in future version
*/
-function get_plugin_setting($name, $plugin_name = "") {
- $plugin = find_plugin_settings($plugin_name);
+function elgg_get_plugin_setting($name, $plugin_id = null) {
+ if ($plugin_id) {
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ } else {
+ $plugin = elgg_get_calling_plugin_entity();
+ }
- if ($plugin) {
- return $plugin->$name;
+ if (!$plugin) {
+ return false;
}
- return false;
+ return $plugin->getSetting($name);
}
/**
- * Clear a plugin setting.
+ * Unsets a plugin setting.
+ *
+ * @param string $name The name of the setting.
+ * @param string $plugin_id Optional plugin name, if not specified
+ * then it is detected from where you are calling from.
*
- * @param string $name The name.
- * @param string $plugin_name Optional plugin name, if not specified then it is detected from where you are calling from.
+ * @return bool
+ * @since 1.8.0
*/
-function clear_plugin_setting($name, $plugin_name = "") {
- $plugin = find_plugin_settings($plugin_name);
+function elgg_unset_plugin_setting($name, $plugin_id = null) {
+ if ($plugin_id) {
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ } else {
+ $plugin = elgg_get_calling_plugin_entity();
+ }
- if ($plugin) {
- return remove_private_setting($plugin->guid, $name);
+ if (!$plugin) {
+ return false;
}
- return FALSE;
+ return $plugin->unsetSetting($name);
}
/**
- * Clear all plugin settings.
+ * Unsets all plugin settings for a plugin.
*
- * @param string $plugin_name Optional plugin name, if not specified then it is detected from where you are calling from.
+ * @param string $plugin_id Optional plugin name, if not specified
+ * then it is detected from where you are calling from.
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function clear_all_plugin_settings($plugin_name = "") {
- $plugin = find_plugin_settings($plugin_name);
-
- if ($plugin) {
- return remove_all_private_settings($plugin->guid);
+function elgg_unset_all_plugin_settings($plugin_id = null) {
+ if ($plugin_id) {
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+ } else {
+ $plugin = elgg_get_calling_plugin_entity();
}
- return FALSE;
-}
-
-/**
- * Return an array of installed plugins.
- */
-function get_installed_plugins() {
- global $CONFIG;
-
- $installed_plugins = array();
-
- if (!empty($CONFIG->pluginspath)) {
- $plugins = get_plugin_list();
-
- foreach($plugins as $mod) {
- // require manifest.
- if (!$manifest = load_plugin_manifest($mod)) {
- continue;
- }
- $installed_plugins[$mod] = array();
- $installed_plugins[$mod]['active'] = is_plugin_enabled($mod);
- $installed_plugins[$mod]['manifest'] = $manifest;
- }
+ if (!$plugin) {
+ return false;
}
- return $installed_plugins;
+ return $plugin->unsetAllSettings();
}
/**
- * Enable a plugin for a site (default current site)
+ * Returns entities based upon plugin settings.
+ * Takes all the options for {@see elgg_get_entities_from_private_settings()}
+ * in addition to the ones below.
+ *
+ * @param array $options Array in the format:
*
- * Important: You should regenerate simplecache and the viewpath cache after executing this function
- * otherwise you may experience view display artifacts. Do this with the following code:
+ * plugin_id => NULL|STR The plugin id. Defaults to calling plugin
*
- * elgg_view_regenerate_simplecache();
- * elgg_filepath_cache_reset();
+ * plugin_user_setting_names => NULL|ARR private setting names
*
- * @param string $plugin The plugin name.
- * @param int $site_guid The site id, if not specified then this is detected.
+ * plugin_user_setting_values => NULL|ARR metadata values
+ *
+ * plugin_user_setting_name_value_pairs => NULL|ARR (
+ * name => 'name',
+ * value => 'value',
+ * 'operand' => '=',
+ * )
+ * Currently if multiple values are sent via
+ * an array (value => array('value1', 'value2')
+ * the pair's operand will be forced to "IN".
+ *
+ * plugin_user_setting_name_value_pairs_operator => NULL|STR The operator to use for combining
+ * (name = value) OPERATOR (name = value); default AND
+ *
+ * @return mixed int If count, int. If not count, array. false on errors.
*/
-function enable_plugin($plugin, $site_guid = 0) {
- global $CONFIG, $ENABLED_PLUGINS_CACHE;
-
- $plugin = sanitise_string($plugin);
- $site_guid = (int) $site_guid;
- if ($site_guid == 0) {
- $site_guid = $CONFIG->site_guid;
+function elgg_get_entities_from_plugin_user_settings(array $options = array()) {
+ // if they're passing it don't bother
+ if (!isset($options['plugin_id'])) {
+ $options['plugin_id'] = elgg_get_calling_plugin_id();
}
- $site = get_entity($site_guid);
- if (!($site instanceof ElggSite)) {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $site_guid, "ElggSite"));
- }
+ $singulars = array('plugin_user_setting_name', 'plugin_user_setting_value',
+ 'plugin_user_setting_name_value_pair');
- if (!$plugin_info = load_plugin_manifest($plugin)) {
- return FALSE;
- }
-
- // getMetadata() doesn't return an array if only one plugin is enabled
- if ($enabled = $site->enabled_plugins) {
- if (!is_array($enabled)) {
- $enabled = array($enabled);
- }
- } else {
- $enabled = array();
- }
+ $options = elgg_normalise_plural_options_array($options, $singulars);
- $enabled[] = $plugin;
- $enabled = array_unique($enabled);
+ // rewrite plugin_user_setting_name_* to the right PS ones.
+ $map = array(
+ 'plugin_user_setting_names' => 'private_setting_names',
+ 'plugin_user_setting_values' => 'private_setting_values',
+ 'plugin_user_setting_name_value_pairs' => 'private_setting_name_value_pairs',
+ 'plugin_user_setting_name_value_pairs_operator' => 'private_setting_name_value_pairs_operator'
+ );
- if ($return = $site->setMetaData('enabled_plugins', $enabled)) {
-
- // for other plugins that want to hook into this.
- if ($return && !trigger_elgg_event('enable', 'plugin', array('plugin' => $plugin, 'manifest' => $plugin_info))) {
- $return = FALSE;
+ foreach ($map as $plugin => $private) {
+ if (!isset($options[$plugin])) {
+ continue;
}
- // for this plugin's on_enable
- if ($return && isset($plugin_info['on_enable'])) {
- // pull in the actual plugin's start so the on_enable function is callabe
- // NB: this will not run re-run the init hooks!
- $start = "{$CONFIG->pluginspath}$plugin/start.php";
- if (!file_exists($start) || !include($start)) {
- $return = FALSE;
+ if (isset($options[$private])) {
+ if (!is_array($options[$private])) {
+ $options[$private] = array($options[$private]);
}
- // need language files for the messages
- $translations = "{$CONFIG->pluginspath}$plugin/languages/";
- register_translations($translations);
- if (!is_callable($plugin_info['on_enable'])) {
- $return = FALSE;
- } else {
- $on_enable = call_user_func($plugin_info['on_enable']);
- // allow null to mean "I don't care" like other subsystems
- $return = ($on_disable === FALSE) ? FALSE : TRUE;
- }
+ $options[$private] = array_merge($options[$private], $options[$plugin]);
+ } else {
+ $options[$private] = $options[$plugin];
}
+ }
- // disable the plugin if the on_enable or trigger results failed
- if (!$return) {
- array_pop($enabled);
- $site->setMetaData('enabled_plugins', $enabled);
- }
- $ENABLED_PLUGINS_CACHE = $enabled;
- }
+ $plugin_id = $options['plugin_id'];
+ $prefix = elgg_namespace_plugin_private_setting('user_setting', '', $plugin_id);
+ $options['private_setting_name_prefix'] = $prefix;
- return $return;
+ return elgg_get_entities_from_private_settings($options);
}
/**
- * Disable a plugin for a site (default current site)
+ * Register object, plugin entities as ElggPlugin classes
*
- * Important: You should regenerate simplecache and the viewpath cache after executing this function
- * otherwise you may experience view display artifacts. Do this with the following code:
+ * @return void
+ * @access private
+ */
+function plugin_run_once() {
+ add_subtype("object", "plugin", "ElggPlugin");
+}
+
+/**
+ * Runs unit tests for the entity objects.
*
- * elgg_view_regenerate_simplecache();
- * elgg_filepath_cache_reset();
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
*
- * @param string $plugin The plugin name.
- * @param int $site_guid The site id, if not specified then this is detected.
+ * @return array
+ * @access private
*/
-function disable_plugin($plugin, $site_guid = 0) {
- global $CONFIG, $ENABLED_PLUGINS_CACHE;
-
- $plugin = sanitise_string($plugin);
- $site_guid = (int) $site_guid;
- if ($site_guid == 0) {
- $site_guid = $CONFIG->site_guid;
- }
-
- $site = get_entity($site_guid);
- if (!($site instanceof ElggSite)) {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $site_guid, "ElggSite"));
- }
-
- if (!$plugin_info = load_plugin_manifest($plugin)) {
- return FALSE;
- }
-
- // getMetadata() doesn't return an array if only one plugin is enabled
- if ($enabled = $site->enabled_plugins) {
- if (!is_array($enabled)) {
- $enabled = array($enabled);
- }
- } else {
- $enabled = array();
- }
-
- $old_enabled = $enabled;
-
- // remove the disabled plugin from the array
- if (FALSE !== $i = array_search($plugin, $enabled)) {
- unset($enabled[$i]);
- }
-
- // if we're unsetting all the plugins, this will return an empty array.
- // it will fail with FALSE, though.
- $return = (FALSE === $site->enabled_plugins = $enabled) ? FALSE : TRUE;
-
- if ($return) {
- // for other plugins that want to hook into this.
- if ($return && !trigger_elgg_event('disable', 'plugin', array('plugin' => $plugin, 'manifest' => $plugin_info))) {
- $return = FALSE;
- }
-
- // for this plugin's on_disable
- if ($return && isset($plugin_info['on_disable'])) {
- if (!is_callable($plugin_info['on_disable'])) {
- $return = FALSE;
- } else {
- $on_disable = call_user_func($plugin_info['on_disable']);
- // allow null to mean "I don't care" like other subsystems
- $return = ($on_disable === FALSE) ? FALSE : TRUE;
- }
- }
-
- // disable the plugin if the on_enable or trigger results failed
- if (!$return) {
- $site->enabled_plugins = $old_enabled;
- $ENABLED_PLUGINS_CACHE = $old_enabled;
- } else {
- $ENABLED_PLUGINS_CACHE = $enabled;
- }
- }
-
- return $return;
+function plugins_test($hook, $type, $value, $params) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/plugins.php';
+ return $value;
}
/**
- * Return whether a plugin is enabled or not.
+ * Checks on deactivate plugin event if disabling it won't create unmet dependencies and blocks disable in such case.
*
- * @param string $plugin The plugin name.
- * @param int $site_guid The site id, if not specified then this is detected.
- * @return bool
+ * @param string $event deactivate
+ * @param string $type plugin
+ * @param array $params Parameters array containing entry with ELggPlugin instance under 'plugin_entity' key
+ * @return bool false to block plugin deactivation action
+ *
+ * @access private
*/
-function is_plugin_enabled($plugin, $site_guid = 0) {
- global $CONFIG, $ENABLED_PLUGINS_CACHE;
+function _plugins_deactivate_dependency_check($event, $type, $params) {
+ $plugin_id = $params['plugin_entity']->getManifest()->getPluginID();
+ $plugin_name = $params['plugin_entity']->getManifest()->getName();
- if (!file_exists($CONFIG->pluginspath . $plugin)) {
- return false;
- }
+ $active_plugins = elgg_get_plugins();
- $site_guid = (int) $site_guid;
- if ($site_guid == 0) {
- $site_guid = $CONFIG->site_guid;
- }
+ $dependents = array();
+ foreach ($active_plugins as $plugin) {
+ $manifest = $plugin->getManifest();
+ $requires = $manifest->getRequires();
- if (!$ENABLED_PLUGINS_CACHE) {
- $site = get_entity($site_guid);
- if (!($site instanceof ElggSite)) {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $site_guid, "ElggSite"));
- }
-
- $enabled_plugins = $site->enabled_plugins;
- if ($enabled_plugins && !is_array($enabled_plugins)) {
- $enabled_plugins = array($enabled_plugins);
+ foreach ($requires as $required) {
+ if ($required['type'] == 'plugin' && $required['name'] == $plugin_id) {
+ // there are active dependents
+ $dependents[$manifest->getPluginID()] = $plugin;
+ }
}
- $ENABLED_PLUGINS_CACHE = $enabled_plugins;
}
- foreach ($ENABLED_PLUGINS_CACHE as $e) {
- if ($e == $plugin) {
- return true;
+ if ($dependents) {
+ $list = '<ul>';
+ // construct error message and prevent disabling
+ foreach ($dependents as $dependent) {
+ $list .= '<li>' . $dependent->getManifest()->getName() . '</li>';
}
- }
+ $list .= '</ul>';
- return false;
-}
+ register_error(elgg_echo('ElggPlugin:Dependencies:ActiveDependent', array($plugin_name, $list)));
-/**
- * Run once and only once.
- */
-function plugin_run_once() {
- // Register a class
- add_subtype("object", "plugin", "ElggPlugin");
+ return false;
+ }
}
/**
- * Initialise the file modules.
- * Listens to system boot and registers any appropriate file types and classes
+ * Initialize the plugin system
+ * Listens to system init and registers actions
+ *
+ * @return void
+ * @access private
*/
function plugin_init() {
- // Now run this stuff, but only once
run_function_once("plugin_run_once");
- // Register some actions
- register_action("plugins/settings/save", false, "", true);
- register_action("plugins/usersettings/save");
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'plugins_test');
+
+ // note - plugins are booted by the time this handler is registered
+ // deactivation due to error may have already occurred
+ elgg_register_event_handler('deactivate', 'plugin', '_plugins_deactivate_dependency_check');
+
+ elgg_register_action("plugins/settings/save", '', 'admin');
+ elgg_register_action("plugins/usersettings/save");
+
+ elgg_register_action('admin/plugins/activate', '', 'admin');
+ elgg_register_action('admin/plugins/deactivate', '', 'admin');
+ elgg_register_action('admin/plugins/activate_all', '', 'admin');
+ elgg_register_action('admin/plugins/deactivate_all', '', 'admin');
- register_action('admin/plugins/enable', false, "", true); // Enable
- register_action('admin/plugins/disable', false, "", true); // Disable
- register_action('admin/plugins/enableall', false, "", true); // Enable all
- register_action('admin/plugins/disableall', false, "", true); // Disable all
+ elgg_register_action('admin/plugins/set_priority', '', 'admin');
- register_action('admin/plugins/reorder', false, "", true); // Reorder
+ elgg_register_library('elgg:markdown', elgg_get_root_path() . 'vendors/markdown/markdown.php');
}
-// Register a startup event
-register_elgg_event_handler('init','system','plugin_init');
+elgg_register_event_handler('init', 'system', 'plugin_init');
diff --git a/engine/lib/private_settings.php b/engine/lib/private_settings.php
new file mode 100644
index 000000000..7541f7b3b
--- /dev/null
+++ b/engine/lib/private_settings.php
@@ -0,0 +1,414 @@
+<?php
+/**
+ * Private settings for entities
+ * Private settings provide metadata like storage of settings for plugins
+ * and users.
+ *
+ * @package Elgg.Core
+ * @subpackage PrivateSettings
+ */
+
+/**
+ * Returns entities based upon private settings. Also accepts all
+ * options available to elgg_get_entities(). Supports
+ * the singular option shortcut.
+ *
+ * @see elgg_get_entities
+ *
+ * @param array $options Array in format:
+ *
+ * private_setting_names => NULL|ARR private setting names
+ *
+ * private_setting_values => NULL|ARR metadata values
+ *
+ * private_setting_name_value_pairs => NULL|ARR (
+ * name => 'name',
+ * value => 'value',
+ * 'operand' => '=',
+ * )
+ * Currently if multiple values are sent via
+ * an array (value => array('value1', 'value2')
+ * the pair's operand will be forced to "IN".
+ *
+ * private_setting_name_value_pairs_operator => NULL|STR The operator to use for combining
+ * (name = value) OPERATOR (name = value); default AND
+ *
+ * private_setting_name_prefix => STR A prefix to apply to all private settings. Used to
+ * namespace plugin user settings or by plugins to namespace
+ * their own settings.
+ *
+ *
+ * @return mixed int If count, int. If not count, array. false on errors.
+ * @since 1.8.0
+ */
+function elgg_get_entities_from_private_settings(array $options = array()) {
+ $defaults = array(
+ 'private_setting_names' => ELGG_ENTITIES_ANY_VALUE,
+ 'private_setting_values' => ELGG_ENTITIES_ANY_VALUE,
+ 'private_setting_name_value_pairs' => ELGG_ENTITIES_ANY_VALUE,
+ 'private_setting_name_value_pairs_operator' => 'AND',
+ 'private_setting_name_prefix' => '',
+ );
+
+ $options = array_merge($defaults, $options);
+
+ $singulars = array('private_setting_name', 'private_setting_value',
+ 'private_setting_name_value_pair');
+
+ $options = elgg_normalise_plural_options_array($options, $singulars);
+
+ $clauses = elgg_get_entity_private_settings_where_sql('e', $options['private_setting_names'],
+ $options['private_setting_values'], $options['private_setting_name_value_pairs'],
+ $options['private_setting_name_value_pairs_operator'], $options['private_setting_name_prefix']);
+
+ if ($clauses) {
+ // merge wheres to pass to get_entities()
+ if (isset($options['wheres']) && !is_array($options['wheres'])) {
+ $options['wheres'] = array($options['wheres']);
+ } elseif (!isset($options['wheres'])) {
+ $options['wheres'] = array();
+ }
+
+ $options['wheres'] = array_merge($options['wheres'], $clauses['wheres']);
+
+ // merge joins to pass to get_entities()
+ if (isset($options['joins']) && !is_array($options['joins'])) {
+ $options['joins'] = array($options['joins']);
+ } elseif (!isset($options['joins'])) {
+ $options['joins'] = array();
+ }
+
+ $options['joins'] = array_merge($options['joins'], $clauses['joins']);
+ }
+
+ return elgg_get_entities($options);
+}
+
+/**
+ * Returns private setting name and value SQL where/join clauses for entities.
+ *
+ * @param string $table Entities table name
+ * @param array|null $names Array of names
+ * @param array|null $values Array of values
+ * @param array|null $pairs Array of names / values / operands
+ * @param string $pair_operator Operator for joining pairs where clauses
+ * @param string $name_prefix A string to prefix all names with
+ * @return array
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_get_entity_private_settings_where_sql($table, $names = NULL, $values = NULL,
+$pairs = NULL, $pair_operator = 'AND', $name_prefix = '') {
+
+ global $CONFIG;
+
+ // @todo short circuit test
+
+ $return = array (
+ 'joins' => array (),
+ 'wheres' => array(),
+ );
+
+ $return['joins'][] = "JOIN {$CONFIG->dbprefix}private_settings ps on
+ {$table}.guid = ps.entity_guid";
+
+ $wheres = array();
+
+ // get names wheres
+ $names_where = '';
+ if ($names !== NULL) {
+ if (!is_array($names)) {
+ $names = array($names);
+ }
+
+ $sanitised_names = array();
+ foreach ($names as $name) {
+ $name = $name_prefix . $name;
+ $sanitised_names[] = '\'' . sanitise_string($name) . '\'';
+ }
+
+ $names_str = implode(',', $sanitised_names);
+ if ($names_str) {
+ $names_where = "(ps.name IN ($names_str))";
+ }
+ }
+
+ // get values wheres
+ $values_where = '';
+ if ($values !== NULL) {
+ if (!is_array($values)) {
+ $values = array($values);
+ }
+
+ $sanitised_values = array();
+ foreach ($values as $value) {
+ // normalize to 0
+ if (!$value) {
+ $value = 0;
+ }
+ $sanitised_values[] = '\'' . sanitise_string($value) . '\'';
+ }
+
+ $values_str = implode(',', $sanitised_values);
+ if ($values_str) {
+ $values_where = "(ps.value IN ($values_str))";
+ }
+ }
+
+ if ($names_where && $values_where) {
+ $wheres[] = "($names_where AND $values_where)";
+ } elseif ($names_where) {
+ $wheres[] = "($names_where)";
+ } elseif ($values_where) {
+ $wheres[] = "($values_where)";
+ }
+
+ // add pairs which must be in arrays.
+ if (is_array($pairs)) {
+ // join counter for incremental joins in pairs
+ $i = 1;
+
+ // check if this is an array of pairs or just a single pair.
+ if (isset($pairs['name']) || isset($pairs['value'])) {
+ $pairs = array($pairs);
+ }
+
+ $pair_wheres = array();
+
+ foreach ($pairs as $index => $pair) {
+ // @todo move this elsewhere?
+ // support shortcut 'n' => 'v' method.
+ if (!is_array($pair)) {
+ $pair = array(
+ 'name' => $index,
+ 'value' => $pair
+ );
+ }
+
+ // must have at least a name and value
+ if (!isset($pair['name']) || !isset($pair['value'])) {
+ // @todo should probably return false.
+ continue;
+ }
+
+ if (isset($pair['operand'])) {
+ $operand = sanitise_string($pair['operand']);
+ } else {
+ $operand = ' = ';
+ }
+
+ // for comparing
+ $trimmed_operand = trim(strtolower($operand));
+
+ // if the value is an int, don't quote it because str '15' < str '5'
+ // if the operand is IN don't quote it because quoting should be done already.
+ if (is_numeric($pair['value'])) {
+ $value = sanitise_string($pair['value']);
+ } else if (is_array($pair['value'])) {
+ $values_array = array();
+
+ foreach ($pair['value'] as $pair_value) {
+ if (is_numeric($pair_value)) {
+ $values_array[] = sanitise_string($pair_value);
+ } else {
+ $values_array[] = "'" . sanitise_string($pair_value) . "'";
+ }
+ }
+
+ if ($values_array) {
+ $value = '(' . implode(', ', $values_array) . ')';
+ }
+
+ // @todo allow support for non IN operands with array of values.
+ // will have to do more silly joins.
+ $operand = 'IN';
+ } else if ($trimmed_operand == 'in') {
+ $value = "({$pair['value']})";
+ } else {
+ $value = "'" . sanitise_string($pair['value']) . "'";
+ }
+
+ $name = sanitise_string($name_prefix . $pair['name']);
+
+ // @todo The multiple joins are only needed when the operator is AND
+ $return['joins'][] = "JOIN {$CONFIG->dbprefix}private_settings ps{$i}
+ on {$table}.guid = ps{$i}.entity_guid";
+
+ $pair_wheres[] = "(ps{$i}.name = '$name' AND ps{$i}.value
+ $operand $value)";
+
+ $i++;
+ }
+
+ $where = implode(" $pair_operator ", $pair_wheres);
+ if ($where) {
+ $wheres[] = "($where)";
+ }
+ }
+
+ $where = implode(' AND ', $wheres);
+ if ($where) {
+ $return['wheres'][] = "($where)";
+ }
+
+ return $return;
+}
+
+/**
+ * Gets a private setting for an entity.
+ *
+ * Plugin authors can set private data on entities. By default
+ * private data will not be searched or exported.
+ *
+ * @internal Private data is used to store settings for plugins
+ * and user settings.
+ *
+ * @param int $entity_guid The entity GUID
+ * @param string $name The name of the setting
+ *
+ * @return mixed The setting value, or false on failure
+ * @see set_private_setting()
+ * @see get_all_private_settings()
+ * @see remove_private_setting()
+ * @see remove_all_private_settings()
+ * @link http://docs.elgg.org/DataModel/Entities/PrivateSettings
+ */
+function get_private_setting($entity_guid, $name) {
+ global $CONFIG;
+ $entity_guid = (int) $entity_guid;
+ $name = sanitise_string($name);
+
+ $entity = get_entity($entity_guid);
+ if (!$entity instanceof ElggEntity) {
+ return false;
+ }
+
+ $query = "SELECT value from {$CONFIG->dbprefix}private_settings
+ where name = '{$name}' and entity_guid = {$entity_guid}";
+ $setting = get_data_row($query);
+
+ if ($setting) {
+ return $setting->value;
+ }
+ return false;
+}
+
+/**
+ * Return an array of all private settings.
+ *
+ * @param int $entity_guid The entity GUID
+ *
+ * @return array|false
+ * @see set_private_setting()
+ * @see get_private_settings()
+ * @see remove_private_setting()
+ * @see remove_all_private_settings()
+ * @link http://docs.elgg.org/DataModel/Entities/PrivateSettings
+ */
+function get_all_private_settings($entity_guid) {
+ global $CONFIG;
+
+ $entity_guid = (int) $entity_guid;
+ $entity = get_entity($entity_guid);
+ if (!$entity instanceof ElggEntity) {
+ return false;
+ }
+
+ $query = "SELECT * from {$CONFIG->dbprefix}private_settings where entity_guid = {$entity_guid}";
+ $result = get_data($query);
+ if ($result) {
+ $return = array();
+ foreach ($result as $r) {
+ $return[$r->name] = $r->value;
+ }
+
+ return $return;
+ }
+
+ 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 bool
+ * @see get_private_setting()
+ * @see get_all_private_settings()
+ * @see remove_private_setting()
+ * @see remove_all_private_settings()
+ * @link http://docs.elgg.org/DataModel/Entities/PrivateSettings
+ */
+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'");
+
+ return $result !== false;
+}
+
+/**
+ * Deletes a private setting for an entity.
+ *
+ * @param int $entity_guid The Entity GUID
+ * @param string $name The name of the setting
+ *
+ * @return bool
+ * @see get_private_setting()
+ * @see get_all_private_settings()
+ * @see set_private_setting()
+ * @see remove_all_private_settings()
+ * @link http://docs.elgg.org/DataModel/Entities/PrivateSettings
+ */
+function remove_private_setting($entity_guid, $name) {
+ global $CONFIG;
+
+ $entity_guid = (int) $entity_guid;
+
+ $entity = get_entity($entity_guid);
+ if (!$entity instanceof ElggEntity) {
+ return false;
+ }
+
+ $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 bool
+ * @see get_private_setting()
+ * @see get_all_private_settings()
+ * @see set_private_setting()
+ * @see remove_private_settings()
+ * @link http://docs.elgg.org/DataModel/Entities/PrivateSettings
+ */
+function remove_all_private_settings($entity_guid) {
+ global $CONFIG;
+
+ $entity_guid = (int) $entity_guid;
+
+ $entity = get_entity($entity_guid);
+ if (!$entity instanceof ElggEntity) {
+ return false;
+ }
+
+ return delete_data("DELETE from {$CONFIG->dbprefix}private_settings
+ WHERE entity_guid = {$entity_guid}");
+}
diff --git a/engine/lib/query.php b/engine/lib/query.php
deleted file mode 100644
index 619a2d288..000000000
--- a/engine/lib/query.php
+++ /dev/null
@@ -1,889 +0,0 @@
-<?php
- /**
- * Elgg database query
- * Contains a wrapper for performing database queries in a structured way.
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
- */
-
-
- /**
- * @class QueryComponent Query component superclass.
- * Component of a query.
- * @author Curverider Ltd
- * @see Query
- */
- abstract class QueryComponent
- {
- /**
- * Associative array of fields and values
- */
- private $fields;
-
- function __construct()
- {
- $this->fields = array();
- }
-
- /**
- * Class member get overloading
- *
- * @param string $name
- * @return mixed
- */
- function __get($name) {
- return $this->fields[$name];
- }
-
- /**
- * Class member set overloading
- *
- * @param string $name
- * @param mixed $value
- * @return void
- */
- function __set($name, $value) {
- $this->fields[$name] = $value;
-
- return true;
- }
- }
-
- /**
- * @class SelectFieldQueryComponent Class representing a select field.
- * This class represents a select field component.
- * @author Curverider Ltd
- * @see Query
- */
- class SelectFieldQueryComponent extends QueryComponent
- {
- /**
- * Construct a select field component
- *
- * @param string $table The table containing the field.
- * @param string $field The field or "*"
- */
- function __construct($table, $field)
- {
- global $CONFIG;
-
- $this->table = $CONFIG->dbprefix . sanitise_string($table);
- $this->field = sanitise_string($field);
- }
-
- function __toString()
- {
- return "{$this->table}.{$this->field}";
- }
- }
-
- /**
- * @class LimitOffsetQueryComponent
- * Limit and offset clauses of a query.
- * @author Curverider Ltd
- * @see Query
- */
- class LimitOffsetQueryComponent extends QueryComponent
- {
- /**
- * Specify a limit and an offset.
- *
- * @param int $limit The limit.
- * @param int $offset The offset.
- */
- function __construct($limit = 25, $offset = 0)
- {
- $this->limit = (int)$limit;
- $this->offset = (int)$offset;
- }
-
- function __toString()
- {
- return "limit {$this->offset}, {$this->limit}";
- }
- }
-
- /**
- * @class OrderQueryComponent
- * Order the query results.
- * @author Curverider Ltd
- * @see Query
- */
- class OrderQueryComponent extends QueryComponent
- {
- function __construct($table, $field, $order = "asc")
- {
- global $CONFIG;
-
- $this->table = $CONFIG->dbprefix . sanitise_string($table);
- $this->field = sanitise_string($field);
- $this->order = sanitise_string($order);
- }
-
- function __toString()
- {
- return "order by {$this->table}.{$this->field} {$this->order}";
- }
- }
-
- /**
- * @class TableQueryComponent
- * List of tables to select from or insert into.
- * @author Curverider Ltd
- * @see Query
- */
- class TableQueryComponent extends QueryComponent
- {
- function __construct($table)
- {
- global $CONFIG;
-
- $this->table = $CONFIG->dbprefix . sanitise_string($table);
- }
-
- function __toString()
- {
- return $this->table;
- }
- }
-
- /**
- * @class AccessControlQueryComponent
- * Access control component.
- * @author Curverider Ltd
- * @see Query
- */
- class AccessControlQueryComponent extends QueryComponent
- {
- /**
- * Construct the ACL.
- *
- * @param string $acl_table The table where the access control field is.
- * @param string $acl_field The field containing the access control.
- * @param string $object_owner_table The table containing the owner information for the stuff you're retrieving.
- * @param string $object_owner_id_field The field in $object_owner_table containing the owner information
- */
- function __construct($acl_table = "entities", $acl_field = "access_id", $object_owner_table = "entities", $object_owner_id_field = "owner_guid")
- {
- global $CONFIG;
-
- $this->acl_table = $CONFIG->dbprefix . sanitise_string($acl_table);
- $this->acl_field = sanitise_string($acl_field);
- $this->object_owner_table = $CONFIG->dbprefix . sanitise_string($object_owner_table);
- $this->object_owner_id_field = sanitise_string($object_owner_id_field);
- }
-
- function __toString()
- {
- //$access = get_access_list();
- // KJ - changed to use get_access_sql_suffix
- // Note: currently get_access_sql_suffix is hardwired to use
- // $acl_field = "access_id", $object_owner_table = $acl_table, and
- // $object_owner_id_field = "owner_guid"
- // TODO: recode get_access_sql_suffix to make it possible to specify alternate field names
- return "and ".get_access_sql_suffix($this->acl_table); // Add access controls
-
- //return "and ({$this->acl_table}.{$this->acl_field} in {$access} or ({$this->acl_table}.{$this->acl_field} = 0 and {$this->object_owner_table}.{$this->object_owner_id_field} = {$_SESSION['id']}))";
- }
- }
-
- /**
- * @class JoinQueryComponent Join query.
- * Represents a join query.
- * @author Curverider Ltd
- * @see Query
- */
- class JoinQueryComponent extends QueryComponent
- {
- /**
- * Construct a join query.
- * @param string $table Table one to join...
- * @param string $field Field 1 with...
- * @param string $table2 Table 2 ...
- * @param string $field2 Field...
- * @param string $operator Using this operator
- */
- function __construct($table1, $field1, $table2, $field2, $operator = "=")
- {
- global $CONFIG;
-
- $this->table1 = $CONFIG->dbprefix . sanitise_string($table1);
- $this->field1 = sanitise_string($field1);
- $this->table2 = $CONFIG->dbprefix . sanitise_string($table2);
- $this->field2 = sanitise_string($field2);
- $this->operator = sanitise_string($operator);
- }
-
- function __toString()
- {
- return "join {$this->table2} on {$this->$table}.{$this->$field} {$this->$operator} {$this->$table2}.{$this->$field2}";
- }
- }
-
- /**
- * @class SetQueryComponent Set query.
- * Represents an update set query.
- * @author Curverider Ltd
- * @see Query
- */
- class SetQueryComponent extends QueryComponent
- {
- /**
- * Construct a setting query
- *
- * @param string $table The table to modify
- * @param string $field The field to modify
- * @param mixed $value The value to set it to
- */
- function __construct($table, $field, $value)
- {
- global $CONFIG;
-
- $this->table = $CONFIG->dbprefix . sanitise_string($table);
- $this->field = sanitise_string($field);
- if (is_numeric($value))
- $this->value = (int)$value;
- else
- $this->value = "'".sanitise_string($value)."'";
- }
-
- function __toString()
- {
- return "{$this->table}.{$this->field}={$this->value}";
- }
- }
-
- /**
- * @class WhereQueryComponent
- * A component of a where query.
- * @author Curverider Ltd
- * @see Query
- */
- class WhereQueryComponent extends QueryComponent
- {
- /**
- * A where query.
- *
- * @param string $left_table The table on the left of the operator
- * @param string $left_field The left field
- * @param string $operator The operator eg "=" or "<"
- * @param string $right_table The table on the right of the operator
- * @param string $right_field The right field
- * @param string $link_operator How this where clause links with the previous clause, eg. "and" "or"
- */
- function __construct($left_table, $left_field, $operator, $right_table, $right_field, $link_operator = "and")
- {
- global $CONFIG;
-
- $this->link_operator = sanitise_string($link_operator);
- $this->left_table = $CONFIG->dbprefix . sanitise_string($left_table);
- $this->left_field = sanitise_string($left_field);
- $this->operator = sanitise_string($operator);
- $this->right_table = $CONFIG->dbprefix . sanitise_string($right_table);
- $this->right_field = sanitise_string($right_field);
- }
-
- /**
- * Return the SQL without the link operator.
- */
- public function toStringNoLink()
- {
- return "{$this->left_table }.{$this->left_field} {$this->operator} {$this->right_table}.{$this->right_field}";
- }
-
- function __toString()
- {
- return "{$this->link_operator} " . $this->toStringNoLink();
- }
- }
-
- /**
- * @class WhereStaticQueryComponent
- * A component of a where query where there is no right hand table, rather a static value.
- * @author Curverider Ltd
- * @see Query
- */
- class WhereStaticQueryComponent extends WhereQueryComponent
- {
- /**
- * A where query.
- *
- * @param string $left_table The table on the left of the operator
- * @param string $left_field The left field
- * @param string $operator The operator eg "=" or "<"
- * @param string $value The value
- * @param string $link_operator How this where clause links with the previous clause, eg. "and" "or"
- */
- function __construct($left_table, $left_field, $operator, $value, $link_operator = "and")
- {
- global $CONFIG;
-
- $this->link_operator = sanitise_string($link_operator);
- $this->left_table = $CONFIG->dbprefix . sanitise_string($left_table);
- $this->left_field = sanitise_string($left_field);
- $this->operator = sanitise_string($operator);
- if (is_numeric($value))
- $this->value = (int)$value;
- else
- $this->value = "'".sanitise_string($value)."'";
- }
-
- /**
- * Return the SQL without the link operator.
- */
- public function toStringNoLink()
- {
- return "{$this->left_table }.{$this->left_field} {$this->operator} {$this->value}";
- }
- }
-
- /**
- * @class WhereSetQueryComponent
- * A where query that may contain other where queries (in brackets).
- * @author Curverider Ltd
- * @see Query
- */
- class WhereSetQueryComponent extends WhereQueryComponent
- {
- /**
- * Construct a subset of wheres.
- *
- * @param array $wheres An array of WhereQueryComponent
- * @param string $link_operator How this where clause links with the previous clause, eg. "and" "or"
- */
- function __construct(array $wheres, $link_operator = "and")
- {
- $this->link_operator = sanitise_string($link_operator);
- $this->wheres = $wheres;
- }
-
- public function toStringNoLink()
- {
- $cnt = 0;
- $string = " (";
- foreach ($this->wheres as $where) {
- if (!($where instanceof WhereQueryComponent))
- throw new DatabaseException(elgg_echo('DatabaseException:WhereSetNonQuery'));
-
- if (!$cnt)
- $string.= $where->toStringNoLink();
- else
- $string.=" $where ";
-
- $cnt ++;
- }
- $string .= ")";
-
- return $string;
- }
- }
-
- /**
- * @class QueryTypeQueryComponent
- * What type of query is this?
- * @author Curverider Ltd
- * @see Query
- */
- abstract class QueryTypeQueryComponent extends QueryComponent
- {
- function __toString()
- {
- return $this->query_type;
- }
- }
-
- /**
- * @class SelectQueryTypeQueryComponent
- * A select query.
- * @author Curverider Ltd
- * @see Query
- */
- class SelectQueryTypeQueryComponent extends QueryTypeQueryComponent
- {
- function __construct()
- {
- $this->query_type = "SELECT";
- }
- }
-
- /**
- * @class InsertQueryTypeQueryComponent
- * An insert query.
- * @author Curverider Ltd
- * @see Query
- */
- class InsertQueryTypeQueryComponent extends QueryTypeQueryComponent
- {
- function __construct()
- {
- $this->query_type = "INSERT INTO";
- }
- }
-
- /**
- * @class DeleteQueryTypeQueryComponent
- * A delete query.
- * @author Curverider Ltd
- * @see Query
- */
- class DeleteQueryTypeQueryComponent extends QueryTypeQueryComponent
- {
- function __construct()
- {
- $this->query_type = "DELETE FROM";
- }
- }
-
- /**
- * @class UpdateQueryTypeQueryComponent
- * An update query.
- * @author Curverider Ltd
- * @see Query
- */
- class UpdateQueryTypeQueryComponent extends QueryTypeQueryComponent
- {
- function __construct()
- {
- $this->query_type = "UPDATE";
- }
- }
-
- /**
- * @class Query Provides a framework to construct complex queries in a safer environment.
- *
- * The usage of this class depends on the type of query you are executing, but the basic idea is to
- * construct a query out of pluggable classes.
- *
- * Once constructed SQL can be generated using the toString method, this should happen automatically
- * if you pass the Query object to get_data or similar.
- *
- * To construct a query, create a new Query() object and begin populating it with the various classes
- * that define the various aspects of the query.
- *
- * Notes:
- * - You do not have to specify things in any particular order, provided you specify all required
- * components.
- * - With database tables you do not have to specify your db prefix, this will be added automatically.
- * - When constructing your query keep an eye on the error log - any problems will get spit out here.
- * Note also that __toString won't let you throw Exceptions (!!!) so these are caught and echoed to
- * the log instead.
- *
- * Here is an example of a select query which requests some data out of the entities table with an
- * order and limit that uses a subset where and some normal where queries:
- *
- * <blockquote>
- * // Construct the query
- * $query = new Query();
- *
- * // Say which table we're interested in
- * $query->addTable(new TableQueryComponent("entities"));
- *
- * // What fields are we interested in
- * $query->addSelectField(new SelectFieldQueryComponent("entities","*"));
- *
- * // Add access control (Default access control uses default fields on entities table.
- * // Note that it will error without something specified here!
- * $query->setAccessControl(new AccessControlQueryComponent());
- *
- * // Set a limit and offset, may be omitted.
- * $query->setLimitAndOffset(new LimitOffsetQueryComponent(10,0));
- *
- * // Specify the order, may be omitted
- * $query->setOrder(new OrderQueryComponent("entities", "subtype", "desc"));
- *
- * // Construct a where query
- * //
- * // This demonstrates a WhereSet which lets you have sub wheres, a
- * // WhereStatic which lets you compare a table field against a value and a
- * // Where which lets you compare a table/field with another table/field.
- * $query->addWhere(
- * new WhereSetQueryComponent(
- * array(
- * new WhereStaticQueryComponent("entities", "subtype","=", 1),
- * new WhereQueryComponent("entities","subtype","=", "entities", "subtype")
- * )
- * )
- * );
- *
- * get_data($query);
- * </blockquote>
- *
- * @author Curverider Ltd
- */
- class Query
- {
-
- /// The limit of the query
- private $limit_and_offset;
-
- /// Fields to return on a query
- private $fields;
-
- /// Tables to use in a from query
- private $tables;
-
- /// Join tables
- private $joins;
-
- /// Set values
- private $sets;
-
- /// Where query
- private $where;
-
- /// Order by
- private $order;
-
- /// The query type
- private $query_type;
-
- /// ACL
- private $access_control;
-
- /**
- * Construct query & initialise variables
- */
- function __construct()
- {
- $this->fields = array();
- $this->tables = array();
- $this->joins = array();
- $this->where = array();
- $this->sets = array();
-
- $this->setQueryType(new SelectQueryTypeQueryComponent());
- }
-
- /**
- * Add limits and offsets to the query.
- *
- * @param LimitOffsetQueryComponent $component The limit and offset.
- */
- public function setLimitAndOffset(LimitOffsetQueryComponent $component) { $this->limit_and_offset = $component; }
-
- /**
- * Reset and set the field to the select statement.
- *
- * @param SelectFieldQueryComponent $component Table and field component.
- */
- public function setSelectField(SelectFieldQueryComponent $component)
- {
- $this->fields = array();
- return $this->addSelectField($component);
- }
-
- /**
- * Add a select field.
- *
- * @param SelectFieldQueryComponent $component Add a component.
- */
- public function addSelectField(SelectFieldQueryComponent $component) { $this->fields[] = $component; }
-
- /**
- * Add a join to the component.
- *
- * @param JoinQueryComponent $component The join.
- */
- public function addJoin(JoinQueryComponent $component) { $this->joins[] = $component; }
-
- /**
- * Set a field value in an update or insert statement.
- *
- * @param SetQueryComponent $component Fields to set.
- */
- public function addSet(SetQueryComponent $component) { $this->sets[] = $component; }
-
- /**
- * Set the query type, i.e. "select", "update", "insert" & "delete".
- *
- * @param QueryTypeQueryComponent $component The query type.
- */
- public function setQueryType(QueryTypeQueryComponent $component) { $this->query_type = $component; }
-
- /**
- * Attach an order component.
- *
- * @param OrderQueryComponent $component The order component.
- */
- public function setOrder(OrderQueryComponent $component) { $this->order = $component; }
-
- /**
- * Add a table to the query.
- *
- * @param TableQueryComponent $component Table to add.
- */
- public function addTable(TableQueryComponent $component) { $this->tables[] = $component; }
-
- /**
- * Add a where clause to the query.
- *
- * @param WhereQueryComponent $component The where component
- */
- public function addWhere(WhereQueryComponent $component) { $this->where[] = $component; }
-
- /**
- * Set access control.
- *
- * @param AccessControlQueryComponent $component Access control.
- */
- public function setAccessControl(AccessControlQueryComponent $component) { $this->access_control = $component; }
-
- public function __toString()
- {
- global $CONFIG;
-
- $sql = "";
-
- try
- {
- // Query prefix & fields
- if (!empty($this->query_type))
- {
- $sql .= "{$this->query_type} ";
-
- if (!empty($this->fields))
- {
- $fields = "";
-
- foreach ($this->fields as $field)
- $fields .= "$field";
-
- $sql .= " $fields from ";
- }
- else
- throw new DatabaseException(elgg_echo('DatabaseException:SelectFieldsMissing'));
- }
- else
- throw new DatabaseException(elgg_echo('DatabaseException:UnspecifiedQueryType'));
-
- // Tables
- if (!empty($this->tables))
- {
- foreach($this->tables as $table)
- $sql .= "$table, ";
-
- $sql = trim($sql, ", ");
- }
- else
- throw new DatabaseException(elgg_echo('DatabaseException:NoTablesSpecified'));
-
- // Joins on select queries
- if ($this->query_type->query_type == 'select')
- {
- if (!empty($this->joins))
- {
- foreach($this->joins as $join)
- $sql .= "$join ";
- }
- }
-
- // Setting values
- if (
- ($this->query_type->query_type == 'update') ||
- ($this->query_type->query_type == 'insert')
- )
- {
- $sql .= "set ";
-
- foreach ($this->sets as $set)
- $sql .= "$set, ";
-
- $sql = trim($sql, ", ") . " ";
- }
-
- // Where
- if (!empty($this->where))
- {
- $sql .= " where 1 ";
-
- foreach ($this->where as $where)
- $sql .= "$where ";
- }
-
- // Access control
- if (!empty($this->access_control))
- {
-
- // Catch missing Where
- if (empty($this->where))
- $sql .= " where 1 ";
-
- $sql .= "{$this->access_control} ";
- }
- else
- throw new DatabaseException(elgg_echo('DatabaseException:NoACL'));
-
- // Order by
- if (!empty($this->order))
- $sql .= "{$this->order} ";
-
- // Limits
- if (!empty($this->limit_and_offset))
- $sql .= "{$this->limit_and_offset} ";
-
-
-
- } catch (Exception $e) {
- trigger_error($e, E_USER_WARNING);
- }
-
-
- return $sql;
- }
-
- }
-
- /**
- * @class SimpleQuery A wrapper for Query which provides simple interface for common functions.
- *
- * This class provides simple interface functions for constructing a (reasonably) standard database
- * query.
- *
- * The constructor for this class sets a number of defaults, for example sets default access controls
- * and a limit and offset - to change this then set it manually.
- *
- * @author Curverider Ltd
- * @see Query
- */
- class SimpleQuery extends Query
- {
- function __construct()
- {
- parent::__construct();
-
- // Set a default query type (select)
- $this->simpleQueryType();
-
- // Set a default access control
- $this->simpleAccessControl();
-
- // Set default limit and offset
- $this->simpleLimitAndOffset();
- }
-
- /**
- * Set the query type.
- *
- * @param string $type The type of search - available are "select", "update", "delete", "insert".
- */
- public function simpleQueryType($type = "select")
- {
- $type = strtolower(sanitise_string($type));
-
- switch ($type)
- {
- case "insert" :
- return $this->setQueryType(InsertQueryTypeQueryComponent());
- break;
- case "delete" :
- return $this->setQueryType(DeleteQueryTypeQueryComponent());
- break;
- case "update" :
- return $this->setQueryType(UpdateQueryTypeQueryComponent());
- break;
- default: return $this->setQueryType(SelectQueryTypeQueryComponent());
- }
- }
-
- /**
- * Set a field to query in a select statement.
- *
- * @param string $table Table to query.
- * @param string $field Field in that table.
- */
- public function simpleSelectField($table, $field) { return $this->setSelectField(new SelectFieldQueryComponent($table, $field)); }
-
- /**
- * Add a select field to query in a select statement.
- *
- * @param string $table Table to query.
- * @param string $field Field in that table.
- */
- public function simpleAddSelectField($table, $field) { return $this->addSelectField(new SelectFieldQueryComponent($table, $field)); }
-
- /**
- * Add a set value to an update query.
- *
- * @param string $table The table to update.
- * @param string $field The field in the table.
- * @param mixed $value The value to set it to.
- */
- public function simpleSet($table, $field, $value) { return $this->addSet(new SetQueryComponent($table, $field, $value)); }
-
- /**
- * Add a join to the table.
- *
- * @param string $table Table one to join...
- * @param string $field Field 1 with...
- * @param string $table2 Table 2 ...
- * @param string $field2 Field...
- * @param string $operator Using this operator
- */
- public function simpleJoin($table1, $field1, $table2, $field2, $operator = "=") { return $this->addJoin(new JoinQueryComponent($table1, $field1, $table2, $field2, $operator)); }
-
- /**
- * Add a table to the query.
- *
- * @param string $table The table.
- */
- public function simpleTable($table) { return $this->addTable(new TableQueryComponent($table)); }
-
- /**
- * Compare one table/field to another table/field.
- *
- * @param string $left_table The table on the left of the operator
- * @param string $left_field The left field
- * @param string $operator The operator eg "=" or "<"
- * @param string $right_table The table on the right of the operator
- * @param string $right_field The right field
- * @param string $link_operator How this where clause links with the previous clause, eg. "and" "or"
- */
- public function simpleWhereOnTable($left_table, $left_field, $operator, $right_table, $right_field, $link_operator = "and") { return $this->addWhere(new WhereQueryComponent($left_table, $left_field, $operator, $right_table, $right_field, $link_operator)); }
-
- /**
- * Compare one table/field to a value.
- *
- * @param string $left_table The table on the left of the operator
- * @param string $left_field The left field
- * @param string $operator The operator eg "=" or "<"
- * @param string $value The value
- * @param string $link_operator How this where clause links with the previous clause, eg. "and" "or"
- */
- public function simpleWhereOnValue($left_table, $left_field, $operator, $value, $link_operator = "and") { return $this->addWhere(new WhereStaticQueryComponent($left_table, $left_field, $operator, $value, $link_operator)); }
-
- /**
- * Set access control.
- *
- * @param string $acl_table The table where the access control field is.
- * @param string $acl_field The field containing the access control.
- * @param string $object_owner_id_field The field in $object_owner_table containing the owner information.
- */
- public function simpleAccessControl($acl_table = "entities", $acl_field = "access_id", $object_owner_id_field = "owner_guid") { return $this->setAccessControl(new AccessControlQueryComponent($acl_table, $acl_field, $acl_table, $object_owner_id_field)); }
-
- /**
- * Set the limit and offset.
- *
- * @param int $limit The limit.
- * @param int $offset The offset.
- */
- public function simpleLimitAndOffset($limit = 25, $offset = 0) { return $this->setLimitAndOffset(new LimitOffsetQueryComponent($limit, $offset)); }
-
- /**
- * Set the order query.
- *
- * @param string $table The table to query
- * @param string $field The field to query
- * @param string $order Order the query
- */
- public function simpleOrder($table, $field, $order = "desc")
- {
- $table = sanitise_string($table);
- $field = sanitise_string($field);
- $order = strtolower(sanitise_string($order));
-
- return $this->setOrder(new OrderQueryComponent($table, $field, $order)); break;
- }
- }
diff --git a/engine/lib/relationships.php b/engine/lib/relationships.php
index f813cacba..b0cd627fc 100644
--- a/engine/lib/relationships.php
+++ b/engine/lib/relationships.php
@@ -3,304 +3,17 @@
* Elgg relationships.
* Stub containing relationship functions, making import and export easier.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage DataModel.Relationship
*/
/**
- * Relationship class.
- *
- * @author Curverider Ltd
- * @package Elgg
- * @subpackage Core
- */
-class ElggRelationship implements
- Importable,
- Exportable,
- Loggable, // Can events related to this object class be logged
- Iterator, // Override foreach behaviour
- ArrayAccess // Override for array access
- {
- /**
- * This contains the site's main properties (id, etc)
- * @var array
- */
- protected $attributes;
-
- /**
- * Construct a new site object, optionally from a given id value or row.
- *
- * @param mixed $id
- */
- function __construct($id = null) {
- $this->attributes = array();
-
- if (!empty($id)) {
- if ($id instanceof stdClass) {
- $relationship = $id; // Create from db row
- } else {
- $relationship = get_relationship($id);
- }
-
- if ($relationship) {
- $objarray = (array) $relationship;
- foreach($objarray as $key => $value) {
- $this->attributes[$key] = $value;
- }
- }
- }
- }
-
- /**
- * Class member get overloading
- *
- * @param string $name
- * @return mixed
- */
- function __get($name) {
- if (isset($this->attributes[$name])) {
- return $this->attributes[$name];
- }
-
- return null;
- }
-
- /**
- * Class member set overloading
- *
- * @param string $name
- * @param mixed $value
- * @return mixed
- */
- function __set($name, $value) {
- $this->attributes[$name] = $value;
- return true;
- }
-
- /**
- * Save the relationship
- *
- * @return int the relationship id
- */
- public function save() {
- if ($this->id > 0) {
- delete_relationship($this->id);
- }
-
- $this->id = add_entity_relationship($this->guid_one, $this->relationship, $this->guid_two);
- if (!$this->id) {
- throw new IOException(sprintf(elgg_new('IOException:UnableToSaveNew'), get_class()));
- }
-
- return $this->id;
- }
-
- /**
- * Delete a given relationship.
- */
- public function delete() {
- return delete_relationship($this->id);
- }
-
- /**
- * Get a URL for this relationship.
- *
- * @return string
- */
- public function getURL() {
- return get_relationship_url($this->id);
- }
-
- // EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * Return an array of fields which can be exported.
- */
- public function getExportableValues() {
- return array(
- 'id',
- 'guid_one',
- 'relationship',
- 'guid_two'
- );
- }
-
- /**
- * Export this relationship
- *
- * @return array
- */
- public function export() {
- $uuid = get_uuid_from_object($this);
- $relationship = new ODDRelationship(
- guid_to_uuid($this->guid_one),
- $this->relationship,
- guid_to_uuid($this->guid_two)
- );
-
- $relationship->setAttribute('uuid', $uuid);
-
- return $relationship;
- }
-
- // IMPORTABLE INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * Import a relationship
- *
- * @param array $data
- * @param int $version
- * @return ElggRelationship
- * @throws ImportException
- */
- public function import(ODD $data) {
- if (!($element instanceof ODDRelationship)) {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnexpectedODDClass'));
- }
-
- $uuid_one = $data->getAttribute('uuid1');
- $uuid_two = $data->getAttribute('uuid2');
-
- // See if this entity has already been imported, if so then we need to link to it
- $entity1 = get_entity_from_uuid($uuid_one);
- $entity2 = get_entity_from_uuid($uuid_two);
- if (($entity1) && ($entity2)) {
- // Set the item ID
- $this->attributes['guid_one'] = $entity1->getGUID();
- $this->attributes['guid_two'] = $entity2->getGUID();
-
- // Map verb to relationship
- //$verb = $data->getAttribute('verb');
- //$relationship = get_relationship_from_verb($verb);
- $relationship = $data->getAttribute('type');
-
- if ($relationship) {
- $this->attributes['relationship'] = $relationship;
- // save
- $result = $this->save();
- if (!$result) {
- throw new ImportException(sprintf(elgg_echo('ImportException:ProblemSaving'), get_class()));
- }
-
- return $this;
- }
- }
- }
-
- // 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->id;
- }
-
- /**
- * 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_relationship($id);
- }
-
- /**
- * Return the GUID of the owner of this object.
- */
- public function getObjectOwnerGUID() {
- return $this->owner_guid;
- }
-
- /**
- * Return a type of the object - eg. object, group, user, relationship, metadata, annotation etc
- */
- public function getType() {
- return 'relationship';
- }
-
- /**
- * Return a subtype. For metadata & annotations this is the 'name' and for relationship this is the relationship type.
- */
- public function getSubtype() {
- return $this->relationship;
- }
-
- // 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);
- }
-}
-
-
-/**
* Convert a database row to a new ElggRelationship
*
- * @param stdClass $row
- * @return stdClass or ElggMetadata
+ * @param stdClass $row Database row from the relationship table
+ *
+ * @return ElggRelationship|stdClass
+ * @access private
*/
function row_to_elggrelationship($row) {
if (!($row instanceof stdClass)) {
@@ -313,20 +26,25 @@ function row_to_elggrelationship($row) {
/**
* Return a relationship.
*
- * @param int $id
+ * @param int $id The ID of a relationship
+ *
+ * @return ElggRelationship|false
*/
function get_relationship($id) {
global $CONFIG;
$id = (int)$id;
- return row_to_elggrelationship(get_data_row("SELECT * from {$CONFIG->dbprefix}entity_relationships where id=$id"));
+ $query = "SELECT * from {$CONFIG->dbprefix}entity_relationships where id=$id";
+ return row_to_elggrelationship(get_data_row($query));
}
/**
* Delete a specific relationship.
*
- * @param int $id
+ * @param int $id The relationship ID
+ *
+ * @return bool
*/
function delete_relationship($id) {
global $CONFIG;
@@ -335,7 +53,7 @@ function delete_relationship($id) {
$relationship = get_relationship($id);
- if (trigger_elgg_event('delete', 'relationship', $relationship)) {
+ if (elgg_trigger_event('delete', 'relationship', $relationship)) {
return delete_data("delete from {$CONFIG->dbprefix}entity_relationships where id=$id");
}
@@ -348,9 +66,11 @@ function delete_relationship($id) {
*
* This function lets you make the statement "$guid_one is a $relationship of $guid_two".
*
- * @param int $guid_one
- * @param string $relationship
- * @param int $guid_two
+ * @param int $guid_one First GUID
+ * @param string $relationship Relationship name
+ * @param int $guid_two Second GUID
+ *
+ * @return bool
*/
function add_entity_relationship($guid_one, $relationship, $guid_two) {
global $CONFIG;
@@ -358,17 +78,20 @@ function add_entity_relationship($guid_one, $relationship, $guid_two) {
$guid_one = (int)$guid_one;
$relationship = sanitise_string($relationship);
$guid_two = (int)$guid_two;
+ $time = time();
// Check for duplicates
if (check_entity_relationship($guid_one, $relationship, $guid_two)) {
return false;
}
- $result = insert_data("INSERT into {$CONFIG->dbprefix}entity_relationships (guid_one, relationship, guid_two) values ($guid_one, '$relationship', $guid_two)");
+ $result = insert_data("INSERT into {$CONFIG->dbprefix}entity_relationships
+ (guid_one, relationship, guid_two, time_created)
+ values ($guid_one, '$relationship', $guid_two, $time)");
- if ($result!==false) {
+ if ($result !== false) {
$obj = get_relationship($result);
- if (trigger_elgg_event('create', $relationship, $obj)) {
+ if (elgg_trigger_event('create', $relationship, $obj)) {
return true;
} else {
delete_relationship($result);
@@ -379,12 +102,14 @@ function add_entity_relationship($guid_one, $relationship, $guid_two) {
}
/**
- * Determine whether or not a relationship between two entities exists and returns the relationship object if it does
+ * Determine if a relationship between two entities exists
+ * and returns the relationship object if it does
*
- * @param int $guid_one The GUID of the entity "owning" the relationship
+ * @param int $guid_one The GUID of the entity "owning" the relationship
* @param string $relationship The type of relationship
- * @param int $guid_two The GUID of the entity the relationship is with
- * @return object|false Depending on success
+ * @param int $guid_two The GUID of the entity the relationship is with
+ *
+ * @return ElggRelationship|false Depending on success
*/
function check_entity_relationship($guid_one, $relationship, $guid_two) {
global $CONFIG;
@@ -393,7 +118,13 @@ function check_entity_relationship($guid_one, $relationship, $guid_two) {
$relationship = sanitise_string($relationship);
$guid_two = (int)$guid_two;
- if ($row = get_data_row("SELECT * FROM {$CONFIG->dbprefix}entity_relationships WHERE guid_one=$guid_one AND relationship='$relationship' AND guid_two=$guid_two limit 1")) {
+ $query = "SELECT * FROM {$CONFIG->dbprefix}entity_relationships
+ WHERE guid_one=$guid_one
+ AND relationship='$relationship'
+ AND guid_two=$guid_two limit 1";
+
+ $row = row_to_elggrelationship(get_data_row($query));
+ if ($row) {
return $row;
}
@@ -403,9 +134,11 @@ function check_entity_relationship($guid_one, $relationship, $guid_two) {
/**
* Remove an arbitrary relationship between two entities.
*
- * @param int $guid_one
- * @param string $relationship
- * @param int $guid_two
+ * @param int $guid_one First GUID
+ * @param string $relationship Relationship name
+ * @param int $guid_two Second GUID
+ *
+ * @return bool
*/
function remove_entity_relationship($guid_one, $relationship, $guid_two) {
global $CONFIG;
@@ -419,8 +152,13 @@ function remove_entity_relationship($guid_one, $relationship, $guid_two) {
return false;
}
- if (trigger_elgg_event('delete', $relationship, $obj)) {
- return delete_data("DELETE from {$CONFIG->dbprefix}entity_relationships where guid_one=$guid_one and relationship='$relationship' and guid_two=$guid_two");
+ if (elgg_trigger_event('delete', $relationship, $obj)) {
+ $query = "DELETE from {$CONFIG->dbprefix}entity_relationships
+ where guid_one=$guid_one
+ and relationship='$relationship'
+ and guid_two=$guid_two";
+
+ return (bool)delete_data($query);
} else {
return false;
}
@@ -429,11 +167,12 @@ function remove_entity_relationship($guid_one, $relationship, $guid_two) {
/**
* Removes all arbitrary relationships originating from a particular entity
*
- * @param int $guid_one The GUID of the entity
- * @param string $relationship The name of the relationship (optionally)
- * @param true|false $inverse Whether we're deleting inverse relationships (default false)
- * @param string $type The type of entity to limit this relationship delete to (defaults to all)
- * @return true|false Depending on success
+ * @param int $guid_one The GUID of the entity
+ * @param string $relationship The name of the relationship (optional)
+ * @param bool $inverse Whether we're deleting inverse relationships (default false)
+ * @param string $type The type of entity to the delete to (defaults to all)
+ *
+ * @return bool Depending on success
*/
function remove_entity_relationships($guid_one, $relationship = "", $inverse = false, $type = '') {
global $CONFIG;
@@ -461,10 +200,16 @@ function remove_entity_relationships($guid_one, $relationship = "", $inverse = f
}
if (!$inverse) {
- $sql = "DELETE er from {$CONFIG->dbprefix}entity_relationships as er {$join} where guid_one={$guid_one} {$where}";
+ $sql = "DELETE er from {$CONFIG->dbprefix}entity_relationships as er
+ {$join}
+ where guid_one={$guid_one} {$where}";
+
return delete_data($sql);
} else {
- $sql = "DELETE er from {$CONFIG->dbprefix}entity_relationships as er {$join} where guid_two={$guid_one} {$where}";
+ $sql = "DELETE er from {$CONFIG->dbprefix}entity_relationships as er
+ {$join} where
+ guid_two={$guid_one} {$where}";
+
return delete_data($sql);
}
}
@@ -472,7 +217,10 @@ function remove_entity_relationships($guid_one, $relationship = "", $inverse = f
/**
* Get all the relationships for a given guid.
*
- * @param int $guid
+ * @param int $guid The GUID of the relationship owner
+ * @param bool $inverse_relationship Inverse relationship owners?
+ *
+ * @return ElggRelationship[]
*/
function get_entity_relationships($guid, $inverse_relationship = FALSE) {
global $CONFIG;
@@ -486,9 +234,22 @@ function get_entity_relationships($guid, $inverse_relationship = FALSE) {
return get_data($query, "row_to_elggrelationship");
}
-
/**
* Return entities matching a given query joining against a relationship.
+ * Also accepts all options available to elgg_get_entities() and
+ * elgg_get_entities_from_metadata().
+ *
+ * To ask for entities that do not have a particulat relationship to an entity,
+ * use a custom where clause like the following:
+ *
+ * $options['wheres'][] = "NOT EXISTS (
+ * SELECT 1 FROM {$db_prefix}entity_relationships
+ * WHERE guid_one = e.guid
+ * AND relationship = '$relationship'
+ * )";
+ *
+ * @see elgg_get_entities
+ * @see elgg_get_entities_from_metadata
*
* @param array $options Array in format:
*
@@ -498,7 +259,8 @@ function get_entity_relationships($guid, $inverse_relationship = FALSE) {
*
* inverse_relationship => BOOL Inverse the relationship
*
- * @return array
+ * @return ElggEntity[]|mixed If count, int. If not count, array. false on errors.
+ * @since 1.7.0
*/
function elgg_get_entities_from_relationship($options) {
$defaults = array(
@@ -509,7 +271,7 @@ function elgg_get_entities_from_relationship($options) {
$options = array_merge($defaults, $options);
- $clauses = elgg_get_entity_relationship_where_sql('e', $options['relationship'],
+ $clauses = elgg_get_entity_relationship_where_sql('e.guid', $options['relationship'],
$options['relationship_guid'], $options['inverse_relationship']);
if ($clauses) {
@@ -530,6 +292,16 @@ function elgg_get_entities_from_relationship($options) {
}
$options['joins'] = array_merge($options['joins'], $clauses['joins']);
+
+ if (isset($options['selects']) && !is_array($options['selects'])) {
+ $options['selects'] = array($options['selects']);
+ } elseif (!isset($options['selects'])) {
+ $options['selects'] = array();
+ }
+
+ $select = array('r.id');
+
+ $options['selects'] = array_merge($options['selects'], $select);
}
return elgg_get_entities_from_metadata($options);
@@ -540,13 +312,20 @@ function elgg_get_entities_from_relationship($options) {
*
* @todo add support for multiple relationships and guids.
*
- * @param $table Entities table name
- * @param $relationship relationship string
- * @param $entity_guid entity guid to check
+ * @param string $column Column name the guid should be checked against.
+ * Provide in table.column format.
+ * @param string $relationship Relationship string
+ * @param int $relationship_guid Entity guid to check
+ * @param bool $inverse_relationship Inverse relationship check?
+ *
* @return mixed
+ * @since 1.7.0
+ * @access private
*/
-function elgg_get_entity_relationship_where_sql($table, $relationship = NULL, $relationship_guid = NULL, $inverse_relationship = FALSE) {
- if ($relationship == NULL && $entity_guid == NULL) {
+function elgg_get_entity_relationship_where_sql($column, $relationship = NULL,
+$relationship_guid = NULL, $inverse_relationship = FALSE) {
+
+ if ($relationship == NULL && $relationship_guid == NULL) {
return '';
}
@@ -556,11 +335,9 @@ function elgg_get_entity_relationship_where_sql($table, $relationship = NULL, $r
$joins = array();
if ($inverse_relationship) {
- $joins[] = "JOIN {$CONFIG->dbprefix}entity_relationships r on r.guid_one = e.guid";
- //$wheres[] = "{$table}.guid = {$CONFIG->dbprefix}entity_relationships.guid_two";
+ $joins[] = "JOIN {$CONFIG->dbprefix}entity_relationships r on r.guid_one = $column";
} else {
- $joins[] = "JOIN {$CONFIG->dbprefix}entity_relationships r on r.guid_two = e.guid";
- //$wheres[] = "{$table}.guid = {$CONFIG->dbprefix}entity_relationships.guid_one";
+ $joins[] = "JOIN {$CONFIG->dbprefix}entity_relationships r on r.guid_two = $column";
}
if ($relationship) {
@@ -575,7 +352,7 @@ function elgg_get_entity_relationship_where_sql($table, $relationship = NULL, $r
}
}
- if ($where_str = implode(' AND ' , $wheres)) {
+ if ($where_str = implode(' AND ', $wheres)) {
return array('wheres' => array("($where_str)"), 'joins' => $joins);
}
@@ -584,302 +361,62 @@ function elgg_get_entity_relationship_where_sql($table, $relationship = NULL, $r
}
/**
- * @deprecated 1.7. Use elgg_get_entities_from_relationship().
- * @param $relationship
- * @param $relationship_guid
- * @param $inverse_relationship
- * @param $type
- * @param $subtype
- * @param $owner_guid
- * @param $order_by
- * @param $limit
- * @param $offset
- * @param $count
- * @param $site_guid
- * @return unknown_type
- */
-function get_entities_from_relationship($relationship, $relationship_guid, $inverse_relationship = false,
-$type = "", $subtype = "", $owner_guid = 0, $order_by = "", $limit = 10, $offset = 0,
-$count = false, $site_guid = 0) {
-
- elgg_deprecated_notice('get_entities_from_relationship() was deprecated by elgg_get_entities_from_relationship()!', 1.7);
-
- $options = array();
-
- $options['relationship'] = $relationship;
- $options['relationship_guid'] = $relationship_guid;
- $options['inverse_relationship'] = $inverse_relationship;
-
- if ($type) {
- $options['types'] = $type;
- }
-
- if ($subtype) {
- $options['subtypes'] = $subtype;
- }
-
- if ($owner_guid) {
- $options['owner_guid'] = $owner_guid;
- }
-
- if ($limit) {
- $options['limit'] = $limit;
- }
-
- if ($offset) {
- $options['offset'] = $offset;
- }
-
- if ($order_by) {
- $options['order_by'];
- }
-
- if ($site_guid) {
- $options['site_guid'];
- }
-
- if ($count) {
- $options['count'] = $count;
- }
-
- return elgg_get_entities_from_relationship($options);
-}
-
-/**
* Returns a viewable list of entities by relationship
*
- * @see elgg_view_entity_list
+ * @param array $options Options array for retrieval of entities
+ *
+ * @see elgg_list_entities()
+ * @see elgg_get_entities_from_relationship()
*
- * @param string $relationship The relationship eg "friends_of"
- * @param int $relationship_guid The guid of the entity to use query
- * @param bool $inverse_relationship Reverse the normal function of the query to instead say "give me all entities for whome $relationship_guid is a $relationship of"
- * @param string $type The type of entity (eg 'object')
- * @param string $subtype The entity subtype
- * @param int $owner_guid The owner (default: all)
- * @param int $limit The number of entities to display on a page
- * @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 Whether to display pagination (default: true)
* @return string The viewable list of entities
*/
-function list_entities_from_relationship($relationship, $relationship_guid, $inverse_relationship = false, $type = ELGG_ENTITIES_ANY_VALUE, $subtype = ELGG_ENTITIES_ANY_VALUE, $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $pagination = true) {
- $limit = (int) $limit;
- $offset = (int) get_input('offset');
- $options = array(
- 'relationship' => $relationship,
- 'relationship_guid' => $relationship_guid,
- 'inverse_relationship' => $inverse_relationship,
- 'types' => $type,
- 'subtypes' => $subtype,
- 'owner_guid' => $owner_guid,
- 'order_by' => '',
- 'limit' => $limit,
- 'offset' => $offset,
- 'count' => TRUE
- );
- $count = elgg_get_entities_from_relationship($options);
- $options['count'] = FALSE;
- $entities = elgg_get_entities_from_relationship($options);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination);
+function elgg_list_entities_from_relationship(array $options = array()) {
+ return elgg_list_entities($options, 'elgg_get_entities_from_relationship');
}
/**
* Gets the number of entities by a the number of entities related to them in a particular way.
- * This is a good way to get out the users with the most friends, or the groups with the most members.
+ * This is a good way to get out the users with the most friends, or the groups with the
+ * most members.
*
- * @param string $relationship The relationship eg "friends_of"
- * @param bool $inverse_relationship Reverse the normal function of the query to instead say "give me all entities for whome $relationship_guid is a $relationship of" (default: true)
- * @param string $type The type of entity (default: all)
- * @param string $subtype The entity subtype (default: all)
- * @param int $owner_guid The owner of the entities (default: none)
- * @param int $limit
- * @param int $offset
- * @param boolean $count Set to true if you want to count the number of entities instead (default false)
- * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites.
- * @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @param array $options An options array compatible with
+ * elgg_get_entities_from_relationship()
+ * @return ElggEntity[]|mixed int If count, int. If not count, array. false on errors.
+ * @since 1.8.0
*/
-
-function get_entities_by_relationship_count($relationship, $inverse_relationship = true, $type = "", $subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
- global $CONFIG;
-
- $relationship = sanitise_string($relationship);
- $inverse_relationship = (bool)$inverse_relationship;
- $type = sanitise_string($type);
- if ($subtype AND !$subtype = get_subtype_id($type, $subtype)) {
- return false;
- }
- $owner_guid = (int)$owner_guid;
- $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;
- }
-
- //$access = get_access_list();
-
- $where = array();
-
- if ($relationship!="") {
- $where[] = "r.relationship='$relationship'";
- }
-
- if ($inverse_relationship) {
- $on = 'e.guid = r.guid_two';
- } else {
- $on = 'e.guid = r.guid_one';
- }
- if ($type != "") {
- $where[] = "e.type='$type'";
- }
-
- if ($subtype) {
- $where[] = "e.subtype=$subtype";
- }
-
- if ($owner_guid != "") {
- $where[] = "e.container_guid='$owner_guid'";
- }
-
- if ($site_guid > 0) {
- $where[] = "e.site_guid = {$site_guid}";
- }
-
- if ($count) {
- $query = "SELECT count(distinct e.guid) as total ";
- } else {
- $query = "SELECT e.*, count(e.guid) as total ";
- }
-
- $query .= " from {$CONFIG->dbprefix}entity_relationships r JOIN {$CONFIG->dbprefix}entities e on {$on} where ";
-
- if (!empty($where)) {
- foreach ($where as $w) {
- $query .= " $w and ";
- }
- }
- $query .= get_access_sql_suffix("e"); // Add access controls
-
- if (!$count) {
- $query .= " group by e.guid ";
- $query .= " order by total desc limit {$offset}, {$limit}"; // Add order and limit
- return get_data($query, "entity_row_to_elggstar");
- } else {
- if ($count = get_data_row($query)) {
- return $count->total;
- }
- }
-
- return false;
+function elgg_get_entities_from_relationship_count(array $options = array()) {
+ $options['selects'][] = "COUNT(e.guid) as total";
+ $options['group_by'] = 'r.guid_two';
+ $options['order_by'] = 'total desc';
+ return elgg_get_entities_from_relationship($options);
}
/**
- * Displays a human-readable list of entities
+ * Returns a list of entities by relationship count
*
- * @param string $relationship The relationship eg "friends_of"
- * @param bool $inverse_relationship Reverse the normal function of the query to instead say "give me all entities for whome $relationship_guid is a $relationship of" (default: true)
- * @param string $type The type of entity (eg 'object')
- * @param string $subtype The entity subtype
- * @param int $owner_guid The owner (default: all)
- * @param int $limit The number of entities to display on a page
- * @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 Whether to display pagination (default: true)
- * @return string The viewable list of entities
- */
-
-function list_entities_by_relationship_count($relationship, $inverse_relationship = true, $type = "", $subtype = "", $owner_guid = 0, $limit = 10, $fullview = true, $viewtypetoggle = false, $pagination = true) {
- $limit = (int) $limit;
- $offset = (int) get_input('offset');
- $count = get_entities_by_relationship_count($relationship,$inverse_relationship,$type,$subtype,$owner_guid,0,0,true);
- $entities = get_entities_by_relationship_count($relationship,$inverse_relationship,$type,$subtype,$owner_guid,$limit,$offset);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination);
-}
-
-/**
- * Gets the number of entities by a the number of entities related to them in a particular way also constrained by
- * metadata
+ * @see elgg_get_entities_from_relationship_count()
*
- * @param string $relationship The relationship eg "friends_of"
- * @param int $relationship_guid The guid of the entity to use query
- * @param bool $inverse_relationship Reverse the normal function of the query to instead say "give me all entities for whome $relationship_guid is a $relationship of" (default: true)
- * @param String $meta_name The metadata name
- * @param String $meta_value The metadata value
- * @param string $type The type of entity (default: all)
- * @param string $subtype The entity subtype (default: all)
- * @param int $owner_guid The owner of the entities (default: none)
- * @param int $limit
- * @param int $offset
- * @param boolean $count Set to true if you want to count the number of entities instead (default false)
- * @param int $site_guid The site to get entities for. Leave as 0 (default) for the current site; -1 for all sites.
- * @return array|int|false An array of entities, or the number of entities, or false on failure
+ * @param array $options Options array
+ *
+ * @return string
+ * @since 1.8.0
*/
-function get_entities_from_relationships_and_meta($relationship, $relationship_guid, $inverse_relationship = false, $meta_name = "", $meta_value = "", $type = "", $subtype = "", $owner_guid = 0, $limit = 10, $offset = 0, $count = false, $site_guid = 0) {
- elgg_deprecated_notice('get_entities_from_relationship_and_meta() was deprecated by elgg_get_entities_from_relationship()!', 1.7);
-
- $options = array();
-
- $options['relationship'] = $relationship;
- $options['relationship_guid'] = $relationship_guid;
- $options['inverse_relationship'] = $inverse_relationship;
-
- if ($meta_value) {
- $options['values'] = $meta_value;
- }
-
- if ($entity_type) {
- $options['types'] = $entity_type;
- }
-
- if ($type) {
- $options['types'] = $type;
- }
-
- if (subtype) {
- $options['subtypes'] = $subtype;
- }
-
- if ($owner_guid) {
- $options['owner_guid'] = $owner_guid;
- }
-
- if ($limit) {
- $options['limit'] = $limit;
- }
-
- if ($offset) {
- $options['offset'] = $offset;
- }
-
- if ($order_by) {
- $options['order_by'];
- }
-
- if ($site_guid) {
- $options['site_guid'];
- }
-
- if ($count) {
- $options['count'] = $count;
- }
-
- return elgg_get_entities_from_relationship($options);
+function elgg_list_entities_from_relationship_count($options) {
+ return elgg_list_entities($options, 'elgg_get_entities_from_relationship_count');
}
/**
* Sets the URL handler for a particular relationship type
*
- * @param string $function_name The function to register
* @param string $relationship_type The relationship type.
- * @return true|false Depending on success
+ * @param string $function_name The function to register
+ *
+ * @return bool Depending on success
*/
-function register_relationship_url_handler($function_name, $relationship_type = "all") {
+function elgg_register_relationship_url_handler($relationship_type, $function_name) {
global $CONFIG;
- if (!is_callable($function_name)) {
+ if (!is_callable($function_name, true)) {
return false;
}
@@ -895,8 +432,9 @@ function register_relationship_url_handler($function_name, $relationship_type =
/**
* Get the url for a given relationship.
*
- * @param unknown_type $id
- * @return unknown
+ * @param int $id Relationship ID
+ *
+ * @return string
*/
function get_relationship_url($id) {
global $CONFIG;
@@ -920,13 +458,13 @@ function get_relationship_url($id) {
}
if (is_callable($function)) {
- $url = $function($relationship);
+ $url = call_user_func($function, $relationship);
}
if ($url == "") {
$nameid = $relationship->id;
- $url = $CONFIG->wwwroot . "export/$view/$guid/relationship/$nameid/";
+ $url = elgg_get_site_url() . "export/$view/$guid/relationship/$nameid/";
}
return $url;
@@ -936,16 +474,19 @@ function get_relationship_url($id) {
}
/**** HELPER FUNCTIONS FOR RELATIONSHIPS OF TYPE 'ATTACHED' ****/
+// @todo what is this?
/**
* Function to determine if the object trying to attach to other, has already done so
+ *
* @param int $guid_one This is the target object
* @param int $guid_two This is the object trying to attach to $guid_one
- * @return true | false
- **/
-
-function already_attached($guid_one, $guid_two){
- if ($attached = check_entity_relationship($guid_one, "attached", $guid_two)){
+ *
+ * @return bool
+ * @access private
+ */
+function already_attached($guid_one, $guid_two) {
+ if ($attached = check_entity_relationship($guid_one, "attached", $guid_two)) {
return true;
} else {
return false;
@@ -954,37 +495,56 @@ function already_attached($guid_one, $guid_two){
/**
* Function to get all objects attached to a particular object
- * @param int $guid
- * @param string $type - the type of object to return e.g. 'file', 'friend_of' etc
- * @return an array of objects
-**/
-
-function get_attachments($guid, $type=""){
- $attached = elgg_get_entities_from_relationship(array('relationship' => 'attached', 'relationship_guid' => $guid, 'inverse_relationship' => $inverse_relationship = false, 'types' => $type, 'subtypes' => '', 'owner_guid' => 0, 'order_by' => 'time_created desc', 'limit' => 10, 'offset' => 0, 'count' => false, 'site_guid' => 0));
+ *
+ * @param int $guid Entity GUID
+ * @param string $type The type of object to return e.g. 'file', 'friend_of' etc
+ *
+ * @return ElggEntity[]
+ * @access private
+ */
+function get_attachments($guid, $type = "") {
+ $options = array(
+ 'relationship' => 'attached',
+ 'relationship_guid' => $guid,
+ 'inverse_relationship' => false,
+ 'type' => $type,
+ 'subtypes' => '',
+ 'owner_guid' => 0,
+ 'order_by' => 'time_created desc',
+ 'limit' => 10,
+ 'offset' => 0,
+ 'count' => false,
+ 'site_guid' => 0
+ );
+ $attached = elgg_get_entities_from_relationship($options);
return $attached;
}
/**
* Function to remove a particular attachment between two objects
+ *
* @param int $guid_one This is the target object
* @param int $guid_two This is the object to remove from $guid_one
- * @return a view
-**/
-
-function remove_attachment($guid_one, $guid_two){
- if(already_attached($guid_one, $guid_two)) {
+ *
+ * @return void
+ * @access private
+ */
+function remove_attachment($guid_one, $guid_two) {
+ if (already_attached($guid_one, $guid_two)) {
remove_entity_relationship($guid_one, "attached", $guid_two);
}
}
/**
* Function to start the process of attaching one object to another
+ *
* @param int $guid_one This is the target object
* @param int $guid_two This is the object trying to attach to $guid_one
- * @return a view
-**/
-
-function make_attachment($guid_one, $guid_two){
+ *
+ * @return true|void
+ * @access private
+ */
+function make_attachment($guid_one, $guid_two) {
if (!(already_attached($guid_one, $guid_two))) {
if (add_entity_relationship($guid_one, "attached", $guid_two)) {
return true;
@@ -993,7 +553,15 @@ function make_attachment($guid_one, $guid_two){
}
/**
- * Handler called by trigger_plugin_hook on the "import" event.
+ * Handler called by trigger_plugin_hook on the "import" event.
+ *
+ * @param string $hook import
+ * @param string $entity_type all
+ * @param mixed $returnvalue Value from previous hook
+ * @param mixed $params Array of params
+ *
+ * @return mixed
+ * @access private
*/
function import_relationship_plugin_hook($hook, $entity_type, $returnvalue, $params) {
$element = $params['element'];
@@ -1003,17 +571,24 @@ function import_relationship_plugin_hook($hook, $entity_type, $returnvalue, $par
if ($element instanceof ODDRelationship) {
$tmp = new ElggRelationship();
$tmp->import($element);
-
- return $tmp;
}
+ return $tmp;
}
/**
- * Handler called by trigger_plugin_hook on the "export" event.
+ * Handler called by trigger_plugin_hook on the "export" event.
+ *
+ * @param string $hook export
+ * @param string $entity_type all
+ * @param mixed $returnvalue Previous hook return value
+ * @param array $params Parameters
+ *
+ * @elgg_event_handler export all
+ * @return mixed
+ * @throws InvalidParameterException
+ * @access private
*/
function export_relationship_plugin_hook($hook, $entity_type, $returnvalue, $params) {
- global $CONFIG;
-
// Sanity check values
if ((!is_array($params)) && (!isset($params['guid']))) {
throw new InvalidParameterException(elgg_echo('InvalidParameterException:GUIDNotForExport'));
@@ -1037,36 +612,32 @@ function export_relationship_plugin_hook($hook, $entity_type, $returnvalue, $par
}
/**
- * An event listener which will notify users based on certain events.
+ * Notify user that someone has friended them
+ *
+ * @param string $event Event name
+ * @param string $type Object type
+ * @param mixed $object Object
*
- * @param unknown_type $event
- * @param unknown_type $object_type
- * @param unknown_type $object
+ * @return bool
+ * @access private
*/
-function relationship_notification_hook($event, $object_type, $object) {
- global $CONFIG;
-
- if (
- ($object instanceof ElggRelationship) &&
- ($event == 'create') &&
- ($object_type == 'friend')
- )
- {
- $user_one = get_entity($object->guid_one);
- $user_two = get_entity($object->guid_two);
-
- // Notify target user
- return notify_user($object->guid_two, $object->guid_one, sprintf(elgg_echo('friend:newfriend:subject'), $user_one->name),
- sprintf(elgg_echo("friend:newfriend:body"), $user_one->name, $user_one->getURL())
- );
- }
+function relationship_notification_hook($event, $type, $object) {
+ /* @var ElggRelationship $object */
+ $user_one = get_entity($object->guid_one);
+ /* @var ElggUser $user_one */
+
+ return notify_user($object->guid_two,
+ $object->guid_one,
+ elgg_echo('friend:newfriend:subject', array($user_one->name)),
+ elgg_echo("friend:newfriend:body", array($user_one->name, $user_one->getURL()))
+ );
}
-/** Register the import hook */
-register_plugin_hook("import", "all", "import_relationship_plugin_hook", 3);
+// Register the import hook
+elgg_register_plugin_hook_handler("import", "all", "import_relationship_plugin_hook", 3);
-/** Register the hook, ensuring entities are serialised first */
-register_plugin_hook("export", "all", "export_relationship_plugin_hook", 3);
+// Register the hook, ensuring entities are serialised first
+elgg_register_plugin_hook_handler("export", "all", "export_relationship_plugin_hook", 3);
-/** Register event to listen to some events **/
-register_elgg_event_handler('create','friend','relationship_notification_hook');
+// Register event to listen to some events
+elgg_register_event_handler('create', 'friend', 'relationship_notification_hook');
diff --git a/engine/lib/river.php b/engine/lib/river.php
index 74e7322e8..e92040eb7 100644
--- a/engine/lib/river.php
+++ b/engine/lib/river.php
@@ -1,27 +1,31 @@
<?php
/**
- * Elgg river 2.0.
- * Functions for listening for and generating the river separately from the system log.
+ * Elgg river.
+ * Activity stream functions.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage SocialModel.River
*/
/**
* Adds an item to the river.
*
- * @param string $view The view that will handle the river item (must exist)
- * @param string $action_type An arbitrary one-word string to define the action (eg 'comment', 'create')
- * @param int $subject_guid The GUID of the entity doing the action
- * @param int $object_guid The GUID of the entity being acted upon
- * @param int $access_id The access ID of the river item (default: same as the object)
- * @param int $posted The UNIX epoch timestamp of the river item (default: now)
- * @return true|false Depending on success
+ * @param string $view The view that will handle the river item (must exist)
+ * @param string $action_type An arbitrary string to define the action (eg 'comment', 'create')
+ * @param int $subject_guid The GUID of the entity doing the action
+ * @param int $object_guid The GUID of the entity being acted upon
+ * @param int $access_id The access ID of the river item (default: same as the object)
+ * @param int $posted The UNIX epoch timestamp of the river item (default: now)
+ * @param int $annotation_id The annotation ID associated with this river entry
+ *
+ * @return int/bool River ID or false on failure
*/
-function add_to_river($view,$action_type,$subject_guid,$object_guid,$access_id = "",$posted = 0, $annotation_id = 0) {
- // use default viewtype for when called from REST api
+function add_to_river($view, $action_type, $subject_guid, $object_guid, $access_id = "",
+$posted = 0, $annotation_id = 0) {
+
+ global $CONFIG;
+
+ // use default viewtype for when called from web services api
if (!elgg_view_exists($view, 'default')) {
return false;
}
@@ -40,660 +44,660 @@ function add_to_river($view,$action_type,$subject_guid,$object_guid,$access_id =
if ($access_id === "") {
$access_id = $object->access_id;
}
- $annotation_id = (int)$annotation_id;
$type = $object->getType();
$subtype = $object->getSubtype();
- $action_type = sanitise_string($action_type);
- // Load config
- global $CONFIG;
+ $view = sanitise_string($view);
+ $action_type = sanitise_string($action_type);
+ $subject_guid = sanitise_int($subject_guid);
+ $object_guid = sanitise_int($object_guid);
+ $access_id = sanitise_int($access_id);
+ $posted = sanitise_int($posted);
+ $annotation_id = sanitise_int($annotation_id);
+
+ $values = array(
+ 'type' => $type,
+ 'subtype' => $subtype,
+ 'action_type' => $action_type,
+ 'access_id' => $access_id,
+ 'view' => $view,
+ 'subject_guid' => $subject_guid,
+ 'object_guid' => $object_guid,
+ 'annotation_id' => $annotation_id,
+ 'posted' => $posted,
+ );
+
+ // return false to stop insert
+ $values = elgg_trigger_plugin_hook('creating', 'river', null, $values);
+ if ($values == false) {
+ // inserting did not fail - it was just prevented
+ return true;
+ }
+
+ extract($values);
// Attempt to save river item; return success status
- $insert_data = insert_data("insert into {$CONFIG->dbprefix}river " .
- " set type = '{$type}', " .
- " subtype = '{$subtype}', " .
- " action_type = '{$action_type}', " .
- " access_id = {$access_id}, " .
- " view = '{$view}', " .
- " subject_guid = {$subject_guid}, " .
- " object_guid = {$object_guid}, " .
- " annotation_id = {$annotation_id}, " .
- " posted = {$posted} ");
-
- //update the entities which had the action carried out on it
- if($insert_data){
+ $id = insert_data("insert into {$CONFIG->dbprefix}river " .
+ " set type = '$type', " .
+ " subtype = '$subtype', " .
+ " action_type = '$action_type', " .
+ " access_id = $access_id, " .
+ " view = '$view', " .
+ " subject_guid = $subject_guid, " .
+ " object_guid = $object_guid, " .
+ " annotation_id = $annotation_id, " .
+ " posted = $posted");
+
+ // update the entities which had the action carried out on it
+ // @todo shouldn't this be down elsewhere? Like when an annotation is saved?
+ if ($id) {
update_entity_last_action($object_guid, $posted);
- return $insert_data;
+
+ $river_items = elgg_get_river(array('id' => $id));
+ if ($river_items) {
+ elgg_trigger_event('created', 'river', $river_items[0]);
+ }
+ return $id;
+ } else {
+ return false;
}
}
/**
- * Removes all items relating to a particular acting entity from the river
+ * Delete river items
+ *
+ * @warning not checking access (should we?)
*
- * @param int $subject_guid The GUID of the entity
- * @return true|false Depending on success
+ * @param array $options Parameters:
+ * ids => INT|ARR River item id(s)
+ * subject_guids => INT|ARR Subject guid(s)
+ * object_guids => INT|ARR Object guid(s)
+ * annotation_ids => INT|ARR The identifier of the annotation(s)
+ * action_types => STR|ARR The river action type(s) identifier
+ * views => STR|ARR River view(s)
+ *
+ * types => STR|ARR Entity type string(s)
+ * subtypes => STR|ARR Entity subtype string(s)
+ * type_subtype_pairs => ARR Array of type => subtype pairs where subtype
+ * can be an array of subtype strings
+ *
+ * posted_time_lower => INT The lower bound on the time posted
+ * posted_time_upper => INT The upper bound on the time posted
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function remove_from_river_by_subject($subject_guid) {
- // Sanitise
- $subject_guid = (int) $subject_guid;
-
- // Load config
+function elgg_delete_river(array $options = array()) {
global $CONFIG;
- // Remove
- return delete_data("delete from {$CONFIG->dbprefix}river where subject_guid = {$subject_guid}");
-}
+ $defaults = array(
+ 'ids' => ELGG_ENTITIES_ANY_VALUE,
-/**
- * Removes all items relating to a particular entity being acted upon from the river
- *
- * @param int $object_guid The GUID of the entity
- * @return true|false Depending on success
- */
-function remove_from_river_by_object($object_guid) {
- // Sanitise
- $object_guid = (int) $object_guid;
+ 'subject_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'object_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE,
- // Load config
- global $CONFIG;
+ 'views' => ELGG_ENTITIES_ANY_VALUE,
+ 'action_types' => ELGG_ENTITIES_ANY_VALUE,
- // Remove
- return delete_data("delete from {$CONFIG->dbprefix}river where object_guid = {$object_guid}");
-}
+ 'types' => ELGG_ENTITIES_ANY_VALUE,
+ 'subtypes' => ELGG_ENTITIES_ANY_VALUE,
+ 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
-/**
- * Removes all items relating to a particular annotation being acted upon from the river
- *
- * @param int annotation_id The ID of the annotation
- * @return true|false Depending on success
- */
-function remove_from_river_by_annotation($annotation_id) {
- // Sanitise
- $annotation_id = (int) $annotation_id;
+ 'posted_time_lower' => ELGG_ENTITIES_ANY_VALUE,
+ 'posted_time_upper' => ELGG_ENTITIES_ANY_VALUE,
- // Load config
- global $CONFIG;
+ 'wheres' => array(),
+ 'joins' => array(),
- // Remove
- return delete_data("delete from {$CONFIG->dbprefix}river where annotation_id = {$annotation_id}");
+ );
+
+ $options = array_merge($defaults, $options);
+
+ $singulars = array('id', 'subject_guid', 'object_guid', 'annotation_id', 'action_type', 'view', 'type', 'subtype');
+ $options = elgg_normalise_plural_options_array($options, $singulars);
+
+ $wheres = $options['wheres'];
+
+ $wheres[] = elgg_get_guid_based_where_sql('rv.id', $options['ids']);
+ $wheres[] = elgg_get_guid_based_where_sql('rv.subject_guid', $options['subject_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('rv.object_guid', $options['object_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('rv.annotation_id', $options['annotation_ids']);
+ $wheres[] = elgg_river_get_action_where_sql($options['action_types']);
+ $wheres[] = elgg_river_get_view_where_sql($options['views']);
+ $wheres[] = elgg_get_river_type_subtype_where_sql('rv', $options['types'],
+ $options['subtypes'], $options['type_subtype_pairs']);
+
+ if ($options['posted_time_lower'] && is_int($options['posted_time_lower'])) {
+ $wheres[] = "rv.posted >= {$options['posted_time_lower']}";
+ }
+
+ if ($options['posted_time_upper'] && is_int($options['posted_time_upper'])) {
+ $wheres[] = "rv.posted <= {$options['posted_time_upper']}";
+ }
+
+ // see if any functions failed
+ // remove empty strings on successful functions
+ foreach ($wheres as $i => $where) {
+ if ($where === FALSE) {
+ return FALSE;
+ } elseif (empty($where)) {
+ unset($wheres[$i]);
+ }
+ }
+
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
+
+ $query = "DELETE rv.* FROM {$CONFIG->dbprefix}river rv ";
+
+ // remove identical join clauses
+ $joins = array_unique($options['joins']);
+
+ // add joins
+ foreach ($joins as $j) {
+ $query .= " $j ";
+ }
+
+ // add wheres
+ $query .= ' WHERE ';
+
+ foreach ($wheres as $w) {
+ $query .= " $w AND ";
+ }
+ $query .= "1=1";
+
+ return delete_data($query);
}
/**
- * Removes a single river entry
+ * Get river items
+ *
+ * @note If using types and subtypes in a query, they are joined with an AND.
+ *
+ * @param array $options Parameters:
+ * ids => INT|ARR River item id(s)
+ * subject_guids => INT|ARR Subject guid(s)
+ * object_guids => INT|ARR Object guid(s)
+ * annotation_ids => INT|ARR The identifier of the annotation(s)
+ * action_types => STR|ARR The river action type(s) identifier
+ * posted_time_lower => INT The lower bound on the time posted
+ * posted_time_upper => INT The upper bound on the time posted
+ *
+ * types => STR|ARR Entity type string(s)
+ * subtypes => STR|ARR Entity subtype string(s)
+ * type_subtype_pairs => ARR Array of type => subtype pairs where subtype
+ * can be an array of subtype strings
+ *
+ * relationship => STR Relationship identifier
+ * relationship_guid => INT|ARR Entity guid(s)
+ * inverse_relationship => BOOL Subject or object of the relationship (false)
+ *
+ * limit => INT Number to show per page (20)
+ * offset => INT Offset in list (0)
+ * count => BOOL Count the river items? (false)
+ * order_by => STR Order by clause (rv.posted desc)
+ * group_by => STR Group by clause
*
- * @param int $id The ID of the river entry
- * @return true|false Depending on success
- * @since 1.7.2
+ * @return array|int
+ * @since 1.8.0
*/
-function remove_from_river_by_id($id) {
+function elgg_get_river(array $options = array()) {
global $CONFIG;
- // Sanitise
- $id = (int) $id;
+ $defaults = array(
+ 'ids' => ELGG_ENTITIES_ANY_VALUE,
- return delete_data("delete from {$CONFIG->dbprefix}river where id = {$id}");
-}
+ 'subject_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'object_guids' => ELGG_ENTITIES_ANY_VALUE,
+ 'annotation_ids' => ELGG_ENTITIES_ANY_VALUE,
+ 'action_types' => ELGG_ENTITIES_ANY_VALUE,
+ 'relationship' => NULL,
+ 'relationship_guid' => NULL,
+ 'inverse_relationship' => FALSE,
-/**
- * Sets the access ID on river items for a particular object
- *
- * @param int $object_guid The GUID of the entity
- * @param int $access_id The access ID
- * @return true|false Depending on success
- */
-function update_river_access_by_object($object_guid, $access_id) {
- // Sanitise
- $object_guid = (int) $object_guid;
- $access_id = (int) $access_id;
+ 'types' => ELGG_ENTITIES_ANY_VALUE,
+ 'subtypes' => ELGG_ENTITIES_ANY_VALUE,
+ 'type_subtype_pairs' => ELGG_ENTITIES_ANY_VALUE,
- // Load config
- global $CONFIG;
+ 'posted_time_lower' => ELGG_ENTITIES_ANY_VALUE,
+ 'posted_time_upper' => ELGG_ENTITIES_ANY_VALUE,
- // Remove
- return update_data("update {$CONFIG->dbprefix}river set access_id = {$access_id} where object_guid = {$object_guid}");
-}
+ 'limit' => 20,
+ 'offset' => 0,
+ 'count' => FALSE,
-/**
- * Retrieves items from the river. All parameters are optional.
- *
- * @param int|array $subject_guid Acting entity to restrict to. Default: all
- * @param int|array $object_guid Entity being acted on to restrict to. Default: all
- * @param string $subject_relationship If set to a relationship type, this will use
- * $subject_guid as the starting point and set the subjects to be all users this
- * entity has this relationship with (eg 'friend'). Default: blank
- * @param string $type The type of entity to restrict to. Default: all
- * @param string $subtype The subtype of entity to restrict to. Default: all
- * @param string $action_type The type of river action to restrict to. Default: all
- * @param int $limit The number of items to retrieve. Default: 20
- * @param int $offset The page offset. Default: 0
- * @param int $posted_min The minimum time period to look at. Default: none
- * @param int $posted_max The maximum time period to look at. Default: none
- * @return array|false Depending on success
- */
-function get_river_items($subject_guid = 0, $object_guid = 0, $subject_relationship = '', $type = '',
- $subtype = '', $action_type = '', $limit = 20, $offset = 0, $posted_min = 0, $posted_max = 0) {
+ 'order_by' => 'rv.posted desc',
+ 'group_by' => ELGG_ENTITIES_ANY_VALUE,
- // Get config
- global $CONFIG;
+ 'wheres' => array(),
+ 'joins' => array(),
+ );
- // Sanitise variables
- if (!is_array($subject_guid)) {
- $subject_guid = (int) $subject_guid;
- } else {
- foreach($subject_guid as $key => $temp) {
- $subject_guid[$key] = (int) $temp;
- }
- }
- if (!is_array($object_guid)) {
- $object_guid = (int) $object_guid;
- } else {
- foreach($object_guid as $key => $temp) {
- $object_guid[$key] = (int) $temp;
- }
- }
- if (!empty($type)) {
- $type = sanitise_string($type);
- }
- if (!empty($subtype)) {
- $subtype = sanitise_string($subtype);
+ $options = array_merge($defaults, $options);
+
+ $singulars = array('id', 'subject_guid', 'object_guid', 'annotation_id', 'action_type', 'type', 'subtype');
+ $options = elgg_normalise_plural_options_array($options, $singulars);
+
+ $wheres = $options['wheres'];
+
+ $wheres[] = elgg_get_guid_based_where_sql('rv.id', $options['ids']);
+ $wheres[] = elgg_get_guid_based_where_sql('rv.subject_guid', $options['subject_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('rv.object_guid', $options['object_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('rv.annotation_id', $options['annotation_ids']);
+ $wheres[] = elgg_river_get_action_where_sql($options['action_types']);
+ $wheres[] = elgg_get_river_type_subtype_where_sql('rv', $options['types'],
+ $options['subtypes'], $options['type_subtype_pairs']);
+
+ if ($options['posted_time_lower'] && is_int($options['posted_time_lower'])) {
+ $wheres[] = "rv.posted >= {$options['posted_time_lower']}";
}
- if (!empty($action_type)) {
- $action_type = sanitise_string($action_type);
+
+ if ($options['posted_time_upper'] && is_int($options['posted_time_upper'])) {
+ $wheres[] = "rv.posted <= {$options['posted_time_upper']}";
}
- $limit = (int) $limit;
- $offset = (int) $offset;
- $posted_min = (int) $posted_min;
- $posted_max = (int) $posted_max;
- // Construct 'where' clauses for the river
- $where = array();
- // river table does not have columns expected by get_access_sql_suffix so we modify its output
- $where[] = str_replace("and enabled='yes'",'',str_replace('owner_guid','subject_guid',get_access_sql_suffix()));
+ $joins = $options['joins'];
- if (empty($subject_relationship)) {
- if (!empty($subject_guid)) {
- if (!is_array($subject_guid)) {
- $where[] = " subject_guid = {$subject_guid} ";
- } else {
- $where[] = " subject_guid in (" . implode(',',$subject_guid) . ") ";
- }
- }
- } else {
- if (!is_array($subject_guid)) {
- if ($entities = elgg_get_entities_from_relationship(array(
- 'relationship' => $subject_relationship,
- 'relationship_guid' => $subject_guid,
- 'limit' => 9999))
- ) {
- $guids = array();
- foreach($entities as $entity) {
- $guids[] = (int) $entity->guid;
- }
- // $guids[] = $subject_guid;
- $where[] = " subject_guid in (" . implode(',',$guids) . ") ";
- } else {
- return array();
- }
+ if ($options['relationship_guid']) {
+ $clauses = elgg_get_entity_relationship_where_sql(
+ 'rv.subject_guid',
+ $options['relationship'],
+ $options['relationship_guid'],
+ $options['inverse_relationship']);
+ if ($clauses) {
+ $wheres = array_merge($wheres, $clauses['wheres']);
+ $joins = array_merge($joins, $clauses['joins']);
}
}
- if (!empty($object_guid))
- if (!is_array($object_guid)) {
- $where[] = " object_guid = {$object_guid} ";
- } else {
- $where[] = " object_guid in (" . implode(',',$object_guid) . ") ";
+
+ // see if any functions failed
+ // remove empty strings on successful functions
+ foreach ($wheres as $i => $where) {
+ if ($where === FALSE) {
+ return FALSE;
+ } elseif (empty($where)) {
+ unset($wheres[$i]);
}
- if (!empty($type)) {
- $where[] = " type = '{$type}' ";
- }
- if (!empty($subtype)) {
- $where[] = " subtype = '{$subtype}' ";
}
- if (!empty($action_type)) {
- $where[] = " action_type = '{$action_type}' ";
+
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
+
+ if (!$options['count']) {
+ $query = "SELECT DISTINCT rv.* FROM {$CONFIG->dbprefix}river rv ";
+ } else {
+ $query = "SELECT count(DISTINCT rv.id) as total FROM {$CONFIG->dbprefix}river rv ";
}
- if (!empty($posted_min)) {
- $where[] = " posted > {$posted_min} ";
+
+ // add joins
+ foreach ($joins as $j) {
+ $query .= " $j ";
}
- if (!empty($posted_max)) {
- $where[] = " posted < {$posted_max} ";
+
+ // add wheres
+ $query .= ' WHERE ';
+
+ foreach ($wheres as $w) {
+ $query .= " $w AND ";
}
- $whereclause = implode(' and ', $where);
+ $query .= elgg_river_get_access_sql();
+
+ if (!$options['count']) {
+ $options['group_by'] = sanitise_string($options['group_by']);
+ if ($options['group_by']) {
+ $query .= " GROUP BY {$options['group_by']}";
+ }
+
+ $options['order_by'] = sanitise_string($options['order_by']);
+ $query .= " ORDER BY {$options['order_by']}";
- // Construct main SQL
- $sql = "select id,type,subtype,action_type,access_id,view,subject_guid,object_guid,annotation_id,posted" .
- " from {$CONFIG->dbprefix}river where {$whereclause} order by posted desc limit {$offset},{$limit}";
+ if ($options['limit']) {
+ $limit = sanitise_int($options['limit']);
+ $offset = sanitise_int($options['offset'], false);
+ $query .= " LIMIT $offset, $limit";
+ }
+
+ $river_items = get_data($query, 'elgg_row_to_elgg_river_item');
+ _elgg_prefetch_river_entities($river_items);
- // Get data
- return get_data($sql);
+ return $river_items;
+ } else {
+ $total = get_data_row($query);
+ return (int)$total->total;
+ }
}
/**
- * Retrieves items from the river. All parameters are optional.
+ * Prefetch entities that will be displayed in the river.
*
- * @param int|array $subject_guid Acting entity to restrict to. Default: all
- * @param int|array $object_guid Entity being acted on to restrict to. Default: all
- * @param string $subject_relationship If set to a relationship type, this will use
- * $subject_guid as the starting point and set the subjects to be all users this
- * entity has this relationship with (eg 'friend'). Default: blank
- * @param string $type The type of entity to restrict to. Default: all
- * @param string $subtype The subtype of entity to restrict to. Default: all
- * @param string $action_type The type of river action to restrict to. Default: all
- * @param int $limit The number of items to retrieve. Default: 20
- * @param int $offset The page offset. Default: 0
- * @param int $posted_min The minimum time period to look at. Default: none
- * @param int $posted_max The maximum time period to look at. Default: none
- * @return array|false Depending on success
+ * @param ElggRiverItem[] $river_items
+ * @access private
*/
-function elgg_get_river_items($subject_guid = 0, $object_guid = 0, $subject_relationship = '', $type = '',
- $subtype = '', $action_type = '', $limit = 10, $offset = 0, $posted_min = 0, $posted_max = 0) {
-
- // Get config
- global $CONFIG;
-
- // Sanitise variables
- if (!is_array($subject_guid)) {
- $subject_guid = (int) $subject_guid;
- } else {
- foreach($subject_guid as $key => $temp) {
- $subject_guid[$key] = (int) $temp;
+function _elgg_prefetch_river_entities(array $river_items) {
+ // prefetch objects and subjects
+ $guids = array();
+ foreach ($river_items as $item) {
+ if ($item->subject_guid && !_elgg_retrieve_cached_entity($item->subject_guid)) {
+ $guids[$item->subject_guid] = true;
}
- }
- if (!is_array($object_guid)) {
- $object_guid = (int) $object_guid;
- } else {
- foreach($object_guid as $key => $temp) {
- $object_guid[$key] = (int) $temp;
+ if ($item->object_guid && !_elgg_retrieve_cached_entity($item->object_guid)) {
+ $guids[$item->object_guid] = true;
}
}
- if (!empty($type)) {
- $type = sanitise_string($type);
- }
- if (!empty($subtype)) {
- $subtype = sanitise_string($subtype);
- }
- if (!empty($action_type)) {
- $action_type = sanitise_string($action_type);
+ if ($guids) {
+ // avoid creating oversized query
+ // @todo how to better handle this?
+ $guids = array_slice($guids, 0, 300, true);
+ // return value unneeded, just priming cache
+ elgg_get_entities(array(
+ 'guids' => array_keys($guids),
+ 'limit' => 0,
+ ));
}
- $limit = (int) $limit;
- $offset = (int) $offset;
- $posted_min = (int) $posted_min;
- $posted_max = (int) $posted_max;
- // Construct 'where' clauses for the river
- $where = array();
- // river table does not have columns expected by get_access_sql_suffix so we modify its output
- $where[] = str_replace("and enabled='yes'",'',str_replace('owner_guid','subject_guid',get_access_sql_suffix_new('er','e')));
-
- if (empty($subject_relationship)) {
- if (!empty($subject_guid)) {
- if (!is_array($subject_guid)) {
- $where[] = " subject_guid = {$subject_guid} ";
- } else {
- $where[] = " subject_guid in (" . implode(',',$subject_guid) . ") ";
- }
+ // prefetch object containers
+ $guids = array();
+ foreach ($river_items as $item) {
+ $object = $item->getObjectEntity();
+ if ($object->container_guid && !_elgg_retrieve_cached_entity($object->container_guid)) {
+ $guids[$object->container_guid] = true;
}
- } else {
- if (!is_array($subject_guid)) {
- $entities = elgg_get_entities_from_relationship(array(
- 'relationship' => $subject_relationship,
- 'relationship_guid' => $subject_guid,
- 'limit' => 9999,
- ));
- if (is_array($entities) && !empty($entities)) {
- $guids = array();
- foreach($entities as $entity) {
- $guids[] = (int) $entity->guid;
- }
- // $guids[] = $subject_guid;
- $where[] = " subject_guid in (" . implode(',',$guids) . ") ";
- } else {
- return array();
- }
- }
- }
- if (!empty($object_guid))
- if (!is_array($object_guid)) {
- $where[] = " object_guid = {$object_guid} ";
- } else {
- $where[] = " object_guid in (" . implode(',',$object_guid) . ") ";
- }
- if (!empty($type)) {
- $where[] = " er.type = '{$type}' ";
- }
- if (!empty($subtype)) {
- $where[] = " er.subtype = '{$subtype}' ";
- }
- if (!empty($action_type)) {
- $where[] = " action_type = '{$action_type}' ";
- }
- if (!empty($posted_min)) {
- $where[] = " posted > {$posted_min} ";
}
- if (!empty($posted_max)) {
- $where[] = " posted < {$posted_max} ";
+ if ($guids) {
+ $guids = array_slice($guids, 0, 300, true);
+ elgg_get_entities(array(
+ 'guids' => array_keys($guids),
+ 'limit' => 0,
+ ));
}
-
- $whereclause = implode(' and ', $where);
-
- // Construct main SQL
- $sql = "select er.*" .
- " from {$CONFIG->dbprefix}river er, {$CONFIG->dbprefix}entities e " .
- " where {$whereclause} AND er.object_guid = e.guid GROUP BY object_guid " .
- " ORDER BY e.last_action desc LIMIT {$offset},{$limit}";
-
- // Get data
- return get_data($sql);
}
/**
- * Returns a human-readable representation of a river item
+ * List river items
*
- * @see get_river_items
+ * @param array $options Any options from elgg_get_river() plus:
+ * pagination => BOOL Display pagination links (true)
*
- * @param stdClass $item A river item object as returned from get_river_items
- * @return string|false Depending on success
+ * @return string
+ * @since 1.8.0
*/
-function elgg_view_river_item($item) {
- if (isset($item->view)) {
- $object = get_entity($item->object_guid);
- $subject = get_entity($item->subject_guid);
- if (!$object || !$subject) {
- // probably means an entity is disabled
- return false;
- } else {
- if (elgg_view_exists($item->view)) {
- $body = elgg_view($item->view,array(
- 'item' => $item
- ));
- }
- }
- return elgg_view('river/item/wrapper',array(
- 'item' => $item,
- 'body' => $body
- ));
- }
- return false;
+function elgg_list_river(array $options = array()) {
+ global $autofeed;
+ $autofeed = true;
+
+ $defaults = array(
+ 'offset' => (int) max(get_input('offset', 0), 0),
+ 'limit' => (int) max(get_input('limit', 20), 0),
+ 'pagination' => TRUE,
+ 'list_class' => 'elgg-list-river elgg-river', // @todo remove elgg-river in Elgg 1.9
+ );
+
+ $options = array_merge($defaults, $options);
+
+ if (!$options["limit"] && !$options["offset"]) {
+ // no need for pagination if listing is unlimited
+ $options["pagination"] = false;
+ }
+
+ $options['count'] = TRUE;
+ $count = elgg_get_river($options);
+
+ $options['count'] = FALSE;
+ $items = elgg_get_river($options);
+
+ $options['count'] = $count;
+ $options['items'] = $items;
+
+ return elgg_view('page/components/list', $options);
}
/**
- * Returns a human-readable version of the river.
+ * Convert a database row to a new ElggRiverItem
*
- * @param int|array $subject_guid Acting entity to restrict to. Default: all
- * @param int|array $object_guid Entity being acted on to restrict to. Default: all
- * @param string $subject_relationship If set to a relationship type, this will use
- * $subject_guid as the starting point and set the subjects to be all users this
- * entity has this relationship with (eg 'friend'). Default: blank
- * @param string $type The type of entity to restrict to. Default: all
- * @param string $subtype The subtype of entity to restrict to. Default: all
- * @param string $action_type The type of river action to restrict to. Default: all
- * @param int $limit The number of items to retrieve. Default: 20
- * @param int $posted_min The minimum time period to look at. Default: none
- * @param int $posted_max The maximum time period to look at. Default: none
- * @return string Human-readable river.
+ * @param stdClass $row Database row from the river table
+ *
+ * @return ElggRiverItem
+ * @since 1.8.0
+ * @access private
*/
-function elgg_view_river_items($subject_guid = 0, $object_guid = 0, $subject_relationship = '',
- $type = '', $subtype = '', $action_type = '', $limit = 20, $posted_min = 0, $posted_max = 0, $pagination = true, $chronological = false) {
-
- // Get input from outside world and sanitise it
- $offset = (int) get_input('offset',0);
-
- // Get the correct function
- if($chronological == true){
- $riveritems = get_river_items($subject_guid,$object_guid,$subject_relationship,$type,$subtype,$action_type,($limit + 1),$offset,$posted_min,$posted_max);
- }else{
- $riveritems = elgg_get_river_items($subject_guid,$object_guid,$subject_relationship,$type,$subtype,$action_type,($limit + 1),$offset,$posted_min,$posted_max);
- }
-
- // Get river items, if they exist
- if ($riveritems) {
-
- return elgg_view('river/item/list',array(
- 'limit' => $limit,
- 'offset' => $offset,
- 'items' => $riveritems,
- 'pagination' => $pagination
- ));
-
+function elgg_row_to_elgg_river_item($row) {
+ if (!($row instanceof stdClass)) {
+ return NULL;
}
- return '';
+ return new ElggRiverItem($row);
}
/**
- * This function has been added here until we decide if it is going to roll into core or not
- * Add access restriction sql code to a given query.
- * Note that if this code is executed in privileged mode it will return blank.
- * @TODO: DELETE once Query classes are fully integrated
+ * Get the river's access where clause
*
- * @param string $table_prefix Optional table. prefix for the access code.
- * @param int $owner
+ * @return string
+ * @since 1.8.0
+ * @access private
*/
-function get_access_sql_suffix_new($table_prefix_one = '', $table_prefix_two = '', $owner = null) {
- global $ENTITY_SHOW_HIDDEN_OVERRIDE, $CONFIG;
-
- $sql = "";
- $friends_bit = "";
- $enemies_bit = "";
+function elgg_river_get_access_sql() {
+ // rewrite default access where clause to work with river table
+ return str_replace("and enabled='yes'", '',
+ str_replace('owner_guid', 'rv.subject_guid',
+ str_replace('access_id', 'rv.access_id', get_access_sql_suffix())));
+}
- if ($table_prefix_one) {
- $table_prefix_one = sanitise_string($table_prefix_one) . ".";
+/**
+ * Returns SQL where clause for type and subtype on river table
+ *
+ * @internal This is a simplified version of elgg_get_entity_type_subtype_where_sql()
+ * which could be used for all queries once the subtypes have been denormalized.
+ *
+ * @param string $table 'rv'
+ * @param NULL|array $types Array of types or NULL if none.
+ * @param NULL|array $subtypes Array of subtypes or NULL if none
+ * @param NULL|array $pairs Array of pairs of types and subtypes
+ *
+ * @return string
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_get_river_type_subtype_where_sql($table, $types, $subtypes, $pairs) {
+ // short circuit if nothing is requested
+ if (!$types && !$subtypes && !$pairs) {
+ return '';
}
- if ($table_prefix_two) {
- $table_prefix_two = sanitise_string($table_prefix_two) . ".";
- }
+ $wheres = array();
+ $types_wheres = array();
+ $subtypes_wheres = array();
- if (!isset($owner)) {
- $owner = get_loggedin_userid();
- }
+ // if no pairs, use types and subtypes
+ if (!is_array($pairs)) {
+ if ($types) {
+ if (!is_array($types)) {
+ $types = array($types);
+ }
+ foreach ($types as $type) {
+ $type = sanitise_string($type);
+ $types_wheres[] = "({$table}.type = '$type')";
+ }
+ }
- if (!$owner) {
- $owner = -1;
- }
+ if ($subtypes) {
+ if (!is_array($subtypes)) {
+ $subtypes = array($subtypes);
+ }
+ foreach ($subtypes as $subtype) {
+ $subtype = sanitise_string($subtype);
+ $subtypes_wheres[] = "({$table}.subtype = '$subtype')";
+ }
+ }
- $ignore_access = elgg_check_access_overrides($owner);
- $access = get_access_list($owner);
+ if (is_array($types_wheres) && count($types_wheres)) {
+ $types_wheres = array(implode(' OR ', $types_wheres));
+ }
- if ($ignore_access) {
- $sql = " (1 = 1) ";
- } else if ($owner != -1) {
- $friends_bit = "{$table_prefix_one}access_id = " . ACCESS_FRIENDS . "
- AND {$table_prefix_one}owner_guid IN (
- SELECT guid_one FROM {$CONFIG->dbprefix}entity_relationships
- WHERE relationship='friend' AND guid_two=$owner
- )";
+ if (is_array($subtypes_wheres) && count($subtypes_wheres)) {
+ $subtypes_wheres = array('(' . implode(' OR ', $subtypes_wheres) . ')');
+ }
- $friends_bit = '('.$friends_bit.') OR ';
+ $wheres = array(implode(' AND ', array_merge($types_wheres, $subtypes_wheres)));
- if ((isset($CONFIG->user_block_and_filter_enabled)) && ($CONFIG->user_block_and_filter_enabled)) {
- // check to see if the user is in the entity owner's block list
- // or if the entity owner is in the user's filter list
- // if so, disallow access
- $enemies_bit = get_annotation_sql('elgg_block_list', "{$table_prefix_one}owner_guid", $owner, false);
- $enemies_bit = '('
- . $enemies_bit
- . ' AND ' . get_annotation_sql('elgg_filter_list', $owner, "{$table_prefix_one}owner_guid", false)
- . ')';
+ } else {
+ // using type/subtype pairs
+ foreach ($pairs as $paired_type => $paired_subtypes) {
+ $paired_type = sanitise_string($paired_type);
+ if (is_array($paired_subtypes)) {
+ $paired_subtypes = array_map('sanitise_string', $paired_subtypes);
+ $paired_subtype_str = implode("','", $paired_subtypes);
+ if ($paired_subtype_str) {
+ $wheres[] = "({$table}.type = '$paired_type'"
+ . " AND {$table}.subtype IN ('$paired_subtype_str'))";
+ }
+ } else {
+ $paired_subtype = sanitise_string($paired_subtypes);
+ $wheres[] = "({$table}.type = '$paired_type'"
+ . " AND {$table}.subtype = '$paired_subtype')";
+ }
}
}
- if (empty($sql)) {
- $sql = " $friends_bit ({$table_prefix_one}access_id IN {$access}
- OR ({$table_prefix_one}owner_guid = {$owner})
- OR (
- {$table_prefix_one}access_id = " . ACCESS_PRIVATE . "
- AND {$table_prefix_one}owner_guid = $owner
- )
- )";
- }
-
- if ($enemies_bit) {
- $sql = "$enemies_bit AND ($sql)";
+ if (is_array($wheres) && count($wheres)) {
+ $where = implode(' OR ', $wheres);
+ return "($where)";
}
- if (!$ENTITY_SHOW_HIDDEN_OVERRIDE)
- $sql .= " and {$table_prefix_two}enabled='yes'";
- return '('.$sql.')';
+ return '';
}
/**
- * Construct and execute the query required for the activity stream.
+ * Get the where clause based on river action type strings
*
- * @deprecated 1.8
+ * @param array $types Array of action type strings
*
- * @param int $limit Limit the query.
- * @param int $offset Execute from the given object
- * @param mixed $type A type, or array of types to look for. Note: This is how they appear in the SYSTEM LOG.
- * @param mixed $subtype A subtype, or array of types to look for. Note: This is how they appear in the SYSTEM LOG.
- * @param mixed $owner_guid The guid or a collection of GUIDs
- * @param string $owner_relationship If defined, the relationship between $owner_guid and the entity owner_guid - so "is $owner_guid $owner_relationship with $entity->owner_guid"
- * @return array An array of system log entries.
+ * @return string
+ * @since 1.8.0
+ * @access private
*/
-function get_activity_stream_data($limit = 10, $offset = 0, $type = "", $subtype = "", $owner_guid = "", $owner_relationship = "") {
- global $CONFIG;
-
- $limit = (int)$limit;
- $offset = (int)$offset;
-
- if ($type) {
- if (!is_array($type)) {
- $type = array(sanitise_string($type));
- } else {
- foreach ($type as $k => $v) {
- $type[$k] = sanitise_string($v);
- }
- }
+function elgg_river_get_action_where_sql($types) {
+ if (!$types) {
+ return '';
}
- if ($subtype) {
- if (!is_array($subtype)) {
- $subtype = array(sanitise_string($subtype));
- } else {
- foreach ($subtype as $k => $v) {
- $subtype[$k] = sanitise_string($v);
- }
- }
+ if (!is_array($types)) {
+ $types = sanitise_string($types);
+ return "(rv.action_type = '$types')";
}
- if ($owner_guid) {
- if (is_array($owner_guid)) {
- foreach ($owner_guid as $k => $v) {
- $owner_guid[$k] = (int)$v;
- }
- } else {
- $owner_guid = array((int)$owner_guid);
- }
+ // sanitize types array
+ $types_sanitized = array();
+ foreach ($types as $type) {
+ $types_sanitized[] = sanitise_string($type);
}
- $owner_relationship = sanitise_string($owner_relationship);
-
- // Get a list of possible views
- $activity_events= array();
- $activity_views = array_merge(elgg_view_tree('activity', 'default'), elgg_view_tree('river', 'default')); // Join activity with river
+ $type_str = implode("','", $types_sanitized);
+ return "(rv.action_type IN ('$type_str'))";
+}
- $done = array();
+/**
+ * Get the where clause based on river view strings
+ *
+ * @param array $views Array of view strings
+ *
+ * @return string
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_river_get_view_where_sql($views) {
+ if (!$views) {
+ return '';
+ }
- foreach ($activity_views as $view) {
- $fragments = explode('/', $view);
- $tmp = explode('/',$view, 2);
- $tmp = $tmp[1];
+ if (!is_array($views)) {
+ $views = sanitise_string($views);
+ return "(rv.view = '$views')";
+ }
- if ((isset($fragments[0])) && (($fragments[0] == 'river') || ($fragments[0] == 'activity'))
- && (!in_array($tmp, $done))) {
+ // sanitize views array
+ $views_sanitized = array();
+ foreach ($views as $view) {
+ $views_sanitized[] = sanitise_string($view);
+ }
- if (isset($fragments[1])) {
- $f = array();
- for ($n = 1; $n < count($fragments); $n++) {
- $val = sanitise_string($fragments[$n]);
- switch($n) {
- case 1: $key = 'type'; break;
- case 2: $key = 'subtype'; break;
- case 3: $key = 'event'; break;
- }
- $f[$key] = $val;
- }
+ $view_str = implode("','", $views_sanitized);
+ return "(rv.view IN ('$view_str'))";
+}
- // Filter result based on parameters
- $add = true;
- if ($type) {
- if (!in_array($f['type'], $type)) {
- $add = false;
- }
- }
- if (($add) && ($subtype)) {
- if (!in_array($f['subtype'], $subtype)) {
- $add = false;
- }
- }
- if (($add) && ($event)) {
- if (!in_array($f['event'], $event)) {
- $add = false;
- }
- }
+/**
+ * Sets the access ID on river items for a particular object
+ *
+ * @param int $object_guid The GUID of the entity
+ * @param int $access_id The access ID
+ *
+ * @return bool Depending on success
+ */
+function update_river_access_by_object($object_guid, $access_id) {
+ // Sanitise
+ $object_guid = (int) $object_guid;
+ $access_id = (int) $access_id;
- if ($add) {
- $activity_events[] = $f;
- }
- }
+ // Load config
+ global $CONFIG;
- $done[] = $tmp;
- }
- }
+ // Remove
+ $query = "update {$CONFIG->dbprefix}river
+ set access_id = {$access_id}
+ where object_guid = {$object_guid}";
+ return update_data($query);
+}
- $n = 0;
- foreach ($activity_events as $details) {
- // Get what we're talking about
- if ($details['subtype'] == 'default') {
- $details['subtype'] = '';
- }
+/**
+ * Page handler for activity
+ *
+ * @param array $page
+ * @return bool
+ * @access private
+ */
+function elgg_river_page_handler($page) {
+ global $CONFIG;
- if (($details['type']) && ($details['event'])) {
- if ($n > 0) {
- $obj_query .= " or ";
- }
+ elgg_set_page_owner_guid(elgg_get_logged_in_user_guid());
- $access = "";
- if ($details['type']!='relationship') {
- $access = " and " . get_access_sql_suffix('sl');
- }
+ // make a URL segment available in page handler script
+ $page_type = elgg_extract(0, $page, 'all');
+ $page_type = preg_replace('[\W]', '', $page_type);
+ if ($page_type == 'owner') {
+ $page_type = 'mine';
+ }
+ set_input('page_type', $page_type);
- $obj_query .= "( sl.object_type='{$details['type']}'
- AND sl.object_subtype='{$details['subtype']}'
- AND sl.event='{$details['event']}' $access )";
+ require_once("{$CONFIG->path}pages/river.php");
+ return true;
+}
- $n++;
- }
- }
+/**
+ * Register river unit tests
+ * @access private
+ */
+function elgg_river_test($hook, $type, $value) {
+ global $CONFIG;
+ $value[] = $CONFIG->path . 'engine/tests/api/river.php';
+ return $value;
+}
- // User
- if ((count($owner_guid)) && ($owner_guid[0] != 0)) {
- $user = " and sl.performed_by_guid in (".implode(',', $owner_guid).")";
-
- if ($owner_relationship) {
- $friendsarray = "";
- if ($friends = elgg_get_entities_from_relationship(array(
- 'relationship' => $owner_relationship,
- 'relationship_guid' => $owner_guid[0],
- 'inverse_relationship' => FALSE,
- 'types' => 'user',
- 'subtypes' => $subtype,
- 'limit' => 9999))
- ) {
-
- $friendsarray = array();
- foreach($friends as $friend) {
- $friendsarray[] = $friend->getGUID();
- }
+/**
+ * Initialize river library
+ * @access private
+ */
+function elgg_river_init() {
+ elgg_register_page_handler('activity', 'elgg_river_page_handler');
+ $item = new ElggMenuItem('activity', elgg_echo('activity'), 'activity');
+ elgg_register_menu_item('site', $item);
+
+ elgg_register_widget_type('river_widget', elgg_echo('river:widget:title'), elgg_echo('river:widget:description'));
- $user = " and sl.performed_by_guid in (" . implode(',', $friendsarray).")";
- }
- }
- }
+ elgg_register_action('river/delete', '', 'admin');
- $query = "SELECT sl.* FROM {$CONFIG->dbprefix}system_log sl
- WHERE 1 $user AND ($obj_query)
- ORDER BY sl.time_created desc limit $offset, $limit";
- return get_data($query);
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'elgg_river_test');
}
+
+elgg_register_event_handler('init', 'system', 'elgg_river_init');
diff --git a/engine/lib/sessions.php b/engine/lib/sessions.php
index b74b2f524..e3d5ce9cd 100644
--- a/engine/lib/sessions.php
+++ b/engine/lib/sessions.php
@@ -4,119 +4,23 @@
* Elgg session management
* Functions to manage logins
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Session
*/
/** Elgg magic session */
global $SESSION;
/**
- * Magic session class.
- * This class is intended to extend the $_SESSION magic variable by providing an API hook
- * to plug in other values.
- *
- * Primarily this is intended to provide a way of supplying "logged in user" details without touching the session
- * (which can cause problems when accessed server side).
- *
- * If a value is present in the session then that value is returned, otherwise a plugin hook 'session:get', '$var' is called,
- * where $var is the variable being requested.
- *
- * Setting values will store variables in the session in the normal way.
- *
- * LIMITATIONS: You can not access multidimensional arrays
- *
- * This is EXPERIMENTAL.
- */
-class ElggSession implements ArrayAccess {
- /** Local cache of trigger retrieved variables */
- private static $__localcache;
-
- function __isset($key) {
- return $this->offsetExists($key);
- }
-
- /** Set a value, go straight to session. */
- function offsetSet($key, $value) {
- $_SESSION[$key] = $value;
- }
-
- /**
- * Get a variable from either the session, or if its not in the session attempt to get it from
- * an api call.
- */
- function offsetGet($key) {
- if (!ElggSession::$__localcache) {
- ElggSession::$__localcache = array();
- }
-
- if (isset($_SESSION[$key])) {
- return $_SESSION[$key];
- }
-
- if (isset(ElggSession::$__localcache[$key])) {
- return ElggSession::$__localcache[$key];
- }
-
- $value = NULL;
- $value = trigger_plugin_hook('session:get', $key, NULL, $value);
-
- ElggSession::$__localcache[$key] = $value;
-
- return ElggSession::$__localcache[$key];
- }
-
- /**
- * Unset a value from the cache and the session.
- */
- function offsetUnset($key) {
- unset(ElggSession::$__localcache[$key]);
- unset($_SESSION[$key]);
- }
-
- /**
- * Return whether the value is set in either the session or the cache.
- */
- function offsetExists($offset) {
- if (isset(ElggSession::$__localcache[$offset])) {
- return true;
- }
-
- if (isset($_SESSION[$offset])) {
- return true;
- }
-
- if ($this->offsetGet($offset)){
- return true;
- }
- }
-
-
- // Alias functions
- function get($key) {
- return $this->offsetGet($key);
- }
-
- function set($key, $value) {
- return $this->offsetSet($key, $value);
- }
-
- function del($key) {
- return $this->offsetUnset($key);
- }
-}
-
-
-/**
* Return the current logged in user, or NULL if no user is logged in.
*
- * If no user can be found in the current session, a plugin hook - 'session:get' 'user' to give plugin
- * authors another way to provide user details to the ACL system without touching the session.
- * @return ElggUser|NULL
+ * If no user can be found in the current session, a plugin
+ * hook - 'session:get' 'user' to give plugin authors another
+ * way to provide user details to the ACL system without touching the session.
+ *
+ * @return ElggUser
*/
-function get_loggedin_user() {
+function elgg_get_logged_in_user_entity() {
global $SESSION;
if (isset($SESSION)) {
@@ -129,11 +33,11 @@ function get_loggedin_user() {
/**
* Return the current logged in user by id.
*
- * @see get_loggedin_user()
+ * @see elgg_get_logged_in_user_entity()
* @return int
*/
-function get_loggedin_userid() {
- $user = get_loggedin_user();
+function elgg_get_logged_in_user_guid() {
+ $user = elgg_get_logged_in_user_entity();
if ($user) {
return $user->guid;
}
@@ -144,14 +48,10 @@ function get_loggedin_userid() {
/**
* Returns whether or not the user is currently logged in
*
- * @return true|false
+ * @return bool
*/
-function isloggedin() {
- if (!is_installed()) {
- return false;
- }
-
- $user = get_loggedin_user();
+function elgg_is_logged_in() {
+ $user = elgg_get_logged_in_user_entity();
if ((isset($user)) && ($user instanceof ElggUser) && ($user->guid > 0)) {
return true;
@@ -163,17 +63,12 @@ function isloggedin() {
/**
* Returns whether or not the user is currently logged in and that they are an admin user.
*
- * @uses isloggedin()
- * @return true|false
+ * @return bool
*/
-function isadminloggedin() {
- if (!is_installed()) {
- return FALSE;
- }
-
- $user = get_loggedin_user();
+function elgg_is_admin_logged_in() {
+ $user = elgg_get_logged_in_user_entity();
- if ((isloggedin()) && $user->isAdmin()) {
+ if ((elgg_is_logged_in()) && $user->isAdmin()) {
return TRUE;
}
@@ -182,13 +77,19 @@ function isadminloggedin() {
/**
* Check if the given user has full access.
+ *
* @todo: Will always return full access if the user is an admin.
*
- * @param $user_guid
+ * @param int $user_guid The user to check
+ *
* @return bool
+ * @since 1.7.1
*/
function elgg_is_admin_user($user_guid) {
global $CONFIG;
+
+ $user_guid = (int)$user_guid;
+
// cannot use magic metadata here because of recursion
// must support the old way of getting admin from metadata
@@ -227,63 +128,71 @@ function elgg_is_admin_user($user_guid) {
}
/**
- * Perform standard authentication with a given username and password.
- * Returns an ElggUser object for use with login.
+ * Perform user authentication with a given username and password.
+ *
+ * @warning This returns an error message on failure. Use the identical operator to check
+ * for access: if (true === elgg_authenticate()) { ... }.
+ *
*
* @see login
- * @param string $username The username, optionally (for standard logins)
- * @param string $password The password, optionally (for standard logins)
- * @return ElggUser|false The authenticated user object, or false on failure.
+ *
+ * @param string $username The username
+ * @param string $password The password
+ *
+ * @return true|string True or an error message on failure
+ * @access private
*/
-
-function authenticate($username, $password) {
- if (pam_authenticate(array('username' => $username, 'password' => $password))) {
- return get_user_by_username($username);
+function elgg_authenticate($username, $password) {
+ $pam = new ElggPAM('user');
+ $credentials = array('username' => $username, 'password' => $password);
+ $result = $pam->authenticate($credentials);
+ if (!$result) {
+ return $pam->getFailureMessage();
}
-
- return false;
+ return true;
}
/**
* Hook into the PAM system which accepts a username and password and attempts to authenticate
* it against a known user.
*
- * @param array $credentials Associated array of credentials passed to pam_authenticate. This function expects
- * 'username' and 'password' (cleartext).
+ * @param array $credentials Associated array of credentials passed to
+ * Elgg's PAM system. This function expects
+ * 'username' and 'password' (cleartext).
+ *
+ * @return bool
+ * @throws LoginException
+ * @access private
*/
-function pam_auth_userpass($credentials = NULL) {
+function pam_auth_userpass(array $credentials = array()) {
- if (is_array($credentials) && ($credentials['username']) && ($credentials['password'])) {
- if ($user = get_user_by_username($credentials['username'])) {
-
- // Let admins log in without validating their email, but normal users must have validated their email or been admin created
- if ((!$user->isAdmin()) && (!$user->validated) && (!$user->admin_created)) {
- return false;
- }
+ if (!isset($credentials['username']) || !isset($credentials['password'])) {
+ return false;
+ }
- // User has been banned, so prevent from logging in
- if ($user->isBanned()) {
- return false;
- }
+ $user = get_user_by_username($credentials['username']);
+ if (!$user) {
+ throw new LoginException(elgg_echo('LoginException:UsernameFailure'));
+ }
- if ($user->password == generate_user_password($user, $credentials['password'])) {
- return true;
- } else {
- // Password failed, log.
- log_login_failure($user->guid);
- }
+ if (check_rate_limit_exceeded($user->guid)) {
+ throw new LoginException(elgg_echo('LoginException:AccountLocked'));
+ }
- }
+ if ($user->password !== generate_user_password($user, $credentials['password'])) {
+ log_login_failure($user->guid);
+ throw new LoginException(elgg_echo('LoginException:PasswordFailure'));
}
- return false;
+ return true;
}
/**
* Log a failed login for $user_guid
*
- * @param $user_guid
- * @return bool on success
+ * @param int $user_guid User GUID
+ *
+ * @return bool
*/
function log_login_failure($user_guid) {
$user_guid = (int)$user_guid;
@@ -304,8 +213,9 @@ function log_login_failure($user_guid) {
/**
* Resets the fail login count for $user_guid
*
- * @param $user_guid
- * @return bool on success (success = user has no logged failed attempts)
+ * @param int $user_guid User GUID
+ *
+ * @return bool true on success (success = user has no logged failed attempts)
*/
function reset_login_failure_count($user_guid) {
$user_guid = (int)$user_guid;
@@ -315,7 +225,7 @@ function reset_login_failure_count($user_guid) {
$fails = (int)$user->getPrivateSetting("login_failures");
if ($fails) {
- for ($n=1; $n <= $fails; $n++) {
+ for ($n = 1; $n <= $fails; $n++) {
$user->removePrivateSetting("login_failure_$n");
}
@@ -334,7 +244,8 @@ function reset_login_failure_count($user_guid) {
/**
* Checks if the rate limit of failed logins has been exceeded for $user_guid.
*
- * @param $user_guid
+ * @param int $user_guid User GUID
+ *
* @return bool on exceeded limit.
*/
function check_rate_limit_exceeded($user_guid) {
@@ -348,13 +259,13 @@ function check_rate_limit_exceeded($user_guid) {
if ($fails >= $limit) {
$cnt = 0;
$time = time();
- for ($n=$fails; $n>0; $n--) {
+ for ($n = $fails; $n > 0; $n--) {
$f = $user->getPrivateSetting("login_failure_$n");
- if ($f > $time - (60*5)) {
+ if ($f > $time - (60 * 5)) {
$cnt++;
}
- if ($cnt==$limit) {
+ if ($cnt == $limit) {
// Limit reached
return true;
}
@@ -367,24 +278,20 @@ function check_rate_limit_exceeded($user_guid) {
/**
* Logs in a specified ElggUser. For standard registration, use in conjunction
- * with authenticate.
+ * with elgg_authenticate.
+ *
+ * @see elgg_authenticate
*
- * @see authenticate
- * @param ElggUser $user A valid Elgg user object
- * @param boolean $persistent Should this be a persistent login?
- * @return true|false Whether login was successful
+ * @param ElggUser $user A valid Elgg user object
+ * @param boolean $persistent Should this be a persistent login?
+ *
+ * @return true or throws exception
+ * @throws LoginException
*/
function login(ElggUser $user, $persistent = false) {
- global $CONFIG;
-
// User is banned, return false.
if ($user->isBanned()) {
- return false;
- }
-
- // Check rate limit
- if (check_rate_limit_exceeded($user->guid)) {
- return false;
+ throw new LoginException(elgg_echo('LoginException:BannedUser'));
}
$_SESSION['user'] = $user;
@@ -398,18 +305,18 @@ function login(ElggUser $user, $persistent = false) {
$code = (md5($user->name . $user->username . time() . rand()));
$_SESSION['code'] = $code;
$user->code = md5($code);
- setcookie("elggperm", $code, (time()+(86400 * 30)),"/");
+ setcookie("elggperm", $code, (time() + (86400 * 30)), "/");
}
- if (!$user->save() || !trigger_elgg_event('login','user',$user)) {
+ if (!$user->save() || !elgg_trigger_event('login', 'user', $user)) {
unset($_SESSION['username']);
unset($_SESSION['name']);
unset($_SESSION['code']);
unset($_SESSION['guid']);
unset($_SESSION['id']);
unset($_SESSION['user']);
- setcookie("elggperm", "", (time()-(86400 * 30)),"/");
- return false;
+ setcookie("elggperm", "", (time() - (86400 * 30)), "/");
+ throw new LoginException(elgg_echo('LoginException:Unknown'));
}
// Users privilege has been elevated, so change the session id (prevents session fixation)
@@ -419,19 +326,23 @@ function login(ElggUser $user, $persistent = false) {
set_last_login($_SESSION['guid']);
reset_login_failure_count($user->guid); // Reset any previous failed login attempts
+ // if memcache is enabled, invalidate the user in memcache @see https://github.com/Elgg/Elgg/issues/3143
+ if (is_memcache_available()) {
+ // this needs to happen with a shutdown function because of the timing with set_last_login()
+ register_shutdown_function("_elgg_invalidate_memcache_for_entity", $_SESSION['guid']);
+ }
+
return true;
}
/**
* Log the current user out
*
- * @return true|false
+ * @return bool
*/
function logout() {
- global $CONFIG;
-
if (isset($_SESSION['user'])) {
- if (!trigger_elgg_event('logout','user',$_SESSION['user'])) {
+ if (!elgg_trigger_event('logout', 'user', $_SESSION['user'])) {
return false;
}
$_SESSION['user']->code = "";
@@ -445,7 +356,7 @@ function logout() {
unset($_SESSION['id']);
unset($_SESSION['user']);
- setcookie("elggperm", "", (time()-(86400 * 30)),"/");
+ setcookie("elggperm", "", (time() - (86400 * 30)), "/");
// pass along any messages
$old_msg = $_SESSION['msg'];
@@ -453,7 +364,7 @@ function logout() {
session_destroy();
// starting a default session to store any post-logout messages.
- session_init(NULL, NULL, NULL);
+ _elgg_session_boot(NULL, NULL, NULL);
$_SESSION['msg'] = $old_msg;
return TRUE;
@@ -465,30 +376,27 @@ function logout() {
* This function looks for:
*
* 1. $_SESSION['id'] - if not present, we're logged out, and this is set to 0
- * 2. The cookie 'elggperm' - if present, checks it for an authentication token, validates it, and potentially logs the user in
+ * 2. The cookie 'elggperm' - if present, checks it for an authentication
+ * token, validates it, and potentially logs the user in
*
* @uses $_SESSION
- * @param unknown_type $event
- * @param unknown_type $object_type
- * @param unknown_type $object
+ *
+ * @return bool
+ * @access private
*/
-function session_init($event, $object_type, $object) {
+function _elgg_session_boot() {
global $DB_PREFIX, $CONFIG;
- if (!is_db_installed()) {
- return false;
- }
-
// Use database for sessions
// HACK to allow access to prefix after object destruction
$DB_PREFIX = $CONFIG->dbprefix;
if ((!isset($CONFIG->use_file_sessions))) {
- session_set_save_handler("__elgg_session_open",
- "__elgg_session_close",
- "__elgg_session_read",
- "__elgg_session_write",
- "__elgg_session_destroy",
- "__elgg_session_gc");
+ session_set_save_handler("_elgg_session_open",
+ "_elgg_session_close",
+ "_elgg_session_read",
+ "_elgg_session_write",
+ "_elgg_session_destroy",
+ "_elgg_session_gc");
}
session_name('Elgg');
@@ -496,7 +404,7 @@ function session_init($event, $object_type, $object) {
// Generate a simple token (private from potentially public session id)
if (!isset($_SESSION['__elgg_session'])) {
- $_SESSION['__elgg_session'] = md5(microtime().rand());
+ $_SESSION['__elgg_session'] = md5(microtime() . rand());
}
// test whether we have a user session
@@ -541,8 +449,8 @@ function session_init($event, $object_type, $object) {
set_last_action($_SESSION['guid']);
}
- register_action("login",true);
- register_action("logout");
+ elgg_register_action('login', '', 'public');
+ elgg_register_action('logout');
// Register a default PAM handler
register_pam_handler('pam_auth_userpass');
@@ -557,42 +465,48 @@ function session_init($event, $object_type, $object) {
return false;
}
- // Since we have loaded a new user, this user may have different language preferences
- register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/");
-
return true;
}
/**
* Used at the top of a page to mark it as logged in users only.
*
+ * @return void
*/
function gatekeeper() {
- if (!isloggedin()) {
+ if (!elgg_is_logged_in()) {
$_SESSION['last_forward_from'] = current_page_url();
register_error(elgg_echo('loggedinrequired'));
- forward();
+ forward('', 'login');
}
}
/**
* Used at the top of a page to mark it as logged in admin or siteadmin only.
*
+ * @return void
*/
function admin_gatekeeper() {
gatekeeper();
- if (!isadminloggedin()) {
+ if (!elgg_is_admin_logged_in()) {
$_SESSION['last_forward_from'] = current_page_url();
register_error(elgg_echo('adminrequired'));
- forward();
+ forward('', 'admin');
}
}
/**
- * DB Based session handling code.
+ * Handles opening a session in the DB
+ *
+ * @param string $save_path The path to save the sessions
+ * @param string $session_name The name of the session
+ *
+ * @return true
+ * @todo Document
+ * @access private
*/
-function __elgg_session_open($save_path, $session_name) {
+function _elgg_session_open($save_path, $session_name) {
global $sess_save_path;
$sess_save_path = $save_path;
@@ -600,16 +514,27 @@ function __elgg_session_open($save_path, $session_name) {
}
/**
- * DB Based session handling code.
+ * Closes a session
+ *
+ * @todo implement
+ * @todo document
+ *
+ * @return true
+ * @access private
*/
-function __elgg_session_close() {
+function _elgg_session_close() {
return true;
}
/**
- * DB Based session handling code.
+ * Read the session data from DB failing back to file.
+ *
+ * @param string $id The session ID
+ *
+ * @return string
+ * @access private
*/
-function __elgg_session_read($id) {
+function _elgg_session_read($id) {
global $DB_PREFIX;
$id = sanitise_string($id);
@@ -635,9 +560,15 @@ function __elgg_session_read($id) {
}
/**
- * DB Based session handling code.
+ * Write session data to the DB falling back to file.
+ *
+ * @param string $id The session ID
+ * @param mixed $sess_data Session data
+ *
+ * @return bool
+ * @access private
*/
-function __elgg_session_write($id, $sess_data) {
+function _elgg_session_write($id, $sess_data) {
global $DB_PREFIX;
$id = sanitise_string($id);
@@ -650,7 +581,7 @@ function __elgg_session_write($id, $sess_data) {
(session, ts, data) VALUES
('$id', '$time', '$sess_data_sanitised')";
- if (insert_data($q)!==false) {
+ if (insert_data($q) !== false) {
return true;
}
} catch (DatabaseException $e) {
@@ -670,9 +601,14 @@ function __elgg_session_write($id, $sess_data) {
}
/**
- * DB Based session handling code.
+ * Destroy a DB session, falling back to file.
+ *
+ * @param string $id Session ID
+ *
+ * @return bool
+ * @access private
*/
-function __elgg_session_destroy($id) {
+function _elgg_session_destroy($id) {
global $DB_PREFIX;
$id = sanitise_string($id);
@@ -685,24 +621,28 @@ function __elgg_session_destroy($id) {
global $sess_save_path;
$sess_file = "$sess_save_path/sess_$id";
- return(@unlink($sess_file));
+ return @unlink($sess_file);
}
-
- return false;
}
/**
- * DB Based session handling code.
+ * Perform garbage collection on session table / files
+ *
+ * @param int $maxlifetime Max age of a session
+ *
+ * @return bool
+ * @access private
*/
-function __elgg_session_gc($maxlifetime) {
+function _elgg_session_gc($maxlifetime) {
global $DB_PREFIX;
- $life = time()-$maxlifetime;
+ $life = time() - $maxlifetime;
try {
return (bool)delete_data("DELETE from {$DB_PREFIX}users_sessions where ts<'$life'");
} catch (DatabaseException $e) {
- // Fall back to file store in this case, since this likely means that the database hasn't been upgraded
+ // Fall back to file store in this case, since this likely means that the database
+ // hasn't been upgraded
global $sess_save_path;
foreach (glob("$sess_save_path/sess_*") as $filename) {
@@ -714,5 +654,3 @@ function __elgg_session_gc($maxlifetime) {
return true;
}
-
-register_elgg_event_handler("boot","system","session_init",20);
diff --git a/engine/lib/sites.php b/engine/lib/sites.php
index d67a540cc..3de0eccc2 100644
--- a/engine/lib/sites.php
+++ b/engine/lib/sites.php
@@ -3,315 +3,43 @@
* Elgg sites
* Functions to manage multiple or single sites in an Elgg install
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage DataModel.Site
*/
/**
- * ElggSite
- * Representation of a "site" in the system.
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Core
+ * Get an ElggSite entity (default is current site)
+ *
+ * @param int $site_guid Optional. Site GUID.
+ *
+ * @return ElggSite
+ * @since 1.8.0
*/
-class ElggSite extends ElggEntity {
- /**
- * Initialise the attributes array.
- * This is vital to distinguish between metadata and base parameters.
- *
- * Place your base parameters here.
- */
- protected function initialise_attributes() {
- parent::initialise_attributes();
-
- $this->attributes['type'] = "site";
- $this->attributes['name'] = "";
- $this->attributes['description'] = "";
- $this->attributes['url'] = "";
- $this->attributes['tables_split'] = 2;
- }
-
- /**
- * Construct a new site object, optionally from a given id value.
- *
- * @param mixed $guid If an int, load that GUID.
- * If a db row then will attempt to load the rest of the data.
- * @throws Exception if there was a problem creating the site.
- */
- function __construct($guid = null) {
- $this->initialise_attributes();
-
- if (!empty($guid)) {
- // Is $guid is a DB row - either a entity row, or a site table row.
- if ($guid instanceof stdClass) {
- // Load the rest
- if (!$this->load($guid->guid)) {
- throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid->guid));
- }
- }
-
- // Is $guid is an ElggSite? Use a copy constructor
- else if ($guid instanceof ElggSite) {
- elgg_deprecated_notice('This type of usage of the ElggSite constructor was deprecated. Please use the clone method.', 1.7);
-
- foreach ($guid->attributes as $key => $value) {
- $this->attributes[$key] = $value;
- }
- }
-
- // Is this is an ElggEntity but not an ElggSite = ERROR!
- else if ($guid instanceof ElggEntity) {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggSite'));
- }
-
- // See if this is a URL
- else if (strpos($guid, "http") !== false) {
- $guid = get_site_by_url($guid);
- foreach ($guid->attributes as $key => $value) {
- $this->attributes[$key] = $value;
- }
- }
-
- // We assume if we have got this far, $guid is an int
- else if (is_numeric($guid)) {
- if (!$this->load($guid)) {
- throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid));
- }
- }
-
- else {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnrecognisedValue'));
- }
- }
- }
-
- /**
- * Override the load function.
- * This function will ensure that all data is loaded (were possible), so
- * if only part of the ElggSite is loaded, it'll load the rest.
- *
- * @param int $guid
- */
- protected function load($guid) {
- // Test to see if we have the generic stuff
- if (!parent::load($guid)) {
- return false;
- }
-
- // Check the type
- if ($this->attributes['type']!='site') {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class()));
- }
-
- // Load missing data
- $row = get_site_entity_as_row($guid);
- if (($row) && (!$this->isFullyLoaded())) {
- // If $row isn't a cached copy then increment the counter
- $this->attributes['tables_loaded'] ++;
- }
-
- // Now put these into the attributes array as core values
- $objarray = (array) $row;
- foreach($objarray as $key => $value) {
- $this->attributes[$key] = $value;
- }
-
- return true;
- }
-
- /**
- * Override the save function.
- */
- public function save() {
- // Save generic stuff
- if (!parent::save()) {
- return false;
- }
-
- // Now save specific stuff
- return create_site_entity($this->get('guid'), $this->get('name'), $this->get('description'), $this->get('url'));
- }
-
- /**
- * Delete this site.
- */
- public function delete() {
- global $CONFIG;
- if ($CONFIG->site->getGUID() == $this->guid) {
- throw new SecurityException('SecurityException:deletedisablecurrentsite');
- }
-
- return parent::delete();
- }
-
- /**
- * Disable override to add safety rail.
- *
- * @param unknown_type $reason
- */
- public function disable($reason = "") {
- global $CONFIG;
-
- if ($CONFIG->site->getGUID() == $this->guid) {
- throw new SecurityException('SecurityException:deletedisablecurrentsite');
- }
-
- return parent::disable($reason);
- }
-
- /**
- * Return a list of users using this site.
- *
- * @param int $limit
- * @param int $offset
- * @return array of ElggUsers
- */
- public function getMembers($limit = 10, $offset = 0) {
- get_site_members($this->getGUID(), $limit, $offset);
- }
-
- /**
- * Add a user to the site.
- *
- * @param int $user_guid
- */
- public function addUser($user_guid) {
- return add_site_user($this->getGUID(), $user_guid);
- }
-
- /**
- * Remove a site user.
- *
- * @param int $user_guid
- */
- public function removeUser($user_guid) {
- return remove_site_user($this->getGUID(), $user_guid);
- }
-
- /**
- * Get an array of member ElggObjects.
- *
- * @param string $subtype
- * @param int $limit
- * @param int $offset
- */
- public function getObjects($subtype="", $limit = 10, $offset = 0) {
- get_site_objects($this->getGUID(), $subtype, $limit, $offset);
- }
-
- /**
- * Add an object to the site.
- *
- * @param int $user_id
- */
- public function addObject($object_guid) {
- return add_site_object($this->getGUID(), $object_guid);
- }
-
- /**
- * Remove a site user.
- *
- * @param int $user_id
- */
- public function removeObject($object_guid) {
- return remove_site_object($this->getGUID(), $object_guid);
- }
-
- /**
- * Get the collections associated with a site.
- *
- * @param string $type
- * @param int $limit
- * @param int $offset
- * @return unknown
- */
- public function getCollections($subtype="", $limit = 10, $offset = 0) {
- get_site_collections($this->getGUID(), $subtype, $limit, $offset);
- }
+function elgg_get_site_entity($site_guid = 0) {
+ global $CONFIG;
- // EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * Return an array of fields which can be exported.
- */
- public function getExportableValues() {
- return array_merge(parent::getExportableValues(), array(
- 'name',
- 'description',
- 'url',
- ));
- }
+ $result = false;
- public function check_walled_garden() {
- global $CONFIG;
-
- if ($CONFIG->walled_garden && !isloggedin()) {
- // hook into the index system call at the highest priority
- register_plugin_hook('index', 'system', 'elgg_walled_garden_index', 1);
-
- if (!$this->is_public_page()) {
- register_error(elgg_echo('loggedinrequired'));
- forward();
- }
- }
+ if ($site_guid == 0) {
+ $site = $CONFIG->site;
+ } else {
+ $site = get_entity($site_guid);
}
- public function is_public_page($url='') {
- global $CONFIG;
-
- if (empty($url)) {
- $url = current_page_url();
-
- // do not check against URL queries
- if ($pos = strpos($url, '?')) {
- $url = substr($url, 0, $pos);
- }
- }
-
- // always allow index page
- if ($url == $CONFIG->url) {
- return TRUE;
- }
-
- // default public pages
- $defaults = array(
- 'action/login',
- 'pg/register',
- 'action/register',
- 'account/forgotten_password\.php',
- 'action/user/requestnewpassword',
- 'pg/resetpassword',
- 'upgrade\.php',
- 'xml-rpc\.php',
- 'mt/mt-xmlrpc\.cgi',
- '_css/css\.css',
- '_css/js\.php',
- );
-
- // include a hook for plugin authors to include public pages
- $plugins = trigger_plugin_hook('public_pages', 'walled_garden', NULL, array());
-
- // lookup admin-specific public pages
-
- // allow public pages
- foreach (array_merge($defaults, $plugins) as $public) {
- $pattern = "`^{$CONFIG->url}$public/*$`i";
- if (preg_match($pattern, $url)) {
- return TRUE;
- }
- }
-
- // non-public page
- return FALSE;
+ if ($site instanceof ElggSite) {
+ $result = $site;
}
+
+ return $result;
}
/**
* Return the site specific details of a site by a row.
*
- * @param int $guid
+ * @param int $guid The site GUID
+ *
+ * @return mixed
+ * @access private
*/
function get_site_entity_as_row($guid) {
global $CONFIG;
@@ -321,13 +49,16 @@ function get_site_entity_as_row($guid) {
}
/**
- * Create or update the extras table for a given site.
+ * Create or update the entities table for a given site.
* Call create_entity first.
*
- * @param int $guid
- * @param string $name
- * @param string $description
- * @param string $url
+ * @param int $guid Site GUID
+ * @param string $name Site name
+ * @param string $description Site Description
+ * @param string $url URL of the site
+ *
+ * @return bool
+ * @access private
*/
function create_site_entity($guid, $name, $description, $url) {
global $CONFIG;
@@ -341,12 +72,16 @@ function create_site_entity($guid, $name, $description, $url) {
if ($row) {
// Exists and you have access to it
- if ($exists = get_data_row("SELECT guid from {$CONFIG->dbprefix}sites_entity where guid = {$guid}")) {
- $result = update_data("UPDATE {$CONFIG->dbprefix}sites_entity set name='$name', description='$description', url='$url' where guid=$guid");
- if ($result!=false) {
+ $query = "SELECT guid from {$CONFIG->dbprefix}sites_entity where guid = {$guid}";
+ if ($exists = get_data_row($query)) {
+ $query = "UPDATE {$CONFIG->dbprefix}sites_entity
+ set name='$name', description='$description', url='$url' where guid=$guid";
+ $result = update_data($query);
+
+ if ($result != false) {
// Update succeeded, continue
$entity = get_entity($guid);
- if (trigger_elgg_event('update',$entity->type,$entity)) {
+ if (elgg_trigger_event('update', $entity->type, $entity)) {
return $guid;
} else {
$entity->delete();
@@ -355,10 +90,13 @@ function create_site_entity($guid, $name, $description, $url) {
}
} else {
// Update failed, attempt an insert.
- $result = insert_data("INSERT into {$CONFIG->dbprefix}sites_entity (guid, name, description, url) values ($guid, '$name','$description','$url')");
- if ($result!==false) {
+ $query = "INSERT into {$CONFIG->dbprefix}sites_entity
+ (guid, name, description, url) values ($guid, '$name', '$description', '$url')";
+ $result = insert_data($query);
+
+ if ($result !== false) {
$entity = get_entity($guid);
- if (trigger_elgg_event('create',$entity->type,$entity)) {
+ if (elgg_trigger_event('create', $entity->type, $entity)) {
return $guid;
} else {
$entity->delete();
@@ -372,27 +110,14 @@ function create_site_entity($guid, $name, $description, $url) {
}
/**
- * THIS FUNCTION IS DEPRECATED.
- *
- * Delete a site's extra data.
- *
- * @param int $guid
- */
-function delete_site_entity($guid) {
- system_message(sprintf(elgg_echo('deprecatedfunction'), 'delete_user_entity'));
-
- return 1; // Always return that we have deleted one row in order to not break existing code.
-}
-
-/**
* Add a user to a site.
*
- * @param int $site_guid
- * @param int $user_guid
+ * @param int $site_guid Site guid
+ * @param int $user_guid User guid
+ *
+ * @return bool
*/
function add_site_user($site_guid, $user_guid) {
- global $CONFIG;
-
$site_guid = (int)$site_guid;
$user_guid = (int)$user_guid;
@@ -402,8 +127,10 @@ function add_site_user($site_guid, $user_guid) {
/**
* Remove a user from a site.
*
- * @param int $site_guid
- * @param int $user_guid
+ * @param int $site_guid Site GUID
+ * @param int $user_guid User GUID
+ *
+ * @return bool
*/
function remove_site_user($site_guid, $user_guid) {
$site_guid = (int)$site_guid;
@@ -413,62 +140,14 @@ function remove_site_user($site_guid, $user_guid) {
}
/**
- * Get the members of a site.
- *
- * @param int $site_guid
- * @param int $limit
- * @param int $offset
- */
-function get_site_members($site_guid, $limit = 10, $offset = 0) {
- $site_guid = (int)$site_guid;
- $limit = (int)$limit;
- $offset = (int)$offset;
-
- return elgg_get_entities_from_relationship(array(
- 'relationship' => 'member_of_site',
- 'relationship_guid' => $site_guid,
- 'inverse_relationship' => TRUE,
- 'types' => 'user',
- 'limit' => $limit, 'offset' => $offset
- ));
-}
-
-/**
- * Display a list of site members
- *
- * @param int $site_guid The GUID of the site
- * @param int $limit The number of members to display on a page
- * @param true|false $fullview Whether or not to display the full view (default: true)
- * @return string A displayable list of members
- */
-function list_site_members($site_guid, $limit = 10, $fullview = true) {
- $offset = (int) get_input('offset');
- $limit = (int) $limit;
- $options = array(
- 'relationship' => 'member_of_site',
- 'relationship_guid' => $site_guid,
- 'inverse_relationship' => TRUE,
- 'types' => 'user',
- 'limit' => $limit,
- 'offset' => $offset,
- 'count' => TRUE
- );
- $count = (int) elgg_get_entities_from_relationship($options);
- $entities = get_site_members($site_guid, $limit, $offset);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview);
-
-}
-
-/**
* Add an object to a site.
*
- * @param int $site_guid
- * @param int $object_guid
+ * @param int $site_guid Site GUID
+ * @param int $object_guid Object GUID
+ *
+ * @return mixed
*/
function add_site_object($site_guid, $object_guid) {
- global $CONFIG;
-
$site_guid = (int)$site_guid;
$object_guid = (int)$object_guid;
@@ -478,8 +157,10 @@ function add_site_object($site_guid, $object_guid) {
/**
* Remove an object from a site.
*
- * @param int $site_guid
- * @param int $object_guid
+ * @param int $site_guid Site GUID
+ * @param int $object_guid Object GUID
+ *
+ * @return bool
*/
function remove_site_object($site_guid, $object_guid) {
$site_guid = (int)$site_guid;
@@ -491,77 +172,24 @@ function remove_site_object($site_guid, $object_guid) {
/**
* Get the objects belonging to a site.
*
- * @param int $site_guid
- * @param string $subtype
- * @param int $limit
- * @param int $offset
+ * @param int $site_guid Site GUID
+ * @param string $subtype Subtype
+ * @param int $limit Limit
+ * @param int $offset Offset
+ *
+ * @return mixed
*/
function get_site_objects($site_guid, $subtype = "", $limit = 10, $offset = 0) {
$site_guid = (int)$site_guid;
- $subtype = sanitise_string($subtype);
$limit = (int)$limit;
$offset = (int)$offset;
return elgg_get_entities_from_relationship(array(
'relationship' => 'member_of_site',
- 'relationship_guid' => $site_guid,
- 'inverse_relationship' => TRUE,
- 'types' => 'object',
- 'subtypes' => $subtype,
- 'limit' => $limit,
- 'offset' => $offset
- ));
-}
-
-/**
- * Add a collection to a site.
- *
- * @param int $site_guid
- * @param int $collection_guid
- */
-function add_site_collection($site_guid, $collection_guid) {
- global $CONFIG;
-
- $site_guid = (int)$site_guid;
- $collection_guid = (int)$collection_guid;
-
- return add_entity_relationship($collection_guid, "member_of_site", $site_guid);
-}
-
-/**
- * Remove a collection from a site.
- *
- * @param int $site_guid
- * @param int $collection_guid
- */
-function remove_site_collection($site_guid, $collection_guid) {
- $site_guid = (int)$site_guid;
- $collection_guid = (int)$collection_guid;
-
- return remove_entity_relationship($collection_guid, "member_of_site", $site_guid);
-}
-
-/**
- * Get the collections belonging to a site.
- *
- * @param int $site_guid
- * @param string $subtype
- * @param int $limit
- * @param int $offset
- */
-function get_site_collections($site_guid, $subtype = "", $limit = 10, $offset = 0) {
- $site_guid = (int)$site_guid;
- $subtype = sanitise_string($subtype);
- $limit = (int)$limit;
- $offset = (int)$offset;
-
- // collection isn't a valid type. This won't work.
- return elgg_get_entities_from_relationship(array(
- 'relationship' => 'member_of_site',
- 'relationship_guid' => $site_guid,
- 'inverse_relationship' => TRUE,
- 'types' => 'collection',
- 'subtypes' => $subtype,
+ 'relationship_guid' => $site_guid,
+ 'inverse_relationship' => TRUE,
+ 'type' => 'object',
+ 'subtype' => $subtype,
'limit' => $limit,
'offset' => $offset
));
@@ -569,6 +197,10 @@ function get_site_collections($site_guid, $subtype = "", $limit = 10, $offset =
/**
* Return the site via a url.
+ *
+ * @param string $url The URL of a site
+ *
+ * @return mixed
*/
function get_site_by_url($url) {
global $CONFIG;
@@ -578,63 +210,18 @@ function get_site_by_url($url) {
$row = get_data_row("SELECT * from {$CONFIG->dbprefix}sites_entity where url='$url'");
if ($row) {
- return new ElggSite($row);
+ return get_entity($row->guid);
}
return false;
}
/**
- * Searches for a site based on a complete or partial name or description or url using full text searching.
- *
- * IMPORTANT NOTE: With MySQL's default setup:
- * 1) $criteria must be 4 or more characters long
- * 2) If $criteria matches greater than 50% of results NO RESULTS ARE RETURNED!
- *
- * @param string $criteria The partial or full name or username.
- * @param int $limit Limit of the search.
- * @param int $offset Offset.
- * @param string $order_by The order.
- * @param boolean $count Whether to return the count of results or just the results.
- * @deprecated 1.7
- */
-function search_for_site($criteria, $limit = 10, $offset = 0, $order_by = "", $count = false) {
- elgg_deprecated_notice('search_for_site() was deprecated by new search plugin.', 1.7);
- global $CONFIG;
-
- $criteria = sanitise_string($criteria);
- $limit = (int)$limit;
- $offset = (int)$offset;
- $order_by = sanitise_string($order_by);
-
- $access = get_access_sql_suffix("e");
-
- if ($order_by == "") {
- $order_by = "e.time_created desc";
- }
-
- if ($count) {
- $query = "SELECT count(e.guid) as total ";
- } else {
- $query = "SELECT e.* ";
- }
- $query .= "from {$CONFIG->dbprefix}entities e join {$CONFIG->dbprefix}sites_entity s on e.guid=s.guid where match(s.name,s.description,s.url) against ('$criteria') and $access";
-
- if (!$count) {
- $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
- return get_data($query, "entity_row_to_elggstar");
- } else {
- if ($count = get_data_row($query)) {
- return $count->total;
- }
- }
- return false;
-}
-
-/**
* Retrieve a site and return the domain portion of its url.
*
- * @param int $guid
+ * @param int $guid ElggSite GUID
+ *
+ * @return string
*/
function get_site_domain($guid) {
$guid = (int)$guid;
@@ -649,44 +236,21 @@ function get_site_domain($guid) {
}
/**
- * Initialise site handling
+ * Unit tests for sites
*
- * Called at the beginning of system running, to set the ID of the current site.
- * This is 0 by default, but plugins may alter this behaviour by attaching functions
- * to the sites init event and changing $CONFIG->site_id.
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
*
- * @uses $CONFIG
- * @param string $event Event API required parameter
- * @param string $object_type Event API required parameter
- * @param null $object Event API required parameter
- * @return true
+ * @return array
+ * @access private
*/
-function sites_init($event, $object_type, $object) {
- global $CONFIG;
-
- if (is_installed() && is_db_installed()) {
- $site = trigger_plugin_hook("siteid","system");
- if ($site === null || $site === false) {
- $CONFIG->site_id = (int) datalist_get('default_site');
- } else {
- $CONFIG->site_id = $site;
- }
- $CONFIG->site_guid = $CONFIG->site_id;
- $CONFIG->site = get_entity($CONFIG->site_guid);
-
- return true;
- }
-
- return true;
-}
-
-// Register event handlers
-register_elgg_event_handler('boot','system','sites_init',2);
-
-// Register with unit test
-register_plugin_hook('unit_test', 'system', 'sites_test');
function sites_test($hook, $type, $value, $params) {
global $CONFIG;
$value[] = "{$CONFIG->path}engine/tests/objects/sites.php";
return $value;
}
+
+// Register with unit test
+elgg_register_plugin_hook_handler('unit_test', 'system', 'sites_test');
diff --git a/engine/lib/social.php b/engine/lib/social.php
deleted file mode 100644
index 381c7ea4f..000000000
--- a/engine/lib/social.php
+++ /dev/null
@@ -1,119 +0,0 @@
-<?php
-/**
- * Elgg Social
- * Functions and objects which provide powerful social aspects within Elgg
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider
- * @link http://elgg.org/
-
-/**
- * Filters a string into an array of significant words
- *
- * @param string $string
- * @return array
- */
-function filter_string($string) {
- // Convert it to lower and trim
- $string = strtolower($string);
- $string = trim($string);
-
- // Remove links and email addresses
- // match protocol://address/path/file.extension?some=variable&another=asf%
- $string = preg_replace("/\s([a-zA-Z]+:\/\/[a-z][a-z0-9\_\.\-]*[a-z]{2,6}[a-zA-Z0-9\/\*\-\?\&\%\=]*)([\s|\.|\,])/iu"," ", $string);
- // match www.something.domain/path/file.extension?some=variable&another=asf%
- $string = preg_replace("/\s(www\.[a-z][a-z0-9\_\.\-]*[a-z]{2,6}[a-zA-Z0-9\/\*\-\?\&\%\=]*)([\s|\.|\,])/iu"," ", $string);
- // match name@address
- $string = preg_replace("/\s([a-zA-Z][a-zA-Z0-9\_\.\-]*[a-zA-Z]*\@[a-zA-Z][a-zA-Z0-9\_\.\-]*[a-zA-Z]{2,6})([\s|\.|\,])/iu"," ", $string);
-
- // Sanitise the string; remove unwanted characters
- $string = preg_replace('/\W/ui', ' ', $string);
-
- // Explode it into an array
- $terms = explode(' ',$string);
-
- // Remove any blacklist terms
- //$terms = array_filter($terms, 'remove_blacklist');
-
- return $terms;
-}
-
-/**
- * Returns true if the word in $input is considered significant
- *
- * @param string $input
- * @return true|false
- */
-function remove_blacklist($input) {
- global $CONFIG;
-
- if (!is_array($CONFIG->wordblacklist)) {
- return $input;
- }
-
- if (strlen($input) < 3 || in_array($input,$CONFIG->wordblacklist)) {
- return false;
- }
-
- return true;
-}
-
-
-/**
- * Initialise.
- *
- * Sets a blacklist of words in the current language. This is a comma separated list in word:blacklist.
- */
-function social_init() {
- global $CONFIG;
-
- $CONFIG->wordblacklist = array();
-
- $list = explode(',', elgg_echo('word:blacklist'));
- if ($list) {
- foreach ($list as $l) {
- $CONFIG->wordblacklist[] = trim($l);
- }
- } else {
- // Fallback - shouldn't happen
- $CONFIG->wordblacklist = array(
- 'and',
- 'the',
- 'then',
- 'but',
- 'she',
- 'his',
- 'her',
- 'him',
- 'one',
- 'not',
- 'also',
- 'about',
- 'now',
- 'hence',
- 'however',
- 'still',
- 'likewise',
- 'otherwise',
- 'therefore',
- 'conversely',
- 'rather',
- 'consequently',
- 'furthermore',
- 'nevertheless',
- 'instead',
- 'meanwhile',
- 'accordingly',
- 'this',
- 'seems',
- 'what',
- 'whom',
- 'whose',
- 'whoever',
- 'whomever',
- );
- }
-}
-
-register_elgg_event_handler("init","system","social_init"); \ No newline at end of file
diff --git a/engine/lib/statistics.php b/engine/lib/statistics.php
index b8bf2b012..4cb0bb0b8 100644
--- a/engine/lib/statistics.php
+++ b/engine/lib/statistics.php
@@ -1,20 +1,20 @@
<?php
/**
* Elgg statistics library.
+ *
* This file contains a number of functions for obtaining statistics about the running system.
- * These statistics are mainly used by the administration pages, and is also where the basic views for statistics
- * are added.
+ * These statistics are mainly used by the administration pages, and is also where the basic
+ * views for statistics are added.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Statistics
*/
/**
* Return an array reporting the number of various entities in the system.
*
* @param int $owner_guid Optional owner of the statistics
+ *
* @return array
*/
function get_entity_statistics($owner_guid = 0) {
@@ -23,7 +23,10 @@ function get_entity_statistics($owner_guid = 0) {
$entity_stats = array();
$owner_guid = (int)$owner_guid;
- $query = "SELECT distinct e.type,s.subtype,e.subtype as subtype_id from {$CONFIG->dbprefix}entities e left join {$CONFIG->dbprefix}entity_subtypes s on e.subtype=s.id";
+ $query = "SELECT distinct e.type,s.subtype,e.subtype as subtype_id
+ from {$CONFIG->dbprefix}entities e left
+ join {$CONFIG->dbprefix}entity_subtypes s on e.subtype=s.id";
+
$owner_query = "";
if ($owner_guid) {
$query .= " where owner_guid=$owner_guid";
@@ -39,9 +42,11 @@ function get_entity_statistics($owner_guid = 0) {
$entity_stats[$type->type] = array();
}
- $query = "SELECT count(*) as count from {$CONFIG->dbprefix}entities where type='{$type->type}' $owner_query";
+ $query = "SELECT count(*) as count
+ from {$CONFIG->dbprefix}entities where type='{$type->type}' $owner_query";
+
if ($type->subtype) {
- $query.= " and subtype={$type->subtype_id}";
+ $query .= " and subtype={$type->subtype_id}";
}
$subtype_cnt = get_data_row($query);
@@ -59,7 +64,8 @@ function get_entity_statistics($owner_guid = 0) {
/**
* Return the number of users registered in the system.
*
- * @param bool $show_deactivated
+ * @param bool $show_deactivated Count not enabled users?
+ *
* @return int
*/
function get_number_users($show_deactivated = false) {
@@ -71,7 +77,10 @@ function get_number_users($show_deactivated = false) {
$access = "and " . get_access_sql_suffix();
}
- $result = get_data_row("SELECT count(*) as count from {$CONFIG->dbprefix}entities where type='user' $access");
+ $query = "SELECT count(*) as count
+ from {$CONFIG->dbprefix}entities where type='user' $access";
+
+ $result = get_data_row($query);
if ($result) {
return $result->count;
@@ -82,28 +91,36 @@ function get_number_users($show_deactivated = false) {
/**
* Return a list of how many users are currently online, rendered as a view.
+ *
+ * @return string
*/
function get_online_users() {
- $offset = get_input('offset', 0);
- $count = count(find_active_users(600, 9999));
- $objects = find_active_users(600, 10, $offset);
+ $limit = max(0, (int) get_input("limit", 10));
+ $offset = max(0, (int) get_input("offset", 0));
+
+ $count = find_active_users(600, $limit, $offset, true);
+ $objects = find_active_users(600, $limit, $offset);
if ($objects) {
- return elgg_view_entity_list($objects, $count,$offset,10,false);
+ return elgg_view_entity_list($objects, array(
+ 'count' => $count,
+ 'limit' => $limit,
+ 'offset' => $offset
+ ));
}
+ return '';
}
/**
* Initialise the statistics admin page.
+ *
+ * @return void
+ * @access private
*/
function statistics_init() {
- extend_elgg_admin_page('admin/statistics_opt/basic', 'admin/statistics');
- extend_elgg_admin_page('admin/statistics_opt/numentities', 'admin/statistics');
- extend_elgg_admin_page('admin/statistics_opt/online', 'admin/statistics');
-
- extend_elgg_settings_page('usersettings/statistics_opt/online', 'usersettings/statistics');
- extend_elgg_settings_page('usersettings/statistics_opt/numentities', 'usersettings/statistics');
+ elgg_extend_view('core/settings/statistics', 'core/settings/statistics/online');
+ elgg_extend_view('core/settings/statistics', 'core/settings/statistics/numentities');
}
/// Register init function
-register_elgg_event_handler('init','system','statistics_init'); \ No newline at end of file
+elgg_register_event_handler('init', 'system', 'statistics_init');
diff --git a/engine/lib/system_log.php b/engine/lib/system_log.php
index 74597ed5d..84302632e 100644
--- a/engine/lib/system_log.php
+++ b/engine/lib/system_log.php
@@ -3,110 +3,72 @@
* Elgg system log.
* Listens to events and writes crud events into the system log database.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Logging
*/
/**
- * Interface that provides an interface which must be implemented by all objects wishing to be
- * recorded in the system log (and by extension the river).
- *
- * This interface defines a set of methods that permit the system log functions to hook in and retrieve
- * the necessary information and to identify what events can actually be logged.
+ * Retrieve the system log based on a number of parameters.
*
- * To have events involving your object to be logged simply implement this interface.
+ * @todo too many args, and the first arg is too confusing
*
- * @author Curverider Ltd
+ * @param int|array $by_user The guid(s) of the user(s) who initiated the event.
+ * Use 0 for unowned entries. Anything else falsey means anyone.
+ * @param string $event The event you are searching on.
+ * @param string $class The class of object it effects.
+ * @param string $type The type
+ * @param string $subtype The subtype.
+ * @param int $limit Maximum number of responses to return.
+ * @param int $offset Offset of where to start.
+ * @param bool $count Return count or not
+ * @param int $timebefore Lower time limit
+ * @param int $timeafter Upper time limit
+ * @param int $object_id GUID of an object
+ * @param string $ip_address The IP address.
+ * @return mixed
*/
-interface Loggable {
- /**
- * Return an identification for the object for storage in the system log.
- * This id must be an integer.
- *
- * @return int
- */
- public function getSystemLogID();
-
- /**
- * Return the class name of the object.
- * Added as a function because get_class causes errors for some reason.
- */
- public function getClassName();
-
- /**
- * Return the type of the object - eg. object, group, user, relationship, metadata, annotation etc
- */
- public function getType();
-
- /**
- * Return a subtype. For metadata & annotations this is the 'name' and for relationship this is the relationship type.
- */
- public function getSubtype();
-
- /**
- * 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 the GUID of the owner of this object.
- */
- public function getObjectOwnerGUID();
-}
+function get_system_log($by_user = "", $event = "", $class = "", $type = "", $subtype = "", $limit = 10,
+ $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $object_id = 0,
+ $ip_address = "") {
-/**
- * Retrieve the system log based on a number of parameters.
- *
- * @param int or array $by_user The guid(s) of the user(s) who initiated the event.
- * @param string $event The event you are searching on.
- * @param string $class The class of object it effects.
- * @param string $type The type
- * @param string $subtype The subtype.
- * @param int $limit Maximum number of responses to return.
- * @param int $offset Offset of where to start.
- * @param bool $count Return count or not
- */
-function get_system_log($by_user = "", $event = "", $class = "", $type = "", $subtype = "", $limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $object_id = 0) {
global $CONFIG;
$by_user_orig = $by_user;
if (is_array($by_user) && sizeof($by_user) > 0) {
- foreach($by_user as $key => $val) {
+ foreach ($by_user as $key => $val) {
$by_user[$key] = (int) $val;
}
} else {
$by_user = (int)$by_user;
}
+
$event = sanitise_string($event);
$class = sanitise_string($class);
$type = sanitise_string($type);
$subtype = sanitise_string($subtype);
+ $ip_address = sanitise_string($ip_address);
$limit = (int)$limit;
$offset = (int)$offset;
$where = array();
- if ($by_user_orig!=="") {
+ if ($by_user_orig !== "" && $by_user_orig !== false && $by_user_orig !== null) {
if (is_int($by_user)) {
$where[] = "performed_by_guid=$by_user";
} else if (is_array($by_user)) {
- $where [] = "performed_by_guid in (". implode(",",$by_user) .")";
+ $where [] = "performed_by_guid in (" . implode(",", $by_user) . ")";
}
}
if ($event != "") {
$where[] = "event='$event'";
}
- if ($class!=="") {
+ if ($class !== "") {
$where[] = "object_class='$class'";
}
if ($type != "") {
$where[] = "object_type='$type'";
}
- if ($subtype!=="") {
+ if ($subtype !== "") {
$where[] = "object_subtype='$subtype'";
}
@@ -119,6 +81,9 @@ function get_system_log($by_user = "", $event = "", $class = "", $type = "", $su
if ($object_id) {
$where[] = "object_id = " . ((int) $object_id);
}
+ if ($ip_address) {
+ $where[] = "ip_address = '$ip_address'";
+ }
$select = "*";
if ($count) {
@@ -135,7 +100,8 @@ function get_system_log($by_user = "", $event = "", $class = "", $type = "", $su
}
if ($count) {
- if ($numrows = get_data_row($query)) {
+ $numrows = get_data_row($query);
+ if ($numrows) {
return $numrows->count;
}
} else {
@@ -149,6 +115,8 @@ function get_system_log($by_user = "", $event = "", $class = "", $type = "", $su
* Return a specific log entry.
*
* @param int $entry_id The log entry
+ *
+ * @return mixed
*/
function get_log_entry($entry_id) {
global $CONFIG;
@@ -162,15 +130,20 @@ function get_log_entry($entry_id) {
* Return the object referred to by a given log entry
*
* @param int $entry_id The log entry
+ *
+ * @return mixed
*/
function get_object_from_log_entry($entry_id) {
$entry = get_log_entry($entry_id);
if ($entry) {
$class = $entry->object_class;
- $tmp = new $class();
- $object = $tmp->getObjectFromID($entry->object_id);
-
+ // surround with try/catch because object could be disabled
+ try {
+ $object = new $class($entry->object_id);
+ } catch (Exception $e) {
+
+ }
if ($object) {
return $object;
}
@@ -184,16 +157,27 @@ function get_object_from_log_entry($entry_id) {
*
* This is called by the event system and should not be called directly.
*
- * @param $object The object you're talking about.
- * @param $event String The event being logged
+ * @param object $object The object you're talking about.
+ * @param string $event The event being logged
+ * @return void
*/
function system_log($object, $event) {
global $CONFIG;
- static $logcache;
+ static $log_cache;
+ static $cache_size = 0;
if ($object instanceof Loggable) {
- if (!is_array($logcache)) {
- $logcache = array();
+
+ /* @var ElggEntity|ElggExtender $object */
+ if (datalist_get('version') < 2012012000) {
+ // this is a site that doesn't have the ip_address column yet
+ return;
+ }
+
+ // reset cache if it has grown too large
+ if (!is_array($log_cache) || $cache_size > 500) {
+ $log_cache = array();
+ $cache_size = 0;
}
// Has loggable interface, extract the necessary information and store
@@ -203,7 +187,17 @@ function system_log($object, $event) {
$object_subtype = $object->getSubtype();
$event = sanitise_string($event);
$time = time();
- $performed_by = get_loggedin_userid();
+
+ if (!empty($_SERVER['HTTP_X_FORWARDED_FOR'])) {
+ $ip_address = array_pop(explode(',', $_SERVER['HTTP_X_FORWARDED_FOR']));
+ } elseif (!empty($_SERVER['HTTP_X_REAL_IP'])) {
+ $ip_address = array_pop(explode(',', $_SERVER['HTTP_X_REAL_IP']));
+ } else {
+ $ip_address = $_SERVER['REMOTE_ADDR'];
+ }
+ $ip_address = sanitise_string($ip_address);
+
+ $performed_by = elgg_get_logged_in_user_guid();
if (isset($object->access_id)) {
$access_id = $object->access_id;
@@ -223,13 +217,19 @@ function system_log($object, $event) {
}
// Create log if we haven't already created it
- if (!isset($logcache[$time][$object_id][$event])) {
- insert_data("INSERT DELAYED into {$CONFIG->dbprefix}system_log (object_id, object_class, object_type, object_subtype, event, performed_by_guid, owner_guid, access_id, enabled, time_created) VALUES ('$object_id','$object_class','$object_type', '$object_subtype', '$event',$performed_by, $owner_guid, $access_id, '$enabled', '$time')");
-
- $logcache[$time][$object_id][$event] = true;
+ if (!isset($log_cache[$time][$object_id][$event])) {
+ $query = "INSERT DELAYED into {$CONFIG->dbprefix}system_log
+ (object_id, object_class, object_type, object_subtype, event,
+ performed_by_guid, owner_guid, access_id, enabled, time_created, ip_address)
+ VALUES
+ ('$object_id','$object_class','$object_type', '$object_subtype', '$event',
+ $performed_by, $owner_guid, $access_id, '$enabled', '$time', '$ip_address')";
+
+ insert_data($query);
+
+ $log_cache[$time][$object_id][$event] = true;
+ $cache_size += 1;
}
-
- return true;
}
}
@@ -237,6 +237,8 @@ function system_log($object, $event) {
* This function creates an archive copy of the system log.
*
* @param int $offset An offset in seconds from now to archive (useful for log rotation)
+ *
+ * @return bool
*/
function archive_log($offset = 0) {
global $CONFIG;
@@ -247,7 +249,10 @@ function archive_log($offset = 0) {
$ts = $now - $offset;
// create table
- if (!update_data("CREATE TABLE {$CONFIG->dbprefix}system_log_$now as SELECT * from {$CONFIG->dbprefix}system_log WHERE time_created<$ts")) {
+ $query = "CREATE TABLE {$CONFIG->dbprefix}system_log_$now as
+ SELECT * from {$CONFIG->dbprefix}system_log WHERE time_created<$ts";
+
+ if (!update_data($query)) {
return false;
}
@@ -268,10 +273,11 @@ function archive_log($offset = 0) {
/**
* Default system log handler, allows plugins to override, extend or disable logging.
*
- * @param string $event
- * @param string $object_type
- * @param Loggable $object
- * @return unknown
+ * @param string $event Event name
+ * @param string $object_type Object type
+ * @param Loggable $object Object to log
+ *
+ * @return true
*/
function system_log_default_logger($event, $object_type, $object) {
system_log($object['object'], $object['event']);
@@ -283,20 +289,23 @@ function system_log_default_logger($event, $object_type, $object) {
* System log listener.
* This function listens to all events in the system and logs anything appropriate.
*
- * @param String $event
- * @param String $object_type
- * @param Loggable $object
+ * @param String $event Event name
+ * @param String $object_type Type of object
+ * @param Loggable $object Object to log
+ *
+ * @return true
+ * @access private
*/
function system_log_listener($event, $object_type, $object) {
- if (($object_type!='systemlog') && ($event!='log')) {
- trigger_elgg_event('log', 'systemlog', array('object' => $object, 'event' => $event));
+ if (($object_type != 'systemlog') && ($event != 'log')) {
+ elgg_trigger_event('log', 'systemlog', array('object' => $object, 'event' => $event));
}
return true;
}
/** Register event to listen to all events **/
-register_elgg_event_handler('all','all','system_log_listener', 400);
+elgg_register_event_handler('all', 'all', 'system_log_listener', 400);
/** Register a default system log handler */
-register_elgg_event_handler('log','systemlog','system_log_default_logger', 999); \ No newline at end of file
+elgg_register_event_handler('log', 'systemlog', 'system_log_default_logger', 999);
diff --git a/engine/lib/tags.php b/engine/lib/tags.php
index ce1fbbf93..586a9b9e4 100644
--- a/engine/lib/tags.php
+++ b/engine/lib/tags.php
@@ -3,28 +3,33 @@
* Elgg tags
* Functions for managing tags and tag clouds.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Tags
*/
-
/**
* The algorithm working out the size of font based on the number of tags.
* This is quick and dirty.
+ *
+ * @param int $min Min size
+ * @param int $max Max size
+ * @param int $number_of_tags The number of tags
+ * @param int $buckets The number of buckets
+ *
+ * @return int
+ * @access private
*/
function calculate_tag_size($min, $max, $number_of_tags, $buckets = 6) {
- $delta = (($max - $min) / $buckets);
+ $delta = (($max - $min) / $buckets);
$thresholds = array();
- for ($n=1; $n <= $buckets; $n++) {
- $thresholds[$n-1] = ($min + $n) * $delta;
+ for ($n = 1; $n <= $buckets; $n++) {
+ $thresholds[$n - 1] = ($min + $n) * $delta;
}
// Correction
- if ($thresholds[$buckets-1]>$max) {
- $thresholds[$buckets-1] = $max;
+ if ($thresholds[$buckets - 1] > $max) {
+ $thresholds[$buckets - 1] = $max;
}
$size = 0;
@@ -40,8 +45,11 @@ function calculate_tag_size($min, $max, $number_of_tags, $buckets = 6) {
/**
* This function generates an array of tags with a weighting.
*
- * @param array $tags The array of tags.
- * @return An associated array of tags with a weighting, this can then be mapped to a display class.
+ * @param array $tags The array of tags.
+ * @param int $buckets The number of buckets
+ *
+ * @return array An associated array of tags with a weighting, this can then be mapped to a display class.
+ * @access private
*/
function generate_tag_cloud(array $tags, $buckets = 6) {
$cloud = array();
@@ -52,11 +60,11 @@ function generate_tag_cloud(array $tags, $buckets = 6) {
foreach ($tags as $tag) {
$cloud[$tag]++;
- if ($cloud[$tag]>$max) {
+ if ($cloud[$tag] > $max) {
$max = $cloud[$tag];
}
- if ($cloud[$tag]<$min) {
+ if ($cloud[$tag] < $min) {
$min = $cloud[$tag];
}
}
@@ -73,8 +81,6 @@ function generate_tag_cloud(array $tags, $buckets = 6) {
*
* Supports similar arguments as elgg_get_entities()
*
- * @since 1.7.1
- *
* @param array $options Array in format:
*
* threshold => INT minimum tag count
@@ -87,7 +93,8 @@ function generate_tag_cloud(array $tags, $buckets = 6) {
*
* subtypes => NULL|STR entity subtype (SQL: subtype = '$subtype')
*
- * type_subtype_pairs => NULL|ARR (array('type' => 'subtype')) (SQL: type = '$type' AND subtype = '$subtype') pairs
+ * type_subtype_pairs => NULL|ARR (array('type' => 'subtype'))
+ * (SQL: type = '$type' AND subtype = '$subtype') pairs
*
* owner_guids => NULL|INT entity guid
*
@@ -107,8 +114,9 @@ function generate_tag_cloud(array $tags, $buckets = 6) {
*
* joins => array() Additional joins
*
- * @return false/array - if no tags or error, false
- * otherwise, array of objects with ->tag and ->total values
+ * @return object[]|false If no tags or error, false
+ * otherwise, array of objects with ->tag and ->total values
+ * @since 1.7.1
*/
function elgg_get_tags(array $options = array()) {
global $CONFIG;
@@ -138,10 +146,9 @@ function elgg_get_tags(array $options = array()) {
$options = array_merge($defaults, $options);
- $singulars = array('type', 'subtype', 'owner_guid', 'container_guid', 'site_guid');
+ $singulars = array('type', 'subtype', 'owner_guid', 'container_guid', 'site_guid', 'tag_name');
$options = elgg_normalise_plural_options_array($options, $singulars);
-
$registered_tags = elgg_get_registered_tag_metadata_names();
if (!is_array($options['tag_names'])) {
@@ -165,22 +172,21 @@ function elgg_get_tags(array $options = array()) {
// catch for tags that were spaces
$wheres[] = "msv.string != ''";
+ $sanitised_tags = array();
foreach ($options['tag_names'] as $tag) {
$sanitised_tags[] = '"' . sanitise_string($tag) . '"';
}
$tags_in = implode(',', $sanitised_tags);
$wheres[] = "(msn.string IN ($tags_in))";
- $wheres[] = elgg_get_entity_type_subtype_where_sql('e', $options['types'], $options['subtypes'], $options['type_subtype_pairs']);
- $wheres[] = elgg_get_entity_site_where_sql('e', $options['site_guids']);
- $wheres[] = elgg_get_entity_owner_where_sql('e', $options['owner_guids']);
- $wheres[] = elgg_get_entity_container_where_sql('e', $options['container_guids']);
+ $wheres[] = elgg_get_entity_type_subtype_where_sql('e', $options['types'],
+ $options['subtypes'], $options['type_subtype_pairs']);
+ $wheres[] = elgg_get_guid_based_where_sql('e.site_guid', $options['site_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('e.owner_guid', $options['owner_guids']);
+ $wheres[] = elgg_get_guid_based_where_sql('e.container_guid', $options['container_guids']);
$wheres[] = elgg_get_entity_time_where_sql('e', $options['created_time_upper'],
$options['created_time_lower'], $options['modified_time_upper'], $options['modified_time_lower']);
- // remove identical where clauses
- $wheres = array_unique($wheres);
-
// see if any functions failed
// remove empty strings on successful functions
foreach ($wheres as $i => $where) {
@@ -191,6 +197,8 @@ function elgg_get_tags(array $options = array()) {
}
}
+ // remove identical where clauses
+ $wheres = array_unique($wheres);
$joins = $options['joins'];
@@ -229,7 +237,7 @@ function elgg_get_tags(array $options = array()) {
$query .= get_access_sql_suffix('e');
$threshold = sanitise_int($options['threshold']);
- $query .= " GROUP BY msv.string HAVING total > {$threshold} ";
+ $query .= " GROUP BY msv.string HAVING total >= {$threshold} ";
$query .= " ORDER BY total DESC ";
$limit = sanitise_int($options['limit']);
@@ -239,75 +247,8 @@ function elgg_get_tags(array $options = array()) {
}
/**
- * Get an array of tags with weights for use with the output/tagcloud view.
- *
- * @deprecated 1.8 Use elgg_get_tags().
- *
- * @param int $threshold Get the threshold of minimum number of each tags to bother with (ie only show tags where there are more than $threshold occurances)
- * @param int $limit Number of tags to return
- * @param string $metadata_name Optionally, the name of the field you want to grab for
- * @param string $entity_type Optionally, the entity type ('object' etc)
- * @param string $entity_subtype The entity subtype, optionally
- * @param int $owner_guid The GUID of the tags owner, optionally
- * @param int $site_guid Optionally, the site to restrict to (default is the current site)
- * @param int $start_ts Optionally specify a start timestamp for tags used to generate cloud.
- * @param int $ent_ts Optionally specify an end timestamp for tags used to generate cloud.
- * @return array|false Array of objects with ->tag and ->total values, or false on failure
- */
-
-function get_tags($threshold = 1, $limit = 10, $metadata_name = "", $entity_type = "object", $entity_subtype = "", $owner_guid = "", $site_guid = -1, $start_ts = "", $end_ts = "") {
-
- elgg_deprecated_notice('get_tags() has been replaced by elgg_get_tags()', 1.8);
-
- if (is_array($metadata_name)) {
- return false;
- }
-
- $options = array();
- if ($metadata_name === '') {
- $options['tag_names'] = array();
- } else {
- $options['tag_names'] = array($metadata_name);
- }
-
- $options['threshold'] = $threshold;
- $options['limit'] = $limit;
-
- // rewrite owner_guid to container_guid to emulate old functionality
- $container_guid = $owner_guid;
- if ($container_guid) {
- $options['container_guids'] = $container_guid;
- }
-
- if ($entity_type) {
- $options['type'] = $entity_type;
- }
-
- if ($entity_subtype) {
- $options['subtype'] = $entity_subtype;
- }
-
- if ($site_guid != -1) {
- $options['site_guids'] = $site_guid;
- }
-
- if ($end_ts) {
- $options['created_time_upper'] = $end_ts;
- }
-
- if ($start_ts) {
- $options['created_time_lower'] = $start_ts;
- }
-
- $r = elgg_get_tags($options);
- return $r;
-}
-
-/**
* Returns viewable tagcloud
*
- * @since 1.7.1
- *
* @see elgg_get_tags
*
* @param array $options Any elgg_get_tags() options except:
@@ -317,7 +258,7 @@ function get_tags($threshold = 1, $limit = 10, $metadata_name = "", $entity_type
* subtype => must be single entity subtype
*
* @return string
- *
+ * @since 1.7.1
*/
function elgg_view_tagcloud(array $options = array()) {
@@ -328,40 +269,12 @@ function elgg_view_tagcloud(array $options = array()) {
if (isset($options['subtype'])) {
$subtype = $options['subtype'];
}
-
- $tag_data = elgg_get_tags($options);
- return elgg_view("output/tagcloud",array('value' => $tag_data,
- 'type' => $type,
- 'subtype' => $subtype));
-}
-
-/**
- * Loads and displays a tagcloud given particular criteria.
- *
- * @deprecated 1.8 use elgg_view_tagcloud()
- *
- * @param int $threshold Get the threshold of minimum number of each tags to bother with (ie only show tags where there are more than $threshold occurances)
- * @param int $limit Number of tags to return
- * @param string $metadata_name Optionally, the name of the field you want to grab for
- * @param string $entity_type Optionally, the entity type ('object' etc)
- * @param string $entity_subtype The entity subtype, optionally
- * @param int $owner_guid The GUID of the tags owner, optionally
- * @param int $site_guid Optionally, the site to restrict to (default is the current site)
- * @param int $start_ts Optionally specify a start timestamp for tags used to generate cloud.
- * @param int $ent_ts Optionally specify an end timestamp for tags used to generate cloud.
- * @return string The HTML (or other, depending on view type) of the tagcloud.
- */
-
-function display_tagcloud($threshold = 1, $limit = 10, $metadata_name = "", $entity_type = "object", $entity_subtype = "", $owner_guid = "", $site_guid = -1, $start_ts = "", $end_ts = "") {
-
- elgg_deprecated_notice('display_cloud() was deprecated by elgg_view_tagcloud()!', 1.8);
-
- $tags = get_tags($threshold, $limit, $metadata_name, $entity_type, $entity_subtype, $owner_guid, $site_guid, $start_ts, $end_ts);
- return elgg_view('output/tagcloud', array(
- 'value' => $tags,
- 'type' => $entity_type,
- 'subtype' => $entity_subtype,
+ $tag_data = elgg_get_tags($options);
+ return elgg_view("output/tagcloud", array(
+ 'value' => $tag_data,
+ 'type' => $type,
+ 'subtype' => $subtype,
));
}
@@ -370,10 +283,10 @@ function display_tagcloud($threshold = 1, $limit = 10, $metadata_name = "", $ent
* This is required if you are using a non-standard metadata name
* for your tags.
*
- * @since 1.7
+ * @param string $name Tag name
*
- * @param string $name
- * @return TRUE
+ * @return bool
+ * @since 1.7.0
*/
function elgg_register_tag_metadata_name($name) {
global $CONFIG;
@@ -392,31 +305,50 @@ function elgg_register_tag_metadata_name($name) {
/**
* Returns an array of valid metadata names for tags.
*
- * @since 1.7
- *
* @return array
+ * @since 1.7.0
*/
function elgg_get_registered_tag_metadata_names() {
global $CONFIG;
- $names = (isset($CONFIG->registered_tag_metadata_names)) ? $CONFIG->registered_tag_metadata_names : array();
+ $names = (isset($CONFIG->registered_tag_metadata_names))
+ ? $CONFIG->registered_tag_metadata_names : array();
+
return $names;
}
-// register the standard tags metadata name
-elgg_register_tag_metadata_name('tags');
-
-register_page_handler('tags', 'elgg_tagcloud_page_handler');
+/**
+ * Page hander for tags
+ *
+ * @param array $page Page array
+ *
+ * @return bool
+ * @access private
+ */
function elgg_tagcloud_page_handler($page) {
- global $CONFIG;
+
+ $title = elgg_view_title(elgg_echo('tags:site_cloud'));
+ $options = array(
+ 'threshold' => 0,
+ 'limit' => 100,
+ 'tag_name' => 'tags',
+ );
+ $tags = elgg_view_tagcloud($options);
+ $content = $title . $tags;
+ $body = elgg_view_layout('one_sidebar', array('content' => $content));
+
+ echo elgg_view_page(elgg_echo('tags:site_cloud'), $body);
+ return true;
+}
+
+/**
+ * @access private
+ */
+function elgg_tags_init() {
+ // register the standard tags metadata name
+ elgg_register_tag_metadata_name('tags');
- switch ($page[0]) {
- default:
- $title = elgg_view_title(elgg_echo('tags:site_cloud'));
- $tags = display_tagcloud(0, 100, 'tags');
- $body = elgg_view_layout('one_column_with_sidebar', $title . $tags);
-
- page_draw(elgg_echo('tags:site_cloud'), $body);
- break;
- }
+ elgg_register_page_handler('tags', 'elgg_tagcloud_page_handler');
}
+
+elgg_register_event_handler('init', 'system', 'elgg_tags_init'); \ No newline at end of file
diff --git a/engine/lib/upgrade.php b/engine/lib/upgrade.php
new file mode 100644
index 000000000..158ec9ec1
--- /dev/null
+++ b/engine/lib/upgrade.php
@@ -0,0 +1,365 @@
+<?php
+/**
+ * Elgg upgrade library.
+ * Contains code for handling versioning and upgrades.
+ *
+ * @package Elgg.Core
+ * @subpackage Upgrade
+ */
+
+/**
+ * Run any php upgrade scripts which are required
+ *
+ * @param int $version Version upgrading from.
+ * @param bool $quiet Suppress errors. Don't use this.
+ *
+ * @return bool
+ * @access private
+ */
+function upgrade_code($version, $quiet = FALSE) {
+ // do not remove - upgrade scripts depend on this
+ global $CONFIG;
+
+ $version = (int) $version;
+ $upgrade_path = elgg_get_config('path') . 'engine/lib/upgrades/';
+ $processed_upgrades = elgg_get_processed_upgrades();
+
+ // upgrading from 1.7 to 1.8. Need to bootstrap.
+ if (!$processed_upgrades) {
+ elgg_upgrade_bootstrap_17_to_18();
+
+ // grab accurate processed upgrades
+ $processed_upgrades = elgg_get_processed_upgrades();
+ }
+
+ $upgrade_files = elgg_get_upgrade_files($upgrade_path);
+
+ if ($upgrade_files === false) {
+ return false;
+ }
+
+ $upgrades = elgg_get_unprocessed_upgrades($upgrade_files, $processed_upgrades);
+
+ // Sort and execute
+ sort($upgrades);
+
+ foreach ($upgrades as $upgrade) {
+ $upgrade_version = elgg_get_upgrade_file_version($upgrade);
+ $success = true;
+
+ // hide all errors.
+ if ($quiet) {
+ // hide include errors as well as any exceptions that might happen
+ try {
+ if (!@include("$upgrade_path/$upgrade")) {
+ $success = false;
+ error_log("Could not include $upgrade_path/$upgrade");
+ }
+ } catch (Exception $e) {
+ $success = false;
+ error_log($e->getmessage());
+ }
+ } else {
+ if (!include("$upgrade_path/$upgrade")) {
+ $success = false;
+ error_log("Could not include $upgrade_path/$upgrade");
+ }
+ }
+
+ if ($success) {
+ // incrementally set upgrade so we know where to start if something fails.
+ $processed_upgrades[] = $upgrade;
+
+ // don't set the version to a lower number in instances where an upgrade
+ // has been merged from a lower version of Elgg
+ if ($upgrade_version > $version) {
+ datalist_set('version', $upgrade_version);
+ }
+
+ elgg_set_processed_upgrades($processed_upgrades);
+ } else {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+/**
+ * Saves the processed upgrades to a dataset.
+ *
+ * @param array $processed_upgrades An array of processed upgrade filenames
+ * (not the path, just the file)
+ * @return bool
+ * @access private
+ */
+function elgg_set_processed_upgrades(array $processed_upgrades) {
+ $processed_upgrades = array_unique($processed_upgrades);
+ return datalist_set('processed_upgrades', serialize($processed_upgrades));
+}
+
+/**
+ * Gets a list of processes upgrades
+ *
+ * @return mixed Array of processed upgrade filenames or false
+ * @access private
+ */
+function elgg_get_processed_upgrades() {
+ $upgrades = datalist_get('processed_upgrades');
+ $unserialized = unserialize($upgrades);
+ return $unserialized;
+}
+
+/**
+ * Returns the version of the upgrade filename.
+ *
+ * @param string $filename The upgrade filename. No full path.
+ * @return int|false
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_get_upgrade_file_version($filename) {
+ preg_match('/^([0-9]{10})([\.a-z0-9-_]+)?\.(php)$/i', $filename, $matches);
+
+ if (isset($matches[1])) {
+ return (int) $matches[1];
+ }
+
+ return false;
+}
+
+/**
+ * Returns a list of upgrade files relative to the $upgrade_path dir.
+ *
+ * @param string $upgrade_path The up
+ * @return array|false
+ * @access private
+ */
+function elgg_get_upgrade_files($upgrade_path = null) {
+ if (!$upgrade_path) {
+ $upgrade_path = elgg_get_config('path') . 'engine/lib/upgrades/';
+ }
+ $upgrade_path = sanitise_filepath($upgrade_path);
+ $handle = opendir($upgrade_path);
+
+ if (!$handle) {
+ return false;
+ }
+
+ $upgrade_files = array();
+
+ while ($upgrade_file = readdir($handle)) {
+ // make sure this is a wellformed upgrade.
+ if (is_dir($upgrade_path . '$upgrade_file')) {
+ continue;
+ }
+ $upgrade_version = elgg_get_upgrade_file_version($upgrade_file);
+ if (!$upgrade_version) {
+ continue;
+ }
+ $upgrade_files[] = $upgrade_file;
+ }
+
+ sort($upgrade_files);
+
+ return $upgrade_files;
+}
+
+/**
+ * Get the current Elgg version information
+ *
+ * @param bool $humanreadable Whether to return a human readable version (default: false)
+ *
+ * @return string|false Depending on success
+ */
+function get_version($humanreadable = false) {
+ global $CONFIG;
+
+ static $version, $release;
+
+ if (isset($CONFIG->path)) {
+ if (!isset($version) || !isset($release)) {
+ if (!include($CONFIG->path . "version.php")) {
+ return false;
+ }
+ }
+ return (!$humanreadable) ? $version : $release;
+ }
+
+ return false;
+}
+
+/**
+ * Checks if any upgrades need to be run.
+ *
+ * @param null|array $upgrade_files Optional upgrade files
+ * @param null|array $processed_upgrades Optional processed upgrades
+ *
+ * @return array
+ * @access private
+ */
+function elgg_get_unprocessed_upgrades($upgrade_files = null, $processed_upgrades = null) {
+ if ($upgrade_files === null) {
+ $upgrade_files = elgg_get_upgrade_files();
+ }
+
+ if ($processed_upgrades === null) {
+ $processed_upgrades = unserialize(datalist_get('processed_upgrades'));
+ if (!is_array($processed_upgrades)) {
+ $processed_upgrades = array();
+ }
+ }
+
+ $unprocessed = array_diff($upgrade_files, $processed_upgrades);
+ return $unprocessed;
+}
+
+/**
+ * Determines whether or not the database needs to be upgraded.
+ *
+ * @return bool Depending on whether or not the db version matches the code version
+ * @access private
+ */
+function version_upgrade_check() {
+ $dbversion = (int) datalist_get('version');
+ $version = get_version();
+
+ if ($version > $dbversion) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ * Upgrades Elgg Database and code
+ *
+ * @return bool
+ * @access private
+ */
+function version_upgrade() {
+ // It's possible large upgrades could exceed the max execution time.
+ set_time_limit(0);
+
+ $dbversion = (int) datalist_get('version');
+
+ // No version number? Oh snap...this is an upgrade from a clean installation < 1.7.
+ // Run all upgrades without error reporting and hope for the best.
+ // See https://github.com/elgg/elgg/issues/1432 for more.
+ $quiet = !$dbversion;
+
+ // Note: Database upgrades are deprecated as of 1.8. Use code upgrades. See #1433
+ if (db_upgrade($dbversion, '', $quiet)) {
+ system_message(elgg_echo('upgrade:db'));
+ }
+
+ if (upgrade_code($dbversion, $quiet)) {
+ system_message(elgg_echo('upgrade:core'));
+
+ // Now we trigger an event to give the option for plugins to do something
+ $upgrade_details = new stdClass;
+ $upgrade_details->from = $dbversion;
+ $upgrade_details->to = get_version();
+
+ elgg_trigger_event('upgrade', 'upgrade', $upgrade_details);
+
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * Boot straps into 1.8 upgrade system from 1.7
+ *
+ * This runs all the 1.7 upgrades, then sets the processed_upgrades to all existing 1.7 upgrades.
+ * Control is then passed back to the main upgrade function which detects and runs the
+ * 1.8 upgrades, regardless of filename convention.
+ *
+ * @return bool
+ * @access private
+ */
+function elgg_upgrade_bootstrap_17_to_18() {
+ $db_version = (int) datalist_get('version');
+
+ // the 1.8 upgrades before the upgrade system change that are interspersed with 1.7 upgrades.
+ $upgrades_18 = array(
+ '2010111501.php',
+ '2010121601.php',
+ '2010121602.php',
+ '2010121701.php',
+ '2010123101.php',
+ '2011010101.php',
+ );
+
+ $upgrade_files = elgg_get_upgrade_files();
+ $processed_upgrades = array();
+
+ foreach ($upgrade_files as $upgrade_file) {
+ // ignore if not in 1.7 format or if it's a 1.8 upgrade
+ if (in_array($upgrade_file, $upgrades_18) || !preg_match("/[0-9]{10}\.php/", $upgrade_file)) {
+ continue;
+ }
+
+ $upgrade_version = elgg_get_upgrade_file_version($upgrade_file);
+
+ // this has already been run in a previous 1.7.X -> 1.7.X upgrade
+ if ($upgrade_version < $db_version) {
+ $processed_upgrades[] = $upgrade_file;
+ }
+ }
+
+ return elgg_set_processed_upgrades($processed_upgrades);
+}
+
+/**
+ * Creates a table {prefix}upgrade_lock that is used as a mutex for upgrades.
+ *
+ * @see _elgg_upgrade_lock()
+ *
+ * @return bool
+ * @access private
+ */
+function _elgg_upgrade_lock() {
+ global $CONFIG;
+
+ if (!_elgg_upgrade_is_locked()) {
+ // lock it
+ insert_data("create table {$CONFIG->dbprefix}upgrade_lock (id INT)");
+ elgg_log('Locked for upgrade.', 'NOTICE');
+ return true;
+ }
+
+ elgg_log('Cannot lock for upgrade: already locked.', 'WARNING');
+ return false;
+}
+
+/**
+ * Unlocks upgrade.
+ *
+ * @see _elgg_upgrade_lock()
+ *
+ * @access private
+ */
+function _elgg_upgrade_unlock() {
+ global $CONFIG;
+ delete_data("drop table {$CONFIG->dbprefix}upgrade_lock");
+ elgg_log('Upgrade unlocked.', 'NOTICE');
+}
+
+/**
+ * Checks if upgrade is locked
+ *
+ * @return bool
+ * @access private
+ */
+function _elgg_upgrade_is_locked() {
+ global $CONFIG;
+
+ $is_locked = count(get_data("show tables like '{$CONFIG->dbprefix}upgrade_lock'"));
+
+ // @todo why?
+ _elgg_invalidate_query_cache();
+
+ return $is_locked;
+}
diff --git a/engine/lib/upgrades/2008100701.php b/engine/lib/upgrades/2008100701.php
index cf976e84c..b8d4dfdbc 100644
--- a/engine/lib/upgrades/2008100701.php
+++ b/engine/lib/upgrades/2008100701.php
@@ -1,8 +1,7 @@
<?php
- /// Activate mail plugin
- /**
- * Because Elgg now has a plugable account activation process we need to activate
- * the email account activation plugin for existing installs.
- */
- enable_plugin('uservalidationbyemail', $CONFIG->site->guid);
-?> \ No newline at end of file
+
+/**
+ * Because Elgg now has a plugable account activation process we need to activate
+ * the email account activation plugin for existing installs.
+ */
+enable_plugin('uservalidationbyemail', $CONFIG->site->guid);
diff --git a/engine/lib/upgrades/2008101303.php b/engine/lib/upgrades/2008101303.php
index c98eace74..69e44e3a0 100644
--- a/engine/lib/upgrades/2008101303.php
+++ b/engine/lib/upgrades/2008101303.php
@@ -1,11 +1,9 @@
<?php
- // Upgrade to solve login issue
-
- if ($users = get_entities_from_metadata('validated_email', '', 'user', '', 0,9999)) {
- foreach($users as $user) {
- set_user_validation_status($user->guid, true, 'email');
- }
- }
-
-?> \ No newline at end of file
+// Upgrade to solve login issue
+
+if ($users = get_entities_from_metadata('validated_email', '', 'user', '', 0, 9999)) {
+ foreach ($users as $user) {
+ set_user_validation_status($user->guid, true, 'email');
+ }
+}
diff --git a/engine/lib/upgrades/2009022701.php b/engine/lib/upgrades/2009022701.php
index 92d540cd3..54083a34d 100644
--- a/engine/lib/upgrades/2009022701.php
+++ b/engine/lib/upgrades/2009022701.php
@@ -1,8 +1,7 @@
<?php
- global $CONFIG;
-
- /**
- * Disable update client since this has now been removed.
- */
- disable_plugin('updateclient', $CONFIG->site->guid);
-?> \ No newline at end of file
+global $CONFIG;
+
+/**
+ * Disable update client since this has now been removed.
+ */
+disable_plugin('updateclient', $CONFIG->site->guid);
diff --git a/engine/lib/upgrades/2009041701.php b/engine/lib/upgrades/2009041701.php
index 609c7e569..7b31a3bc9 100644
--- a/engine/lib/upgrades/2009041701.php
+++ b/engine/lib/upgrades/2009041701.php
@@ -1,10 +1,8 @@
<?php
- global $CONFIG;
-
- /// Activate kses
- /**
- * Elgg now has kses tag filtering built as a plugin. This needs to be enabled.
- */
- enable_plugin('kses', $CONFIG->site->guid);
-?> \ No newline at end of file
+global $CONFIG;
+
+/**
+ * Elgg now has kses tag filtering built as a plugin. This needs to be enabled.
+ */
+enable_plugin('kses', $CONFIG->site->guid);
diff --git a/engine/lib/upgrades/2009070101.php b/engine/lib/upgrades/2009070101.php
index edd8ce4b4..d0eae9b91 100644
--- a/engine/lib/upgrades/2009070101.php
+++ b/engine/lib/upgrades/2009070101.php
@@ -1,11 +1,9 @@
<?php
- global $CONFIG;
-
- /// Deprecate kses and activate htmlawed
- /**
- * Kses appears to be a dead project so we are deprecating it in favour of htmlawed.
- */
- disable_plugin('kses', $CONFIG->site->guid);
- enable_plugin('htmlawed', $CONFIG->site->guid);
-?> \ No newline at end of file
+global $CONFIG;
+
+/**
+ * Kses appears to be a dead project so we are deprecating it in favour of htmlawed.
+ */
+disable_plugin('kses', $CONFIG->site->guid);
+enable_plugin('htmlawed', $CONFIG->site->guid);
diff --git a/engine/lib/upgrades/2009102801.php b/engine/lib/upgrades/2009102801.php
index b72e0a781..3ad113fb2 100644
--- a/engine/lib/upgrades/2009102801.php
+++ b/engine/lib/upgrades/2009102801.php
@@ -1,154 +1,180 @@
<?php
-// disable timeout for large sites.
-set_time_limit(0);
+/**
+ * Move user's data directories from using username to registration date
+ */
/**
- Elgg 1.0
+ * Generates a file matrix like Elgg 1.0 did
+ *
+ * @param string $username Username of user
+ *
+ * @return string File matrix path
*/
-function file_matrix_1_0($username)
-{
+function file_matrix_1_0($username) {
$matrix = "";
-
+
$len = strlen($username);
- if ($len > 5)
+ if ($len > 5) {
$len = 5;
-
+ }
+
for ($n = 0; $n < $len; $n++) {
- if (ctype_alnum($username[$n]))
+ if (ctype_alnum($username[$n])) {
$matrix .= $username[$n] . "/";
- }
+ }
+ }
- return $matrix.$username."/";
+ return $matrix . $username . "/";
}
/**
- Elgg 1.1, 1.2 and 1.5
+ * Generate a file matrix like Elgg 1.1, 1.2 and 1.5
+ *
+ * @param string $filename The filename
+ *
+ * @return string
*/
-function file_matrix_1_1($filename)
-{
+function file_matrix_1_1($filename) {
$matrix = "";
-
+
$name = $filename;
$filename = mb_str_split($filename);
- if (!$filename) return false;
-
+ if (!$filename) {
+ return false;
+ }
+
$len = count($filename);
- if ($len > 5)
+ if ($len > 5) {
$len = 5;
-
+ }
+
for ($n = 0; $n < $len; $n++) {
$matrix .= $filename[$n] . "/";
- }
+ }
- return $matrix.$name."/";
+ return $matrix . $name . "/";
}
-function mb_str_split($string, $charset = 'UTF8')
-{
- if (is_callable('mb_substr'))
- {
+/**
+ * Handle splitting multibyte strings
+ *
+ * @param string $string String to split.
+ * @param string $charset Charset to use.
+ *
+ * @return array|false
+ */
+function mb_str_split($string, $charset = 'UTF8') {
+ if (is_callable('mb_substr')) {
$length = mb_strlen($string);
$array = array();
-
- while ($length)
- {
+
+ while ($length) {
$array[] = mb_substr($string, 0, 1, $charset);
$string = mb_substr($string, 1, $length, $charset);
-
+
$length = mb_strlen($string);
}
-
+
return $array;
- }
- else
+ } else {
return str_split($string);
-
+ }
+
return false;
}
/**
- Elgg 1.6
+ * 1.6 style file matrix
+ *
+ * @param string $filename The filename
+ *
+ * @return string
*/
-function file_matrix_1_6($filename)
-{
+function file_matrix_1_6($filename) {
$invalid_fs_chars = '*\'\\/"!$%^&*.%(){}[]#~?<>;|¬`@-+=';
-
+
$matrix = "";
-
+
$name = $filename;
$filename = mb_str_split($filename);
- if (!$filename) return false;
-
+ if (!$filename) {
+ return false;
+ }
+
$len = count($filename);
- if ($len > 5)
+ if ($len > 5) {
$len = 5;
-
+ }
+
for ($n = 0; $n < $len; $n++) {
-
+
// Prevent a matrix being formed with unsafe characters
$char = $filename[$n];
- if (strpos($invalid_fs_chars, $char)!==false)
+ if (strpos($invalid_fs_chars, $char) !== false) {
$char = '_';
-
+ }
+
$matrix .= $char . "/";
- }
+ }
- return $matrix.$name."/";
+ return $matrix . $name . "/";
}
/**
- * Scans a directory and moves any files from $from to $to
+ * Scans a directory and moves any files from $from to $to
* preserving structure and handling existing paths.
* Will no overwrite files in $to.
*
* TRAILING SLASHES REQUIRED.
*
- * @param $from From dir.
- * @param $to To dir.
- * @param $move Bool. True to move, false to copy.
- * @param $preference str to|from If file collisions, which dir has preference.
+ * @param string $from From dir.
+ * @param string $to To dir.
+ * @param bool $move True to move, false to copy.
+ * @param string $preference to|from If file collisions, which dir has preference.
+ *
+ * @return bool
*/
-function merge_directories($from, $to, $move=false, $preference='to') {
+function merge_directories($from, $to, $move = false, $preference = 'to') {
if (!$entries = scandir($from)) {
return false;
}
-
+
// character filtering needs to be elsewhere.
if (!is_dir($to)) {
mkdir($to, 0700, true);
}
-
+
if ($move === true) {
$f = 'rename';
} else {
$f = 'copy';
}
-
+
foreach ($entries as $entry) {
if ($entry == '.' || $entry == '..') {
continue;
}
-
+
$from_path = $from . $entry;
$to_path = $to . $entry;
-
+
// check to see if the path exists and is a dir, if so, recurse.
if (is_dir($from_path) && is_dir($to_path)) {
$from_path .= '/';
$to_path .= '/';
merge_directories($from_path, $to_path, $move, $preference);
-
+
// since it's a dir that already exists we don't need to move it
continue;
}
-
+
// only move if target doesn't exist or if preference is for the from dir
if (!file_exists($to_path) || $preference == 'from') {
-
+
if ($f($from_path, $to_path)) {
//elgg_dump("Moved/Copied $from_path to $to_path");
}
@@ -158,36 +184,39 @@ function merge_directories($from, $to, $move=false, $preference='to') {
}
}
+/**
+ * Create a 1.7 style user file matrix based upon date.
+ *
+ * @param int $guid Guid of owner
+ *
+ * @return string File matrix path
+ */
function user_file_matrix($guid) {
// lookup the entity
$user = get_entity($guid);
- if ($user->type != 'user')
- {
+ if ($user->type != 'user') {
// only to be used for user directories
return FALSE;
}
-
- if (!$user->time_created) {
- // fall back to deprecated method
- return $this->deprecated_file_matrix($user->username);
- }
-
+
$time_created = date('Y/m/d', $user->time_created);
return "$time_created/$user->guid/";
}
-global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE;
+global $ENTITY_CACHE, $CONFIG;
/**
- Upgrade file locations
+ * Upgrade file locations
*/
-$users = mysql_query("SELECT guid, username FROM {$CONFIG->dbprefix}users_entity WHERE username != ''");
+$users = mysql_query("SELECT guid, username
+ FROM {$CONFIG->dbprefix}users_entity WHERE username != ''");
while ($user = mysql_fetch_object($users)) {
- $DB_QUERY_CACHE = $DB_PROFILE = $ENTITY_CACHE = array();
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
$to = $CONFIG->dataroot . user_file_matrix($user->guid);
foreach (array('1_0', '1_1', '1_6') as $version) {
$function = "file_matrix_$version";
$from = $CONFIG->dataroot . $function($user->username);
- merge_directories($from, $to, $move=TRUE, $preference='from');
+ merge_directories($from, $to, $move = TRUE, $preference = 'from');
}
}
diff --git a/engine/lib/upgrades/2010033101.php b/engine/lib/upgrades/2010033101.php
index b137e0285..4779295fd 100644
--- a/engine/lib/upgrades/2010033101.php
+++ b/engine/lib/upgrades/2010033101.php
@@ -1,6 +1,7 @@
<?php
-/*
- * Conditional upgrade for UTF8 as described in http://trac.elgg.org/ticket/1928
+
+/**
+ * Conditional upgrade for UTF8 as described in https://github.com/elgg/elgg/issues/1928
*/
// get_version() returns the code version.
@@ -38,20 +39,24 @@ if ($dbversion < 2009100701) {
$qs[] = "ALTER TABLE {$CONFIG->dbprefix}groups_entity DISABLE KEYS";
$qs[] = "REPLACE INTO {$CONFIG->dbprefix}groups_entity (guid, name, description)
- SELECT guid, unhex(hex(convert(name using latin1))), unhex(hex(convert(description using latin1)))
+ SELECT guid, unhex(hex(convert(name using latin1))),
+ unhex(hex(convert(description using latin1)))
FROM {$CONFIG->dbprefix}groups_entity";
$qs[] = "ALTER TABLE {$CONFIG->dbprefix}groups_entity ENABLE KEYS";
$qs[] = "ALTER TABLE {$CONFIG->dbprefix}objects_entity DISABLE KEYS";
$qs[] = "REPLACE INTO {$CONFIG->dbprefix}objects_entity (guid, title, description)
- SELECT guid, unhex(hex(convert(title using latin1))), unhex(hex(convert(description using latin1)))
+ SELECT guid, unhex(hex(convert(title using latin1))),
+ unhex(hex(convert(description using latin1)))
FROM {$CONFIG->dbprefix}objects_entity";
$qs[] = "ALTER TABLE {$CONFIG->dbprefix}objects_entity ENABLE KEYS";
$qs[] = "ALTER TABLE {$CONFIG->dbprefix}users_entity DISABLE KEYS";
- $qs[] = "REPLACE INTO {$CONFIG->dbprefix}users_entity (guid, name, username, password, salt, email, language, code,
+ $qs[] = "REPLACE INTO {$CONFIG->dbprefix}users_entity
+ (guid, name, username, password, salt, email, language, code,
banned, last_action, prev_last_action, last_login, prev_last_login)
- SELECT guid, unhex(hex(convert(name using latin1))), username, password, salt, email, language, code,
+ SELECT guid, unhex(hex(convert(name using latin1))),
+ username, password, salt, email, language, code,
banned, last_action, prev_last_action, last_login, prev_last_login
FROM {$CONFIG->dbprefix}users_entity";
$qs[] = "ALTER TABLE {$CONFIG->dbprefix}users_entity ENABLE KEYS";
@@ -62,4 +67,4 @@ if ($dbversion < 2009100701) {
}
}
}
-} \ No newline at end of file
+}
diff --git a/engine/lib/upgrades/2010040201.php b/engine/lib/upgrades/2010040201.php
index 22eee15f8..789bf5dfc 100644
--- a/engine/lib/upgrades/2010040201.php
+++ b/engine/lib/upgrades/2010040201.php
@@ -1,4 +1,5 @@
<?php
+
/**
* Pull admin metadata setting into users_entity table column
*/
@@ -37,4 +38,4 @@ $qs[] = "DELETE FROM {$CONFIG->dbprefix}metadata
foreach ($qs as $q) {
update_data($q);
-} \ No newline at end of file
+}
diff --git a/engine/lib/upgrades/2010050701.php b/engine/lib/upgrades/2010050701.php
deleted file mode 100644
index 4a02a77c6..000000000
--- a/engine/lib/upgrades/2010050701.php
+++ /dev/null
@@ -1,17 +0,0 @@
-<?php
-/**
- * Removes the Walled Garden plugin in favor of new system settings
- */
-
-$access = elgg_set_ignore_access(TRUE);
-
-if (is_plugin_enabled('walledgarden')) {
- disable_plugin('walledgarden');
- set_config('allow_registration', FALSE);
- set_config('walled_garden', TRUE);
-} else {
- set_config('allow_registration', TRUE);
- set_config('walled_garden', FALSE);
-}
-
-elgg_set_ignore_access($access);
diff --git a/engine/lib/upgrades/2010052601.php b/engine/lib/upgrades/2010052601.php
index 5b477910f..a9cca6dc5 100644
--- a/engine/lib/upgrades/2010052601.php
+++ b/engine/lib/upgrades/2010052601.php
@@ -9,14 +9,14 @@ $params = array('type' => 'group',
$groups = elgg_get_entities($params);
if ($groups) {
foreach ($groups as $group) {
- $group->name = html_entity_decode($group->name, ENT_COMPAT, 'UTF-8');
- $group->description = html_entity_decode($group->description, ENT_COMPAT, 'UTF-8');
- $group->briefdescription = html_entity_decode($group->briefdescription, ENT_COMPAT, 'UTF-8');
- $group->website = html_entity_decode($group->website, ENT_COMPAT, 'UTF-8');
+ $group->name = _elgg_html_decode($group->name);
+ $group->description = _elgg_html_decode($group->description);
+ $group->briefdescription = _elgg_html_decode($group->briefdescription);
+ $group->website = _elgg_html_decode($group->website);
if ($group->interests) {
$tags = $group->interests;
- foreach ($tags as $index=>$tag) {
- $tags[$index] = html_entity_decode($tag, ENT_COMPAT, 'UTF-8');
+ foreach ($tags as $index => $tag) {
+ $tags[$index] = _elgg_html_decode($tag);
}
$group->interests = $tags;
}
diff --git a/engine/lib/upgrades/2010060101.php b/engine/lib/upgrades/2010060101.php
index 7772c42eb..bb7f7c1a6 100644
--- a/engine/lib/upgrades/2010060101.php
+++ b/engine/lib/upgrades/2010060101.php
@@ -10,7 +10,7 @@ delete_data($query);
if ($CONFIG->simplecache_enabled) {
datalist_set('simplecache_enabled', 1);
- elgg_view_regenerate_simplecache();
+ elgg_regenerate_simplecache();
} else {
datalist_set('simplecache_enabled', 0);
}
diff --git a/engine/lib/upgrades/2010060401.php b/engine/lib/upgrades/2010060401.php
index 2106bdbc0..6d628b8eb 100644
--- a/engine/lib/upgrades/2010060401.php
+++ b/engine/lib/upgrades/2010060401.php
@@ -11,7 +11,8 @@ $count = 0;
$user_guids = mysql_query("SELECT guid FROM {$CONFIG->dbprefix}users_entity");
while ($user = mysql_fetch_object($user_guids)) {
- $query = "SELECT * FROM {$CONFIG->dbprefix}entity_relationships WHERE guid_one=$user->guid AND relationship LIKE 'notify%'";
+ $query = "SELECT * FROM {$CONFIG->dbprefix}entity_relationships
+ WHERE guid_one=$user->guid AND relationship LIKE 'notify%'";
$relationships = mysql_query($query);
if (mysql_num_rows($relationships) == 0) {
// no notify relationships for this user
@@ -42,11 +43,12 @@ while ($user = mysql_fetch_object($user_guids)) {
WHERE guid_one=$user->guid AND relationship='$relationship_type'
AND guid_two=$obj->guid_two";
$results = mysql_query($query);
- if (mysql_num_rows($results) == 0) {
- $query = "DELETE FROM {$CONFIG->dbprefix}entity_relationships WHERE id=$obj->id";
- mysql_query($query);
- $count++;
- }
+
+ if (mysql_num_rows($results) == 0) {
+ $query = "DELETE FROM {$CONFIG->dbprefix}entity_relationships WHERE id=$obj->id";
+ mysql_query($query);
+ $count++;
+ }
}
}
diff --git a/engine/lib/upgrades/2010061501.php b/engine/lib/upgrades/2010061501.php
index 19d6467ed..744c28fd5 100644
--- a/engine/lib/upgrades/2010061501.php
+++ b/engine/lib/upgrades/2010061501.php
@@ -1,70 +1,75 @@
<?php
/**
- * utf8 conversion and file merging for usernames with multibyte chars
- *
+ * utf8 database conversion and file merging for usernames with multibyte chars
+ *
*/
// check that we need to do the utf8 conversion
// C&P logic from 2010033101
-set_time_limit(0);
$dbversion = (int) datalist_get('version');
if ($dbversion < 2009100701) {
// start a new link to the DB to see what its defaults are.
$link = mysql_connect($CONFIG->dbhost, $CONFIG->dbuser, $CONFIG->dbpass, TRUE);
mysql_select_db($CONFIG->dbname, $link);
-
+
$q = "SHOW VARIABLES LIKE 'character_set_client'";
$r = mysql_query($q);
$client = mysql_fetch_assoc($r);
-
+
$q = "SHOW VARIABLES LIKE 'character_set_connection'";
$r = mysql_query($q);
$connection = mysql_fetch_assoc($r);
-
+
// only run upgrade if not already talking utf8
if ($client['Value'] != 'utf8' && $connection['Value'] != 'utf8') {
$qs = array();
$qs[] = "SET NAMES utf8";
-
+
$qs[] = "ALTER TABLE {$CONFIG->dbprefix}users_entity DISABLE KEYS";
- $qs[] = "REPLACE INTO {$CONFIG->dbprefix}users_entity (guid, name, username, password, salt, email, language, code,
- banned, last_action, prev_last_action, last_login, prev_last_login)
- SELECT guid, name, unhex(hex(convert(username using latin1))), password, salt, email, language, code,
- banned, last_action, prev_last_action, last_login, prev_last_login
+ $qs[] = "REPLACE INTO {$CONFIG->dbprefix}users_entity
+ (guid, name, username, password, salt, email, language, code,
+ banned, admin, last_action, prev_last_action, last_login, prev_last_login)
+
+ SELECT guid, name, unhex(hex(convert(username using latin1))),
+ password, salt, email, language, code,
+ banned, admin, last_action, prev_last_action, last_login, prev_last_login
FROM {$CONFIG->dbprefix}users_entity";
-
+
$qs[] = "ALTER TABLE {$CONFIG->dbprefix}users_entity ENABLE KEYS";
-
+
foreach ($qs as $q) {
if (!update_data($q)) {
throw new Exception('Couldn\'t execute upgrade query: ' . $q);
}
}
-
- global $DB_QUERY_CACHE, $DB_PROFILE, $ENTITY_CACHE;
-
+
+ global $ENTITY_CACHE;
+
/**
Upgrade file locations
*/
// new connection to force into utf8 mode to get the old name
$link = mysql_connect($CONFIG->dbhost, $CONFIG->dbuser, $CONFIG->dbpass, TRUE);
mysql_select_db($CONFIG->dbname, $link);
-
+
// must be the first command
mysql_query("SET NAMES utf8");
-
- $users = mysql_query("SELECT guid, username FROM {$CONFIG->dbprefix}users_entity WHERE username != ''", $link);
+
+ $users = mysql_query("SELECT guid, username FROM {$CONFIG->dbprefix}users_entity
+ WHERE username != ''", $link);
while ($user = mysql_fetch_object($users)) {
- $DB_QUERY_CACHE = $DB_PROFILE = $ENTITY_CACHE = array();
-
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
+
+
$to = $CONFIG->dataroot . user_file_matrix($user->guid);
foreach (array('1_0', '1_1', '1_6') as $version) {
$function = "file_matrix_$version";
$from = $CONFIG->dataroot . $function($user->username);
- merge_directories($from, $to, $move=TRUE, $preference='from');
+ merge_directories($from, $to, $move = TRUE, $preference = 'from');
}
}
}
-} \ No newline at end of file
+}
diff --git a/engine/lib/upgrades/2010062301.php b/engine/lib/upgrades/2010062301.php
new file mode 100644
index 000000000..f679fa46d
--- /dev/null
+++ b/engine/lib/upgrades/2010062301.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * Change ownership of group ACLs to group entity
+ */
+
+elgg_set_ignore_access(TRUE);
+
+$params = array('type' => 'group',
+ 'limit' => 0);
+$groups = elgg_get_entities($params);
+if ($groups) {
+ foreach ($groups as $group) {
+ $acl = $group->group_acl;
+
+ try {
+ $query = "UPDATE {$CONFIG->dbprefix}access_collections
+ SET owner_guid = $group->guid WHERE id = $acl";
+ update_data($query);
+ } catch (Exception $e) {
+ // no acl so create one
+ $ac_name = elgg_echo('groups:group') . ": " . $group->name;
+ $group_acl = create_access_collection($ac_name, $group->guid);
+ if ($group_acl) {
+ create_metadata($group->guid, 'group_acl', $group_acl, 'integer', $group->owner_guid);
+ $object->group_acl = $group_id;
+ }
+ }
+
+ }
+}
+elgg_set_ignore_access(FALSE);
+
diff --git a/engine/lib/upgrades/2010062302.php b/engine/lib/upgrades/2010062302.php
new file mode 100644
index 000000000..fe33e12ea
--- /dev/null
+++ b/engine/lib/upgrades/2010062302.php
@@ -0,0 +1,33 @@
+<?php
+
+/**
+ * Make sure that everyone who belongs to a group is a member of the group's access collection
+ */
+
+
+elgg_set_ignore_access(TRUE);
+
+$params = array('type' => 'group', 'limit' => 0);
+$groups = elgg_get_entities($params);
+if ($groups) {
+ foreach ($groups as $group) {
+ $acl = $group->group_acl;
+
+ $query = "SELECT u.guid FROM {$CONFIG->dbprefix}users_entity u
+ JOIN {$CONFIG->dbprefix}entity_relationships r
+ ON u.guid = r.guid_one AND r.relationship = 'member' AND r.guid_two = $group->guid
+ LEFT JOIN {$CONFIG->dbprefix}access_collection_membership a
+ ON u.guid = a.user_guid AND a.access_collection_id = $acl
+ WHERE a.user_guid IS NULL";
+
+ $results = get_data($query);
+ if ($results != FALSE) {
+ foreach ($results as $user) {
+ $insert = "INSERT INTO {$CONFIG->dbprefix}access_collection_membership
+ (user_guid, access_collection_id) VALUES ($user->guid, $acl)";
+ insert_data($insert);
+ }
+ }
+ }
+}
+elgg_set_ignore_access(FALSE);
diff --git a/engine/lib/upgrades/2010070301.php b/engine/lib/upgrades/2010070301.php
new file mode 100644
index 000000000..af5c80419
--- /dev/null
+++ b/engine/lib/upgrades/2010070301.php
@@ -0,0 +1,9 @@
+<?php
+
+/**
+ * Group join river view has been renamed
+ */
+
+$query = "UPDATE {$CONFIG->dbprefix}river SET view='river/relationship/member/create'
+ WHERE view='river/group/create' AND action_type='join'";
+update_data($query);
diff --git a/engine/lib/upgrades/2010071001.php b/engine/lib/upgrades/2010071001.php
new file mode 100644
index 000000000..5594493a8
--- /dev/null
+++ b/engine/lib/upgrades/2010071001.php
@@ -0,0 +1,58 @@
+<?php
+/**
+ * Change profile image names to use guid rather than username
+ */
+
+/**
+ * Need the same function to generate a user matrix, but can't call it
+ * the same thing as the previous update.
+ *
+ * @param int $guid User guid.
+ *
+ * @return string File matrix
+ */
+function user_file_matrix_2010071001($guid) {
+ // lookup the entity
+ $user = get_entity($guid);
+ if ($user->type != 'user') {
+ // only to be used for user directories
+ return FALSE;
+ }
+
+ if (!$user->time_created) {
+ // no idea where this user has its files
+ return FALSE;
+ }
+
+ $time_created = date('Y/m/d', $user->time_created);
+ return "$time_created/$user->guid/";
+}
+
+$sizes = array('large', 'medium', 'small', 'tiny', 'master', 'topbar');
+
+global $ENTITY_CACHE, $CONFIG;
+$users = mysql_query("SELECT guid, username FROM {$CONFIG->dbprefix}users_entity
+ WHERE username != ''");
+while ($user = mysql_fetch_object($users)) {
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
+
+ $user_directory = user_file_matrix_2010071001($user->guid);
+ if (!$user_directory) {
+ continue;
+ }
+ $profile_directory = $CONFIG->dataroot . $user_directory . "profile/";
+ if (!file_exists($profile_directory)) {
+ continue;
+ }
+
+ foreach ($sizes as $size) {
+ $old_filename = "$profile_directory{$user->username}{$size}.jpg";
+ $new_filename = "$profile_directory{$user->guid}{$size}.jpg";
+ if (file_exists($old_filename)) {
+ if (!rename($old_filename, $new_filename)) {
+ error_log("Failed to rename profile photo for $user->username");
+ }
+ }
+ }
+}
diff --git a/engine/lib/upgrades/2010071002.php b/engine/lib/upgrades/2010071002.php
new file mode 100644
index 000000000..52aa15ef5
--- /dev/null
+++ b/engine/lib/upgrades/2010071002.php
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Update the notifications based on all friends and access collections
+ */
+
+// loop through all users checking collections and notifications
+global $ENTITY_CACHE, $CONFIG;
+global $NOTIFICATION_HANDLERS;
+$users = mysql_query("SELECT guid, username FROM {$CONFIG->dbprefix}users_entity
+ WHERE username != ''");
+while ($user = mysql_fetch_object($users)) {
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
+
+ $user = get_entity($user->guid);
+ foreach ($NOTIFICATION_HANDLERS as $method => $foo) {
+ $notify = "notify$method";
+ $metaname = "collections_notifications_preferences_$method";
+ $collections_preferences = $user->$metaname;
+ if (!$collections_preferences) {
+ continue;
+ }
+ if (!is_array($collections_preferences)) {
+ $collections_preferences = array($collections_preferences);
+ }
+ foreach ($collections_preferences as $collection_id) {
+ // check the all friends notifications
+ if ($collection_id == -1) {
+ $options = array(
+ 'relationship' => 'friend',
+ 'relationship_guid' => $user->guid,
+ 'limit' => 0
+ );
+ $friends = elgg_get_entities_from_relationship($options);
+ foreach ($friends as $friend) {
+ if (!check_entity_relationship($user->guid, $notify, $friend->guid)) {
+ add_entity_relationship($user->guid, $notify, $friend->guid);
+ }
+ }
+ } else {
+ $members = get_members_of_access_collection($collection_id, TRUE);
+ foreach ($members as $member) {
+ if (!check_entity_relationship($user->guid, $notify, $members)) {
+ add_entity_relationship($user->guid, $notify, $member);
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/engine/lib/upgrades/2010111501.php b/engine/lib/upgrades/2010111501.php
new file mode 100644
index 000000000..15e4a7d35
--- /dev/null
+++ b/engine/lib/upgrades/2010111501.php
@@ -0,0 +1,33 @@
+<?php
+/**
+ * Set validation metadata on unvalidated users to false rather than
+ * not existing. This is needed because of the change in how validation is
+ * being handled.
+ */
+
+// turn off system log because of all the metadata this can create
+elgg_unregister_event_handler('all', 'all', 'system_log_listener');
+elgg_unregister_event_handler('log', 'systemlog', 'system_log_default_logger');
+
+$ia = elgg_set_ignore_access(TRUE);
+$hidden_entities = access_get_show_hidden_status();
+access_show_hidden_entities(TRUE);
+
+$validated_id = get_metastring_id('validated');
+$one_id = get_metastring_id(1);
+
+$query = "SELECT guid FROM {$CONFIG->dbprefix}entities e
+ WHERE e.type = 'user' AND e.enabled = 'no' AND
+ NOT EXISTS (
+ SELECT 1 FROM {$CONFIG->dbprefix}metadata md
+ WHERE md.entity_guid = e.guid
+ AND md.name_id = $validated_id
+ AND md.value_id = $one_id)";
+
+$user_guids = mysql_query($query);
+while ($user_guid = mysql_fetch_object($user_guids)) {
+ create_metadata($user_guid->guid, 'validated', false, '', 0, ACCESS_PUBLIC, false);
+}
+
+access_show_hidden_entities($hidden_entities);
+elgg_set_ignore_access($ia);
diff --git a/engine/lib/upgrades/2010121601.php b/engine/lib/upgrades/2010121601.php
new file mode 100644
index 000000000..ad7d26adb
--- /dev/null
+++ b/engine/lib/upgrades/2010121601.php
@@ -0,0 +1,9 @@
+<?php
+/**
+ * Create friends river view has been changed
+ */
+
+$query = "UPDATE {$CONFIG->dbprefix}river
+ SET view='river/relationship/friend/create', action_type='create'
+ WHERE view='friends/river/create' AND action_type='friend'";
+update_data($query);
diff --git a/engine/lib/upgrades/2010121602.php b/engine/lib/upgrades/2010121602.php
new file mode 100644
index 000000000..5b0996b5e
--- /dev/null
+++ b/engine/lib/upgrades/2010121602.php
@@ -0,0 +1,10 @@
+<?php
+/**
+ * Create comment river view has been changed
+ */
+
+$query = "UPDATE {$CONFIG->dbprefix}river
+ SET view='river/annotation/generic_comment/create'
+ WHERE view='annotation/annotate' AND action_type='comment'";
+update_data($query);
+
diff --git a/engine/lib/upgrades/2010121701.php b/engine/lib/upgrades/2010121701.php
new file mode 100644
index 000000000..375654bac
--- /dev/null
+++ b/engine/lib/upgrades/2010121701.php
@@ -0,0 +1,10 @@
+<?php
+/**
+ * Create group forum topic river view has been changed
+ */
+
+$query = "UPDATE {$CONFIG->dbprefix}river
+ SET view='river/object/groupforumtopic/create'
+ WHERE view='river/forum/topic/create' AND action_type='create'";
+update_data($query);
+
diff --git a/engine/lib/upgrades/2010123101.php b/engine/lib/upgrades/2010123101.php
new file mode 100644
index 000000000..f4befd1a8
--- /dev/null
+++ b/engine/lib/upgrades/2010123101.php
@@ -0,0 +1,9 @@
+<?php
+/**
+ * Set default access for older sites
+ */
+
+$access = elgg_get_config('default_access');
+if ($access == false) {
+ elgg_save_config('default_access', ACCESS_LOGGED_IN);
+}
diff --git a/engine/lib/upgrades/2011010101.php b/engine/lib/upgrades/2011010101.php
new file mode 100644
index 000000000..f4411ee20
--- /dev/null
+++ b/engine/lib/upgrades/2011010101.php
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Migrate plugins to the new system using ElggPlugin and private settings
+ */
+
+$old_ia = elgg_set_ignore_access(true);
+
+$site = get_config('site');
+$old_plugin_order = unserialize($site->pluginorder);
+$old_enabled_plugins = $site->enabled_plugins;
+
+$db_prefix = get_config('dbprefix');
+$plugin_subtype_id = get_subtype_id('object', 'plugin');
+
+// easy one first: make sure the the site owns all plugin entities.
+$q = "UPDATE {$db_prefix}entities e
+ SET owner_guid = $site->guid, container_guid = $site->guid
+ WHERE e.type = 'object' AND e.subtype = $plugin_subtype_id";
+
+$r = update_data($q);
+
+// rewrite all plugin:setting:* to ELGG_PLUGIN_USER_SETTING_PREFIX . *
+$q = "UPDATE {$db_prefix}private_settings
+ SET name = replace(name, 'plugin:settings:', '" . ELGG_PLUGIN_USER_SETTING_PREFIX . "')
+ WHERE name LIKE 'plugin:settings:%'";
+
+$r = update_data($q);
+
+// grab current plugin GUIDs to add a temp priority
+$q = "SELECT * FROM {$db_prefix}entities e
+ JOIN {$db_prefix}objects_entity oe ON e.guid = oe.guid
+ WHERE e.type = 'object' AND e.subtype = $plugin_subtype_id";
+
+$plugins = get_data($q);
+
+foreach ($plugins as $plugin) {
+ $priority = elgg_namespace_plugin_private_setting('internal', 'priority');
+ set_private_setting($plugin->guid, $priority, 0);
+}
+
+// force regenerating plugin entities
+elgg_generate_plugin_entities();
+
+// set the priorities for all plugins
+// this function rewrites it to a normal index so use the current one.
+elgg_set_plugin_priorities($old_plugin_order);
+
+// add relationships for enabled plugins
+if ($old_enabled_plugins) {
+ // they might only have one plugin enabled.
+ if (!is_array($old_enabled_plugins)) {
+ $old_enabled_plugins = array($old_enabled_plugins);
+ }
+
+ // sometimes there were problems and you'd get 1000s of enabled plugins.
+ $old_enabled_plugins = array_unique($old_enabled_plugins);
+
+ foreach ($old_enabled_plugins as $plugin_id) {
+ $plugin = elgg_get_plugin_from_id($plugin_id);
+
+ if ($plugin) {
+ $plugin->activate();
+ }
+ }
+}
+
+// invalidate caches
+elgg_invalidate_simplecache();
+elgg_reset_system_cache();
+
+// clean up.
+remove_metadata($site->guid, 'pluginorder');
+remove_metadata($site->guid, 'enabled_plugins');
+
+elgg_set_ignore_access($old_id);
+
+/**
+ * @hack
+ *
+ * We stop the upgrade at this point because plugins weren't given the chance to
+ * load due to the new plugin code introduced with Elgg 1.8. Instead, we manually
+ * set the version and start the upgrade process again.
+ *
+ * The variables from upgrade_code() are available because this script was included
+ */
+if ($upgrade_version > $version) {
+ datalist_set('version', $upgrade_version);
+}
+
+// add ourselves to the processed_upgrades.
+$processed_upgrades[] = '2011010101.php';
+
+$processed_upgrades = array_unique($processed_upgrades);
+elgg_set_processed_upgrades($processed_upgrades);
+
+_elgg_upgrade_unlock();
+
+forward('upgrade.php');
diff --git a/engine/lib/upgrades/2011021800-1.8_svn-goodbye_walled_garden-083121a656d06894.php b/engine/lib/upgrades/2011021800-1.8_svn-goodbye_walled_garden-083121a656d06894.php
new file mode 100644
index 000000000..40b2c71d5
--- /dev/null
+++ b/engine/lib/upgrades/2011021800-1.8_svn-goodbye_walled_garden-083121a656d06894.php
@@ -0,0 +1,34 @@
+<?php
+/**
+ * Elgg 1.8-svn upgrade 2011021800
+ * goodbye_walled_garden
+ *
+ * Removes the Walled Garden plugin in favor of new system settings
+ */
+
+global $CONFIG;
+
+$access = elgg_set_ignore_access(TRUE);
+
+if (elgg_is_active_plugin('walledgarden')) {
+ disable_plugin('walledgarden');
+ set_config('allow_registration', FALSE);
+ set_config('walled_garden', TRUE);
+} else {
+ set_config('allow_registration', TRUE);
+ set_config('walled_garden', FALSE);
+}
+
+// this was for people who manually set the config option
+$disable_registration = elgg_get_config('disable_registration');
+if ($disable_registration !== null) {
+ $allow_registration = !$disable_registration;
+ elgg_save_config('allow_registration', $allow_registration);
+
+ $site = elgg_get_site_entity();
+ $query = "DELETE FROM {$CONFIG->dbprefix}config
+ WHERE name = 'disable_registration' AND site_guid = $site->guid";
+ delete_data($query);
+}
+
+elgg_set_ignore_access($access);
diff --git a/engine/lib/upgrades/2011022000-1.8_svn-custom_profile_fields-390ac967b0bb5665.php b/engine/lib/upgrades/2011022000-1.8_svn-custom_profile_fields-390ac967b0bb5665.php
new file mode 100644
index 000000000..7561b84ba
--- /dev/null
+++ b/engine/lib/upgrades/2011022000-1.8_svn-custom_profile_fields-390ac967b0bb5665.php
@@ -0,0 +1,59 @@
+<?php
+/**
+ * Elgg 2011010401 upgrade 00
+ * custom_profile_fields
+ *
+ * Migrate 1.7 style custom profile fields to 1.8
+ */
+
+$plugin = elgg_get_plugin_from_id('profile');
+
+// plugin not installed
+if (!$plugin) {
+ return true;
+}
+
+$settings = $plugin->getAllSettings();
+// no fields to migrate
+if (!$settings['user_defined_fields']) {
+ return true;
+}
+
+$order = array();
+$remove_settings = array();
+
+// make sure we have a name and type
+foreach ($settings as $k => $v) {
+ if (!preg_match('/admin_defined_profile_([0-9]+)/i', $k, $matches)) {
+ continue;
+ }
+
+ $i = $matches[1];
+ $type_name = "admin_defined_profile_type_$i";
+ $type = elgg_extract($type_name, $settings, null);
+
+ if ($type) {
+ // field name
+ elgg_save_config($k, $v);
+ // field value
+ elgg_save_config($type_name, $type);
+
+ $order[] = $i;
+ $remove_settings[] = $k;
+ $remove_settings[] = $type_name;
+ }
+}
+
+if ($order) {
+ // these will always need to be in order, but there might be gaps
+ ksort($order);
+
+ $order_str = implode(',', $order);
+ elgg_save_config('profile_custom_fields', $order_str);
+
+ foreach ($remove_settings as $name) {
+ $plugin->unsetSetting($name);
+ }
+
+ $plugin->unsetSetting('user_defined_fields');
+} \ No newline at end of file
diff --git a/engine/lib/upgrades/2011030700-1.8_svn-blog_status_metadata-4645225d7b440876.php b/engine/lib/upgrades/2011030700-1.8_svn-blog_status_metadata-4645225d7b440876.php
new file mode 100644
index 000000000..fe2af9928
--- /dev/null
+++ b/engine/lib/upgrades/2011030700-1.8_svn-blog_status_metadata-4645225d7b440876.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Elgg 1.8-svn upgrade 2011030700
+ * blog_status_metadata
+ *
+ * Add a "status" metadata entry to every blog entity because in 1.8 you can have status = draft or
+ * status = published
+ */
+$ia = elgg_set_ignore_access(true);
+$options = array(
+ 'type' => 'object',
+ 'subtype' => 'blog',
+ 'limit' => 0,
+);
+$batch = new ElggBatch('elgg_get_entities', $options);
+
+foreach ($batch as $entity) {
+ if (!$entity->status) {
+ // create metadata owned by the original owner
+ create_metadata($entity->getGUID(), 'status', 'published', '', $entity->owner_guid,
+ $entity->access_id);
+ }
+}
+elgg_set_ignore_access($ia); \ No newline at end of file
diff --git a/engine/lib/upgrades/2011031300-1.8_svn-twitter_api-12b832a5a7a3e1bd.php b/engine/lib/upgrades/2011031300-1.8_svn-twitter_api-12b832a5a7a3e1bd.php
new file mode 100644
index 000000000..df60892a6
--- /dev/null
+++ b/engine/lib/upgrades/2011031300-1.8_svn-twitter_api-12b832a5a7a3e1bd.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Elgg 1.8-svn upgrade 2011031300
+ * twitter_api
+ *
+ * Updates the database for twitterservice to twitter_api changes.
+ */
+
+
+$ia = elgg_set_ignore_access(true);
+
+// make sure we have updated plugins
+elgg_generate_plugin_entities();
+
+$show_hidden = access_get_show_hidden_status();
+access_show_hidden_entities(true);
+
+$db_prefix = elgg_get_config('dbprefix');
+$site_guid = elgg_get_site_entity()->getGUID();
+$old = elgg_get_plugin_from_id('twitterservice');
+$new = elgg_get_plugin_from_id('twitter_api');
+$has_settings = false;
+
+// if not loaded, don't bother.
+if (!$old || !$new) {
+ return true;
+}
+
+$settings = array('consumer_key', 'consumer_secret', 'sign_on', 'new_users');
+
+foreach ($settings as $setting) {
+ $value = $old->getSetting($setting);
+ if ($value) {
+ $has_settings = true;
+ $new->setSetting($setting, $value);
+ }
+}
+
+// update the user settings
+$q = "UPDATE {$db_prefix}private_settings
+ SET name = replace(name, 'twitterservice', 'twitter_api')
+ WHERE name like '%twitterservice%'";
+
+update_data($q);
+
+// if there were settings, emit a notice to re-enable twitter_api
+if ($has_settings) {
+ elgg_add_admin_notice('twitter_api:disabled', elgg_echo('update:twitter_api:deactivated'));
+}
+
+$old->delete();
+
+access_show_hidden_entities($show_hidden);
+elgg_set_ignore_access($ia); \ No newline at end of file
diff --git a/engine/lib/upgrades/2011031600-1.8_svn-datalist_grows_up-0b8aec5a55cc1e1c.php b/engine/lib/upgrades/2011031600-1.8_svn-datalist_grows_up-0b8aec5a55cc1e1c.php
new file mode 100644
index 000000000..379244b36
--- /dev/null
+++ b/engine/lib/upgrades/2011031600-1.8_svn-datalist_grows_up-0b8aec5a55cc1e1c.php
@@ -0,0 +1,18 @@
+<?php
+/**
+ * Elgg 1.8-svn upgrade 2011031600
+ * datalist_grows_up
+ *
+ * Ups the varchar to 256 for the datalist and config table.
+ *
+ * Keeping it as a varchar because of the trailing whitespace trimming it apparently does:
+ * http://dev.mysql.com/doc/refman/5.0/en/char.html
+ */
+
+$db_prefix = elgg_get_config('dbprefix');
+
+$q = "ALTER TABLE {$db_prefix}datalists CHANGE name name VARCHAR(255)";
+update_data($q);
+
+$q = "ALTER TABLE {$db_prefix}config CHANGE name name VARCHAR(255)";
+update_data($q);
diff --git a/engine/lib/upgrades/2011032000-1.8_svn-widgets_arent_plugins-61836261fa280a5c.php b/engine/lib/upgrades/2011032000-1.8_svn-widgets_arent_plugins-61836261fa280a5c.php
new file mode 100644
index 000000000..a20970d79
--- /dev/null
+++ b/engine/lib/upgrades/2011032000-1.8_svn-widgets_arent_plugins-61836261fa280a5c.php
@@ -0,0 +1,10 @@
+<?php
+/**
+ * Elgg 1.8-svn upgrade 2011031800
+ * widgets_arent_plugins
+ *
+ * At some point in Elgg's history subtype widget was registered with class ElggPlugin.
+ * Fix that.
+ */
+
+update_subtype('object', 'widget', 'ElggWidget');
diff --git a/engine/lib/upgrades/2011032200-1.8_svn-admins_like_widgets-7f19d2783c1680d3.php b/engine/lib/upgrades/2011032200-1.8_svn-admins_like_widgets-7f19d2783c1680d3.php
new file mode 100644
index 000000000..592adb403
--- /dev/null
+++ b/engine/lib/upgrades/2011032200-1.8_svn-admins_like_widgets-7f19d2783c1680d3.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Elgg 1.8-svn upgrade 2011032200
+ * admins_like_widgets
+ *
+ * Give current admins widgets for those pre-1.8
+ */
+
+$admins = elgg_get_admins(array('limit' => 0));
+foreach ($admins as $admin) {
+ // call the admin handler for the make_admin event
+ elgg_add_admin_widgets('make_admin', 'user', $admin);
+}
diff --git a/engine/lib/upgrades/2011052801.php b/engine/lib/upgrades/2011052801.php
new file mode 100644
index 000000000..b5a8e1018
--- /dev/null
+++ b/engine/lib/upgrades/2011052801.php
@@ -0,0 +1,46 @@
+<?php
+/**
+ * Make sure all users have the relationship member_of_site
+ */
+global $ENTITY_CACHE;
+$db_prefix = get_config('dbprefix');
+
+$limit = 100;
+
+$q = "SELECT e.* FROM {$db_prefix}entities e
+ WHERE e.type = 'user' AND e.guid NOT IN (
+ SELECT guid_one FROM {$db_prefix}entity_relationships
+ WHERE guid_two = 1 AND relationship = 'member_of_site'
+ )
+ LIMIT $limit";
+
+$users = get_data($q);
+
+while ($users) {
+ $ENTITY_CACHE = array();
+ _elgg_invalidate_query_cache();
+
+ // do manually to not trigger any events because these aren't new users.
+ foreach ($users as $user) {
+ $rel_q = "INSERT INTO {$db_prefix}entity_relationships VALUES (
+ '',
+ '$user->guid',
+ 'member_of_site',
+ '$user->site_guid',
+ '$user->time_created'
+ )";
+
+ insert_data($rel_q);
+ }
+
+ // every time we run this query we've just reduced the rows it returns by $limit
+ // so don't pass an offset.
+ $q = "SELECT e.* FROM {$db_prefix}entities e
+ WHERE e.type = 'user' AND e.guid NOT IN (
+ SELECT guid_one FROM {$db_prefix}entity_relationships
+ WHERE guid_two = 1 AND relationship = 'member_of_site'
+ )
+ LIMIT $limit";
+
+ $users = get_data($q);
+} \ No newline at end of file
diff --git a/engine/lib/upgrades/2011061200-1.8b1-sites_need_a_site_guid-6d9dcbf46c0826cc.php b/engine/lib/upgrades/2011061200-1.8b1-sites_need_a_site_guid-6d9dcbf46c0826cc.php
new file mode 100644
index 000000000..41ab29998
--- /dev/null
+++ b/engine/lib/upgrades/2011061200-1.8b1-sites_need_a_site_guid-6d9dcbf46c0826cc.php
@@ -0,0 +1,31 @@
+<?php
+/**
+ * Elgg 1.8b1 upgrade 2011061200
+ * sites_need_a_site_guid
+ *
+ * Sites did not have a site guid. This causes problems with getting
+ * metadata on site objects since we default to the current site.
+ */
+
+global $CONFIG;
+
+$ia = elgg_set_ignore_access(true);
+$access_status = access_get_show_hidden_status();
+access_show_hidden_entities(true);
+
+$options = array(
+ 'type' => 'site',
+ 'site_guid' => 0,
+ 'limit' => 0,
+);
+$batch = new ElggBatch('elgg_get_entities', $options);
+
+foreach ($batch as $entity) {
+ if (!$entity->site_guid) {
+ update_data("UPDATE {$CONFIG->dbprefix}entities SET site_guid=$entity->guid
+ WHERE guid=$entity->guid");
+ }
+}
+
+access_show_hidden_entities($access_status);
+elgg_set_ignore_access($ia);
diff --git a/engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php b/engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php
new file mode 100644
index 000000000..3a9200b51
--- /dev/null
+++ b/engine/lib/upgrades/2011092500-1.8.0.1-forum_reply_river_view-5758ce8d86ac56ce.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Elgg 1.8.0.1 upgrade 2011092500
+ * forum_reply_river_view
+ *
+ * The forum reply river view is in a new location in Elgg 1.8
+ */
+
+$query = "UPDATE {$CONFIG->dbprefix}river SET view='river/annotation/group_topic_post/reply',
+ action_type='reply'
+ WHERE view='river/forum/create' AND action_type='create'";
+update_data($query);
diff --git a/engine/lib/upgrades/2011123100-1.8.2-fix_friend_river-b17e7ff8345c2269.php b/engine/lib/upgrades/2011123100-1.8.2-fix_friend_river-b17e7ff8345c2269.php
new file mode 100644
index 000000000..4dc43cd32
--- /dev/null
+++ b/engine/lib/upgrades/2011123100-1.8.2-fix_friend_river-b17e7ff8345c2269.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Elgg 1.8.2 upgrade 2011123100
+ * fix_friend_river
+ *
+ * Action type was incorrect due to previoud friends river upgrade
+ */
+
+$query = "UPDATE {$CONFIG->dbprefix}river
+ SET action_type='friend'
+ WHERE view='river/relationship/friend/create' AND action_type='create'";
+update_data($query);
diff --git a/engine/lib/upgrades/2011123101-1.8.2-fix_blog_status-b14c2a0e7b9e7d55.php b/engine/lib/upgrades/2011123101-1.8.2-fix_blog_status-b14c2a0e7b9e7d55.php
new file mode 100644
index 000000000..e351c6ac9
--- /dev/null
+++ b/engine/lib/upgrades/2011123101-1.8.2-fix_blog_status-b14c2a0e7b9e7d55.php
@@ -0,0 +1,25 @@
+<?php
+/**
+ * Elgg 1.8.2 upgrade 2011123101
+ * fix_blog_status
+ *
+ * Most blog posts did not have their status properly set with 1.8 upgrade so we run
+ * the blog status upgrade again
+ */
+
+$ia = elgg_set_ignore_access(true);
+$options = array(
+ 'type' => 'object',
+ 'subtype' => 'blog',
+ 'limit' => 0,
+);
+$batch = new ElggBatch('elgg_get_entities', $options);
+
+foreach ($batch as $entity) {
+ if (!$entity->status) {
+ // create metadata owned by the original owner
+ create_metadata($entity->getGUID(), 'status', 'published', '', $entity->owner_guid,
+ $entity->access_id);
+ }
+}
+elgg_set_ignore_access($ia); \ No newline at end of file
diff --git a/engine/lib/upgrades/2012012000-1.8.3-ip_in_syslog-87fe0f068cf62428.php b/engine/lib/upgrades/2012012000-1.8.3-ip_in_syslog-87fe0f068cf62428.php
new file mode 100644
index 000000000..b9514e156
--- /dev/null
+++ b/engine/lib/upgrades/2012012000-1.8.3-ip_in_syslog-87fe0f068cf62428.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Elgg 1.8.3 upgrade 2012012000
+ * ip_in_syslog
+ *
+ * Adds a field for an IP address in the system log table
+ */
+
+$db_prefix = elgg_get_config('dbprefix');
+$q = "ALTER TABLE {$db_prefix}system_log ADD ip_address VARCHAR(15) NOT NULL AFTER time_created";
+
+update_data($q); \ No newline at end of file
diff --git a/engine/lib/upgrades/2012012100-1.8.3-system_cache-93100e7d55a24a11.php b/engine/lib/upgrades/2012012100-1.8.3-system_cache-93100e7d55a24a11.php
new file mode 100644
index 000000000..3a9aae2a1
--- /dev/null
+++ b/engine/lib/upgrades/2012012100-1.8.3-system_cache-93100e7d55a24a11.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Elgg 1.8.3 upgrade 2012012100
+ * system_cache
+ *
+ * Convert viewpath cache to system cache
+ */
+
+$value = datalist_get('viewpath_cache_enabled');
+datalist_set('system_cache_enabled', $value);
+
+$query = "DELETE FROM {$CONFIG->dbprefix}datalists WHERE name='viewpath_cache_enabled'";
+delete_data($query);
diff --git a/engine/lib/upgrades/2012041800-1.8.3-dont_filter_passwords-c0ca4a18b38ae2bc.php b/engine/lib/upgrades/2012041800-1.8.3-dont_filter_passwords-c0ca4a18b38ae2bc.php
new file mode 100644
index 000000000..b82ffbebf
--- /dev/null
+++ b/engine/lib/upgrades/2012041800-1.8.3-dont_filter_passwords-c0ca4a18b38ae2bc.php
@@ -0,0 +1,11 @@
+<?php
+/**
+ * Elgg 1.8.3 upgrade 2012041800
+ * dont_filter_passwords
+ *
+ * Add admin notice that password handling has changed and if
+ * users can't login to have them reset their passwords.
+ */
+elgg_add_admin_notice('dont_filter_passwords', 'Password handling has been updated to be more secure and flexible. '
+ . 'This change may prevent a small number of users from logging in with their existing passwords. '
+ . 'If a user is unable to log in, please advise him or her to reset their password, or reset it as an admin user.');
diff --git a/engine/lib/upgrades/2012041801-1.8.3-multiple_user_tokens-852225f7fd89f6c5.php b/engine/lib/upgrades/2012041801-1.8.3-multiple_user_tokens-852225f7fd89f6c5.php
new file mode 100644
index 000000000..780038c32
--- /dev/null
+++ b/engine/lib/upgrades/2012041801-1.8.3-multiple_user_tokens-852225f7fd89f6c5.php
@@ -0,0 +1,13 @@
+<?php
+/**
+ * Elgg 1.8.3 upgrade 2012041801
+ * multiple_user_tokens
+ *
+ * Fixes https://github.com/elgg/elgg/issues/4291
+ * Removes the unique index on users_apisessions for user_guid and site_guid
+ */
+
+$db_prefix = elgg_get_config('dbprefix');
+$q = "ALTER TABLE {$db_prefix}users_apisessions DROP INDEX user_guid,
+ ADD INDEX user_guid (user_guid, site_guid)";
+update_data($q); \ No newline at end of file
diff --git a/engine/lib/upgrades/2013030600-1.8.13-update_user_location-8999eb8bf1bdd9a3.php b/engine/lib/upgrades/2013030600-1.8.13-update_user_location-8999eb8bf1bdd9a3.php
new file mode 100644
index 000000000..8eccf05e2
--- /dev/null
+++ b/engine/lib/upgrades/2013030600-1.8.13-update_user_location-8999eb8bf1bdd9a3.php
@@ -0,0 +1,24 @@
+<?php
+/**
+ * Elgg 1.8.14 upgrade 2013030600
+ * update_user_location
+ *
+ * Before Elgg 1.8, a location like "London, England" would be stored as an array.
+ * This script turns that back into a string.
+ */
+
+$ia = elgg_set_ignore_access(true);
+$options = array(
+ 'type' => 'user',
+ 'limit' => 0,
+);
+$batch = new ElggBatch('elgg_get_entities', $options);
+
+foreach ($batch as $entity) {
+ _elgg_invalidate_query_cache();
+
+ if (is_array($entity->location)) {
+ $entity->location = implode(', ', $entity->location);
+ }
+}
+elgg_set_ignore_access($ia);
diff --git a/engine/lib/upgrades/2013051700-1.8.15-add_missing_group_index-52a63a3a3ffaced2.php b/engine/lib/upgrades/2013051700-1.8.15-add_missing_group_index-52a63a3a3ffaced2.php
new file mode 100644
index 000000000..ee99bdbc8
--- /dev/null
+++ b/engine/lib/upgrades/2013051700-1.8.15-add_missing_group_index-52a63a3a3ffaced2.php
@@ -0,0 +1,28 @@
+<?php
+/**
+ * Elgg 1.8.15 upgrade 2013051700
+ * add_missing_group_index
+ *
+ * Some Elgg sites are missing the groups_entity full text index on name and
+ * description. This checks if it exists and adds it if it does not.
+ */
+
+$db_prefix = elgg_get_config('dbprefix');
+
+$full_text_index_exists = false;
+$results = get_data("SHOW INDEX FROM {$db_prefix}groups_entity");
+if ($results) {
+ foreach ($results as $result) {
+ if ($result->Index_type === 'FULLTEXT') {
+ $full_text_index_exists = true;
+ }
+ }
+}
+
+if ($full_text_index_exists == false) {
+ $query = "ALTER TABLE {$db_prefix}groups_entity
+ ADD FULLTEXT name_2 (name, description)";
+ if (!update_data($query)) {
+ elgg_log("Failed to add full text index to groups_entity table", 'ERROR');
+ }
+}
diff --git a/engine/lib/upgrades/2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php b/engine/lib/upgrades/2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php
new file mode 100644
index 000000000..d333a6cd2
--- /dev/null
+++ b/engine/lib/upgrades/2013052900-1.8.15-ipv6_in_syslog-f5c2cc0196e9e731.php
@@ -0,0 +1,12 @@
+<?php
+/**
+ * Elgg 1.8.15 upgrade 2013052900
+ * ipv6_in_syslog
+ *
+ * Upgrade the ip column in system_log to be able to store ipv6 addresses
+ */
+
+$db_prefix = elgg_get_config('dbprefix');
+$q = "ALTER TABLE {$db_prefix}system_log MODIFY COLUMN ip_address varchar(46) NOT NULL";
+
+update_data($q); \ No newline at end of file
diff --git a/engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php b/engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php
new file mode 100644
index 000000000..538d74dd6
--- /dev/null
+++ b/engine/lib/upgrades/2013060900-1.8.15-site_secret-404fc165cf9e0ac9.php
@@ -0,0 +1,16 @@
+<?php
+/**
+ * Elgg 1.8.15 upgrade 2013060900
+ * site_secret
+ *
+ * Description
+ */
+
+$strength = _elgg_get_site_secret_strength();
+
+if ($strength !== 'strong') {
+ // a new key is needed immediately
+ register_translations(elgg_get_root_path() . 'languages/');
+
+ elgg_add_admin_notice('weak_site_key', elgg_echo("upgrade:site_secret_warning:$strength"));
+}
diff --git a/engine/lib/upgrades/create_upgrade.php b/engine/lib/upgrades/create_upgrade.php
new file mode 100644
index 000000000..b34f31b7e
--- /dev/null
+++ b/engine/lib/upgrades/create_upgrade.php
@@ -0,0 +1,152 @@
+<?php
+/**
+ * Creates an upgrade file for Elgg.
+ *
+ * Run this from the command line:
+ * php create_upgrade.php upgrade_name
+ */
+
+error_reporting(E_NOTICE);
+
+// only allow from the command line.
+if (php_sapi_name() != 'cli') {
+ die('Upgrades can only be created from the command line.');
+}
+
+if (count($argv) < 2) {
+ elgg_create_upgrade_show_usage('No upgrade name.');
+}
+
+$name = $argv[1];
+
+if (strlen($name) > 24) {
+ elgg_create_upgrade_show_usage('Upgrade names cannot be longer than 24 characters.');
+}
+
+require_once '../../../version.php';
+require_once '../elgglib.php';
+$upgrade_path = dirname(__FILE__);
+
+$upgrade_name = strtolower($name);
+$upgrade_name = str_replace(array(' ', '-'), '_', $upgrade_name);
+$upgrade_release = str_replace(array(' ', '-'), '_', $release);
+$time = time();
+$upgrade_rnd = substr(md5($time), 0, 16);
+$upgrade_date = date('Ymd', $time);
+
+// determine the inc count
+$upgrade_inc = 0;
+$files = elgg_get_file_list($upgrade_path);
+sort($files);
+
+foreach ($files as $filename) {
+ $filename = basename($filename);
+ $date = (int)substr($filename, 0, 8);
+ $inc = (int)substr($filename, 8, 2);
+
+ if ($upgrade_date == $date) {
+ if ($inc >= $upgrade_inc) {
+ $upgrade_inc = $inc + 1;
+ }
+ }
+}
+
+// zero-pad
+// if there are more than 10 upgrades in a day, someone needs talking to.
+if ($upgrade_inc < 10) {
+ $upgrade_inc = "0$upgrade_inc";
+}
+
+$upgrade_version = $upgrade_date . $upgrade_inc;
+
+// make filename
+if (substr($release, 0, 3) == '1.7') {
+ // 1.7 upgrades are YYYYMMDDXX
+ $upgrade_name = $upgrade_version . '.php';
+} else {
+ // 1.8+ upgrades are YYYYMMDDXX-release-friendly_name-rnd
+ $upgrade_name = $upgrade_version . "-$upgrade_release-$name-$upgrade_rnd.php";
+}
+
+$upgrade_file = $upgrade_path . '/' . $upgrade_name;
+
+if (is_file($upgrade_file)) {
+ elgg_create_upgrade_show_usage("Upgrade file $upgrade_file already exists. This script has failed you.");
+}
+
+$upgrade_code = <<<___UPGRADE
+<?php
+/**
+ * Elgg $release upgrade $upgrade_version
+ * $name
+ *
+ * Description
+ */
+
+// upgrade code here.
+
+___UPGRADE;
+
+$h = fopen($upgrade_file, 'wb');
+
+if (!$h) {
+ die("Could not open file $upgrade_file");
+}
+
+if (!fwrite($h, $upgrade_code)) {
+ die("Could not write to $upgrade_file");
+} else {
+ elgg_set_version_dot_php_version($upgrade_version);
+ echo <<<___MSG
+
+Created upgrade file and updated version.php.
+
+Upgrade file: $upgrade_name
+Version: $upgrade_version
+
+___MSG;
+}
+
+fclose($h);
+
+
+function elgg_set_version_dot_php_version($version) {
+ $file = '../../../version.php';
+ $h = fopen($file, 'r+b');
+
+ if (!$h) {
+ return false;
+ }
+
+ $out = '';
+
+ while (($line = fgets($h)) !== false) {
+ $find = "/\\\$version[ ]?=[ ]?[0-9]{10};/";
+ $replace = "\$version = $version;";
+ $out .= preg_replace($find, $replace, $line);
+ }
+
+ rewind($h);
+
+ fwrite($h, $out);
+ fclose($h);
+ return true;
+}
+
+/**
+ * Shows the usage for the create_upgrade script and dies().
+ *
+ * @param string $msg Optional message to display
+ * @return void
+ */
+function elgg_create_upgrade_show_usage($msg = '') {
+ $text = <<<___MSG
+$msg
+
+Example:
+ php create_upgrade.php my_upgrade
+
+___MSG;
+
+ die($text);
+}
diff --git a/engine/lib/user_settings.php b/engine/lib/user_settings.php
new file mode 100644
index 000000000..0e36dc46d
--- /dev/null
+++ b/engine/lib/user_settings.php
@@ -0,0 +1,360 @@
+<?php
+/**
+ * Elgg user settings functions.
+ * Functions for adding and manipulating options on the user settings panel.
+ *
+ * @package Elgg.Core
+ * @subpackage Settings.User
+ */
+
+/**
+ * Saves user settings.
+ *
+ * @todo this assumes settings are coming in on a GET/POST request
+ *
+ * @note This is a handler for the 'usersettings:save', 'user' plugin hook
+ *
+ * @return void
+ * @access private
+ */
+function users_settings_save() {
+ elgg_set_user_language();
+ elgg_set_user_password();
+ elgg_set_user_default_access();
+ elgg_set_user_name();
+ elgg_set_user_email();
+}
+
+/**
+ * Set a user's password
+ *
+ * @return bool
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_set_user_password() {
+ $current_password = get_input('current_password', null, false);
+ $password = get_input('password', null, false);
+ $password2 = get_input('password2', null, false);
+ $user_guid = get_input('guid');
+
+ if (!$user_guid) {
+ $user = elgg_get_logged_in_user_entity();
+ } else {
+ $user = get_entity($user_guid);
+ }
+
+ if ($user && $password) {
+ // let admin user change anyone's password without knowing it except his own.
+ if (!elgg_is_admin_logged_in() || elgg_is_admin_logged_in() && $user->guid == elgg_get_logged_in_user_guid()) {
+ $credentials = array(
+ 'username' => $user->username,
+ 'password' => $current_password
+ );
+
+ try {
+ pam_auth_userpass($credentials);
+ } catch (LoginException $e) {
+ register_error(elgg_echo('LoginException:ChangePasswordFailure'));
+ return false;
+ }
+ }
+
+ try {
+ $result = validate_password($password);
+ } catch (RegistrationException $e) {
+ register_error($e->getMessage());
+ return false;
+ }
+
+ if ($result) {
+ if ($password == $password2) {
+ $user->salt = generate_random_cleartext_password(); // Reset the salt
+ $user->password = generate_user_password($user, $password);
+ if ($user->save()) {
+ system_message(elgg_echo('user:password:success'));
+ return true;
+ } else {
+ register_error(elgg_echo('user:password:fail'));
+ }
+ } else {
+ register_error(elgg_echo('user:password:fail:notsame'));
+ }
+ } else {
+ register_error(elgg_echo('user:password:fail:tooshort'));
+ }
+ } else {
+ // no change
+ return null;
+ }
+
+ return false;
+}
+
+/**
+ * Set a user's display name
+ *
+ * @return bool
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_set_user_name() {
+ $name = strip_tags(get_input('name'));
+ $user_id = get_input('guid');
+
+ if (!$user_id) {
+ $user = elgg_get_logged_in_user_entity();
+ } else {
+ $user = get_entity($user_id);
+ }
+
+ if (elgg_strlen($name) > 50) {
+ register_error(elgg_echo('user:name:fail'));
+ return false;
+ }
+
+ if (($user) && ($user->canEdit()) && ($name)) {
+ if ($name != $user->name) {
+ $user->name = $name;
+ if ($user->save()) {
+ system_message(elgg_echo('user:name:success'));
+ return true;
+ } else {
+ register_error(elgg_echo('user:name:fail'));
+ }
+ } else {
+ // no change
+ return null;
+ }
+ } else {
+ register_error(elgg_echo('user:name:fail'));
+ }
+ return false;
+}
+
+/**
+ * Set a user's language
+ *
+ * @return bool
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_set_user_language() {
+ $language = get_input('language');
+ $user_id = get_input('guid');
+
+ if (!$user_id) {
+ $user = elgg_get_logged_in_user_entity();
+ } else {
+ $user = get_entity($user_id);
+ }
+
+ if (($user) && ($language)) {
+ if (strcmp($language, $user->language) != 0) {
+ $user->language = $language;
+ if ($user->save()) {
+ system_message(elgg_echo('user:language:success'));
+ return true;
+ } else {
+ register_error(elgg_echo('user:language:fail'));
+ }
+ } else {
+ // no change
+ return null;
+ }
+ } else {
+ register_error(elgg_echo('user:language:fail'));
+ }
+ return false;
+}
+
+/**
+ * Set a user's email address
+ *
+ * @return bool
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_set_user_email() {
+ $email = get_input('email');
+ $user_id = get_input('guid');
+
+ if (!$user_id) {
+ $user = elgg_get_logged_in_user_entity();
+ } else {
+ $user = get_entity($user_id);
+ }
+
+ if (!is_email_address($email)) {
+ register_error(elgg_echo('email:save:fail'));
+ return false;
+ }
+
+ if ($user) {
+ if (strcmp($email, $user->email) != 0) {
+ if (!get_user_by_email($email)) {
+ if ($user->email != $email) {
+
+ $user->email = $email;
+ if ($user->save()) {
+ system_message(elgg_echo('email:save:success'));
+ return true;
+ } else {
+ register_error(elgg_echo('email:save:fail'));
+ }
+ }
+ } else {
+ register_error(elgg_echo('registration:dupeemail'));
+ }
+ } else {
+ // no change
+ return null;
+ }
+ } else {
+ register_error(elgg_echo('email:save:fail'));
+ }
+ return false;
+}
+
+/**
+ * Set a user's default access level
+ *
+ * @return bool
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_set_user_default_access() {
+
+ if (!elgg_get_config('allow_user_default_access')) {
+ return false;
+ }
+
+ $default_access = get_input('default_access');
+ $user_id = get_input('guid');
+
+ if (!$user_id) {
+ $user = elgg_get_logged_in_user_entity();
+ } else {
+ $user = get_entity($user_id);
+ }
+
+ if ($user) {
+ $current_default_access = $user->getPrivateSetting('elgg_default_access');
+ if ($default_access !== $current_default_access) {
+ if ($user->setPrivateSetting('elgg_default_access', $default_access)) {
+ system_message(elgg_echo('user:default_access:success'));
+ return true;
+ } else {
+ register_error(elgg_echo('user:default_access:fail'));
+ }
+ } else {
+ // no change
+ return null;
+ }
+ } else {
+ register_error(elgg_echo('user:default_access:fail'));
+ }
+
+ return false;
+}
+
+/**
+ * Set up the menu for user settings
+ *
+ * @return void
+ * @access private
+ */
+function usersettings_pagesetup() {
+ $user = elgg_get_page_owner_entity();
+
+ if ($user && elgg_get_context() == "settings") {
+ $params = array(
+ 'name' => '1_account',
+ 'text' => elgg_echo('usersettings:user:opt:linktext'),
+ 'href' => "settings/user/{$user->username}",
+ );
+ elgg_register_menu_item('page', $params);
+ $params = array(
+ 'name' => '1_plugins',
+ 'text' => elgg_echo('usersettings:plugins:opt:linktext'),
+ 'href' => "settings/plugins/{$user->username}",
+ );
+ elgg_register_menu_item('page', $params);
+ $params = array(
+ 'name' => '1_statistics',
+ 'text' => elgg_echo('usersettings:statistics:opt:linktext'),
+ 'href' => "settings/statistics/{$user->username}",
+ );
+ elgg_register_menu_item('page', $params);
+ }
+}
+
+/**
+ * Page handler for user settings
+ *
+ * @param array $page Pages array
+ *
+ * @return bool
+ * @access private
+ */
+function usersettings_page_handler($page) {
+ global $CONFIG;
+
+ if (!isset($page[0])) {
+ $page[0] = 'user';
+ }
+
+ if (isset($page[1])) {
+ $user = get_user_by_username($page[1]);
+ elgg_set_page_owner_guid($user->guid);
+ } else {
+ $user = elgg_get_logged_in_user_entity();
+ elgg_set_page_owner_guid($user->guid);
+ }
+
+ elgg_push_breadcrumb(elgg_echo('settings'), "settings/user/$user->username");
+
+ switch ($page[0]) {
+ case 'statistics':
+ elgg_push_breadcrumb(elgg_echo('usersettings:statistics:opt:linktext'));
+ $path = $CONFIG->path . "pages/settings/statistics.php";
+ break;
+ case 'plugins':
+ elgg_push_breadcrumb(elgg_echo('usersettings:plugins:opt:linktext'));
+ $path = $CONFIG->path . "pages/settings/tools.php";
+ break;
+ case 'user':
+ $path = $CONFIG->path . "pages/settings/account.php";
+ break;
+ }
+
+ if (isset($path)) {
+ require $path;
+ return true;
+ }
+ return false;
+}
+
+/**
+ * Initialize the user settings library
+ *
+ * @return void
+ * @access private
+ */
+function usersettings_init() {
+ elgg_register_page_handler('settings', 'usersettings_page_handler');
+
+ elgg_register_plugin_hook_handler('usersettings:save', 'user', 'users_settings_save');
+
+ elgg_register_action("usersettings/save");
+
+ // extend the account settings form
+ elgg_extend_view('forms/account/settings', 'core/settings/account/name', 100);
+ elgg_extend_view('forms/account/settings', 'core/settings/account/password', 100);
+ elgg_extend_view('forms/account/settings', 'core/settings/account/email', 100);
+ elgg_extend_view('forms/account/settings', 'core/settings/account/language', 100);
+ elgg_extend_view('forms/account/settings', 'core/settings/account/default_access', 100);
+}
+
+elgg_register_event_handler('init', 'system', 'usersettings_init');
+elgg_register_event_handler('pagesetup', 'system', 'usersettings_pagesetup');
diff --git a/engine/lib/users.php b/engine/lib/users.php
index 99ef15246..a8fb9121c 100644
--- a/engine/lib/users.php
+++ b/engine/lib/users.php
@@ -3,449 +3,25 @@
* Elgg users
* Functions to manage multiple or single users in an Elgg install
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage DataModel.User
*/
/// Map a username to a cached GUID
+global $USERNAME_TO_GUID_MAP_CACHE;
$USERNAME_TO_GUID_MAP_CACHE = array();
/// Map a user code to a cached GUID
+global $CODE_TO_GUID_MAP_CACHE;
$CODE_TO_GUID_MAP_CACHE = array();
/**
- * ElggUser
- *
- * Representation of a "user" in the system.
- *
- * @package Elgg
- * @subpackage Core
- */
-class ElggUser extends ElggEntity
- implements Friendable {
- /**
- * Initialise the attributes array.
- * This is vital to distinguish between metadata and base parameters.
- *
- * Place your base parameters here.
- */
- protected function initialise_attributes() {
- parent::initialise_attributes();
-
- $this->attributes['type'] = "user";
- $this->attributes['name'] = "";
- $this->attributes['username'] = "";
- $this->attributes['password'] = "";
- $this->attributes['salt'] = "";
- $this->attributes['email'] = "";
- $this->attributes['language'] = "";
- $this->attributes['code'] = "";
- $this->attributes['banned'] = "no";
- $this->attributes['admin'] = 'no';
- $this->attributes['tables_split'] = 2;
- }
-
- /**
- * Construct a new user entity, optionally from a given id value.
- *
- * @param mixed $guid If an int, load that GUID.
- * If a db row then will attempt to load the rest of the data.
- * @throws Exception if there was a problem creating the user.
- */
- function __construct($guid = null) {
- $this->initialise_attributes();
-
- if (!empty($guid)) {
- // Is $guid is a DB row - either a entity row, or a user table row.
- if ($guid instanceof stdClass) {
- // Load the rest
- if (!$this->load($guid->guid)) {
- throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid->guid));
- }
- }
-
- // See if this is a username
- else if (is_string($guid)) {
- $guid = get_user_by_username($guid);
- foreach ($guid->attributes as $key => $value) {
- $this->attributes[$key] = $value;
- }
- }
-
- // Is $guid is an ElggUser? Use a copy constructor
- else if ($guid instanceof ElggUser) {
- elgg_deprecated_notice('This type of usage of the ElggUser constructor was deprecated. Please use the clone method.', 1.7);
-
- foreach ($guid->attributes as $key => $value) {
- $this->attributes[$key] = $value;
- }
- }
-
- // Is this is an ElggEntity but not an ElggUser = ERROR!
- else if ($guid instanceof ElggEntity) {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:NonElggUser'));
- }
-
- // We assume if we have got this far, $guid is an int
- else if (is_numeric($guid)) {
- if (!$this->load($guid)) {
- throw new IOException(sprintf(elgg_echo('IOException:FailedToLoadGUID'), get_class(), $guid));
- }
- }
-
- else {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:UnrecognisedValue'));
- }
- }
- }
-
- /**
- * Override the load function.
- * This function will ensure that all data is loaded (were possible), so
- * if only part of the ElggUser is loaded, it'll load the rest.
- *
- * @param int $guid
- * @return true|false
- */
- protected function load($guid) {
- // Test to see if we have the generic stuff
- if (!parent::load($guid)) {
- return false;
- }
-
- // Check the type
- if ($this->attributes['type']!='user') {
- throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, get_class()));
- }
-
- // Load missing data
- $row = get_user_entity_as_row($guid);
- if (($row) && (!$this->isFullyLoaded())) {
- // If $row isn't a cached copy then increment the counter
- $this->attributes['tables_loaded'] ++;
- }
-
- // Now put these into the attributes array as core values
- $objarray = (array) $row;
- foreach($objarray as $key => $value) {
- $this->attributes[$key] = $value;
- }
-
- return true;
- }
-
- /**
- * Saves this user to the database.
- * @return true|false
- */
- public function save() {
- // Save generic stuff
- if (!parent::save()) {
- return false;
- }
-
- // Now save specific stuff
- return create_user_entity($this->get('guid'), $this->get('name'), $this->get('username'), $this->get('password'), $this->get('salt'), $this->get('email'), $this->get('language'), $this->get('code'));
- }
-
- /**
- * User specific override of the entity delete method.
- *
- * @return bool
- */
- public function delete() {
- global $USERNAME_TO_GUID_MAP_CACHE, $CODE_TO_GUID_MAP_CACHE;
-
- // clear cache
- if (isset($USERNAME_TO_GUID_MAP_CACHE[$this->username])) {
- unset($USERNAME_TO_GUID_MAP_CACHE[$this->username]);
- }
- if (isset($CODE_TO_GUID_MAP_CACHE[$this->code])) {
- unset($CODE_TO_GUID_MAP_CACHE[$this->code]);
- }
-
- // Delete owned data
- clear_annotations_by_owner($this->guid);
- clear_metadata_by_owner($this->guid);
- clear_user_files($this);
-
- // Delete entity
- return parent::delete();
- }
-
- /**
- * Ban this user.
- *
- * @param string $reason Optional reason
- */
- public function ban($reason = "") {
- return ban_user($this->guid, $reason);
- }
-
- /**
- * Unban this user.
- */
- public function unban() {
- return unban_user($this->guid);
- }
-
- /**
- * Is this user banned or not?
- *
- * @return bool
- */
- public function isBanned() {
- return $this->banned == 'yes';
- }
-
- /**
- * Is this user admin?
- *
- * @return bool
- */
- public function isAdmin() {
-
- // for backward compatibility we need to pull this directly
- // from the attributes instead of using the magic methods.
- // this can be removed in 1.9
- // return $this->admin == 'yes';
- return $this->attributes['admin'] == 'yes';
- }
-
- /**
- * Make the user an admin
- *
- * @return bool
- */
- public function makeAdmin() {
- if (make_user_admin($this->guid)) {
- $this->attributes['admin'] = 'yes';
- return TRUE;
- }
- return FALSE;
- }
-
- /**
- * Remove the admin flag for user
- *
- * @return bool
- */
- public function removeAdmin() {
- if (remove_user_admin($this->guid)) {
- $this->attributes['admin'] = 'no';
- return TRUE;
- }
- return FALSE;
- }
-
- /**
- * Get sites that this user is a member of
- *
- * @param string $subtype Optionally, the subtype of result we want to limit to
- * @param int $limit The number of results to return
- * @param int $offset Any indexing offset
- */
- function getSites($subtype="", $limit = 10, $offset = 0) {
- // return get_site_users($this->getGUID(), $subtype, $limit, $offset);
- return get_user_sites($this->getGUID(), $subtype, $limit, $offset);
- }
-
- /**
- * Add this user to a particular site
- *
- * @param int $site_guid The guid of the site to add it to
- * @return true|false
- */
- function addToSite($site_guid) {
- // return add_site_user($this->getGUID(), $site_guid);
- return add_site_user($site_guid, $this->getGUID());
- }
-
- /**
- * Remove this user from a particular site
- *
- * @param int $site_guid The guid of the site to remove it from
- * @return true|false
- */
- function removeFromSite($site_guid) {
- //return remove_site_user($this->getGUID(), $site_guid);
- return remove_site_user($site_guid, $this->getGUID());
- }
-
- /**
- * Adds a user to this user's friends list
- *
- * @param int $friend_guid The GUID of the user to add
- * @return true|false Depending on success
- */
- function addFriend($friend_guid) {
- return user_add_friend($this->getGUID(), $friend_guid);
- }
-
- /**
- * Removes a user from this user's friends list
- *
- * @param int $friend_guid The GUID of the user to remove
- * @return true|false Depending on success
- */
- function removeFriend($friend_guid) {
- return user_remove_friend($this->getGUID(), $friend_guid);
- }
-
- /**
- * Determines whether or not this user is a friend of the currently logged in user
- *
- * @return true|false
- */
- function isFriend() {
- return user_is_friend(get_loggedin_userid(), $this->getGUID());
- }
-
- /**
- * Determines whether this user is friends with another user
- *
- * @param int $user_guid The GUID of the user to check is on this user's friends list
- * @return true|false
- */
- function isFriendsWith($user_guid) {
- return user_is_friend($this->getGUID(), $user_guid);
- }
-
- /**
- * Determines whether or not this user is on another user's friends list
- *
- * @param int $user_guid The GUID of the user to check against
- * @return true|false
- */
- function isFriendOf($user_guid) {
- return user_is_friend($user_guid, $this->getGUID());
- }
-
- /**
- * Retrieves a list of this user's friends
- *
- * @param string $subtype Optionally, the subtype of user to filter to (leave blank for all)
- * @param int $limit The number of users to retrieve
- * @param int $offset Indexing offset, if any
- * @return array|false Array of ElggUsers, or false, depending on success
- */
- function getFriends($subtype = "", $limit = 10, $offset = 0) {
- return get_user_friends($this->getGUID(), $subtype, $limit, $offset);
- }
-
- /**
- * Retrieves a list of people who have made this user a friend
- *
- * @param string $subtype Optionally, the subtype of user to filter to (leave blank for all)
- * @param int $limit The number of users to retrieve
- * @param int $offset Indexing offset, if any
- * @return array|false Array of ElggUsers, or false, depending on success
- */
- function getFriendsOf($subtype = "", $limit = 10, $offset = 0) {
- return get_user_friends_of($this->getGUID(), $subtype, $limit, $offset);
- }
-
- /**
- * Get an array of ElggObjects owned by this user.
- *
- * @param string $subtype The subtype of the objects, if any
- * @param int $limit Number of results to return
- * @param int $offset Any indexing offset
- */
- public function getObjects($subtype="", $limit = 10, $offset = 0) {
- return get_user_objects($this->getGUID(), $subtype, $limit, $offset);
- }
-
- /**
- * Get an array of ElggObjects owned by this user's friends.
- *
- * @param string $subtype The subtype of the objects, if any
- * @param int $limit Number of results to return
- * @param int $offset Any indexing offset
- */
- public function getFriendsObjects($subtype = "", $limit = 10, $offset = 0) {
- return get_user_friends_objects($this->getGUID(), $subtype, $limit, $offset);
- }
-
- /**
- * Counts the number of ElggObjects owned by this user
- *
- * @param string $subtype The subtypes of the objects, if any
- * @return int The number of ElggObjects
- */
- public function countObjects($subtype = "") {
- return count_user_objects($this->getGUID(), $subtype);
- }
-
- /**
- * Get the collections associated with a user.
- *
- * @param string $subtype Optionally, the subtype of result we want to limit to
- * @param int $limit The number of results to return
- * @param int $offset Any indexing offset
- * @return unknown
- */
- public function getCollections($subtype="", $limit = 10, $offset = 0) {
- return get_user_collections($this->getGUID(), $subtype, $limit, $offset);
- }
-
- /**
- * If a user's owner is blank, return its own GUID as the owner
- *
- * @return int User GUID
- */
- function getOwner() {
- if ($this->owner_guid == 0) {
- return $this->getGUID();
- }
-
- return $this->owner_guid;
- }
-
- // EXPORTABLE INTERFACE ////////////////////////////////////////////////////////////
-
- /**
- * Return an array of fields which can be exported.
- */
- public function getExportableValues() {
- return array_merge(parent::getExportableValues(), array(
- 'name',
- 'username',
- 'language',
- ));
- }
-
- // backward compatibility with admin flag
- // remove for 1.9
- public function __set($name, $value) {
- if ($name == 'admin' || $name == 'siteadmin') {
- elgg_deprecated_notice('The admin/siteadmin metadata are not longer used. Use ElggUser->makeAdmin() and ElggUser->removeAdmin().', '1.7.1');
-
- if ($value == 'yes' || $value == '1') {
- $this->makeAdmin();
- } else {
- $this->removeAdmin();
- }
- }
- return parent::__set($name, $value);
- }
-
- public function __get($name) {
- if ($name == 'admin' || $name == 'siteadmin') {
- elgg_deprecated_notice('The admin/siteadmin metadata are not longer used. Use ElggUser->isAdmin().', '1.7.1');
- return $this->isAdmin();
- }
-
- return parent::__get($name);
- }
-}
-
-/**
* Return the user specific details of a user by a row.
*
- * @param int $guid
+ * @param int $guid The ElggUser guid
+ *
+ * @return mixed
+ * @access private
*/
function get_user_entity_as_row($guid) {
global $CONFIG;
@@ -455,13 +31,20 @@ function get_user_entity_as_row($guid) {
}
/**
- * Create or update the extras table for a given user.
+ * Create or update the entities table for a given user.
* Call create_entity first.
*
- * @param int $guid
- * @param string $name
- * @param string $description
- * @param string $url
+ * @param int $guid The user's GUID
+ * @param string $name The user's display name
+ * @param string $username The username
+ * @param string $password The password
+ * @param string $salt A salt for the password
+ * @param string $email The user's email address
+ * @param string $language The user's default language
+ * @param string $code A code
+ *
+ * @return bool
+ * @access private
*/
function create_user_entity($guid, $name, $username, $password, $salt, $email, $language, $code) {
global $CONFIG;
@@ -478,27 +61,36 @@ function create_user_entity($guid, $name, $username, $password, $salt, $email, $
$row = get_entity_as_row($guid);
if ($row) {
// Exists and you have access to it
-
- if ($exists = get_data_row("SELECT guid from {$CONFIG->dbprefix}users_entity where guid = {$guid}")) {
- $result = update_data("UPDATE {$CONFIG->dbprefix}users_entity set name='$name', username='$username', password='$password', salt='$salt', email='$email', language='$language', code='$code', last_action = ". time() ." where guid = {$guid}");
+ $query = "SELECT guid from {$CONFIG->dbprefix}users_entity where guid = {$guid}";
+ if ($exists = get_data_row($query)) {
+ $query = "UPDATE {$CONFIG->dbprefix}users_entity
+ SET name='$name', username='$username', password='$password', salt='$salt',
+ email='$email', language='$language', code='$code'
+ WHERE guid = $guid";
+
+ $result = update_data($query);
if ($result != false) {
// Update succeeded, continue
$entity = get_entity($guid);
- if (trigger_elgg_event('update',$entity->type,$entity)) {
+ if (elgg_trigger_event('update', $entity->type, $entity)) {
return $guid;
} else {
$entity->delete();
}
}
} else {
- // Update failed, attempt an insert.
- $result = insert_data("INSERT into {$CONFIG->dbprefix}users_entity (guid, name, username, password, salt, email, language, code) values ($guid, '$name', '$username', '$password', '$salt', '$email', '$language', '$code')");
- if ($result!==false) {
+ // Exists query failed, attempt an insert.
+ $query = "INSERT into {$CONFIG->dbprefix}users_entity
+ (guid, name, username, password, salt, email, language, code)
+ values ($guid, '$name', '$username', '$password', '$salt', '$email', '$language', '$code')";
+
+ $result = insert_data($query);
+ if ($result !== false) {
$entity = get_entity($guid);
- if (trigger_elgg_event('create',$entity->type,$entity)) {
+ if (elgg_trigger_event('create', $entity->type, $entity)) {
return $guid;
} else {
- $entity->delete(); //delete_entity($guid);
+ $entity->delete();
}
}
}
@@ -511,15 +103,20 @@ function create_user_entity($guid, $name, $username, $password, $salt, $email, $
* Disables all of a user's entities
*
* @param int $owner_guid The owner GUID
- * @return true|false Depending on success
+ *
+ * @return bool Depending on success
*/
function disable_user_entities($owner_guid) {
global $CONFIG;
$owner_guid = (int) $owner_guid;
if ($entity = get_entity($owner_guid)) {
- if (trigger_elgg_event('disable',$entity->type,$entity)) {
+ if (elgg_trigger_event('disable', $entity->type, $entity)) {
if ($entity->canEdit()) {
- $res = update_data("UPDATE {$CONFIG->dbprefix}entities set enabled='no' where owner_guid={$owner_guid} or container_guid = {$owner_guid}");
+ $query = "UPDATE {$CONFIG->dbprefix}entities
+ set enabled='no' where owner_guid={$owner_guid}
+ or container_guid = {$owner_guid}";
+
+ $res = update_data($query);
return $res;
}
}
@@ -531,22 +128,23 @@ function disable_user_entities($owner_guid) {
/**
* Ban a user
*
- * @param int $user_guid The user guid
- * @param string $reason A reason
+ * @param int $user_guid The user guid
+ * @param string $reason A reason
+ *
+ * @return bool
*/
function ban_user($user_guid, $reason = "") {
global $CONFIG;
$user_guid = (int)$user_guid;
- $reason = sanitise_string($reason);
$user = get_entity($user_guid);
if (($user) && ($user->canEdit()) && ($user instanceof ElggUser)) {
- if (trigger_elgg_event('ban', 'user', $user)) {
+ if (elgg_trigger_event('ban', 'user', $user)) {
// Add reason
if ($reason) {
- create_metadata($user_guid, 'ban_reason', $reason,'', 0, ACCESS_PUBLIC);
+ create_metadata($user_guid, 'ban_reason', $reason, '', 0, ACCESS_PUBLIC);
}
// clear "remember me" cookie code so user cannot login in using it
@@ -564,7 +162,8 @@ function ban_user($user_guid, $reason = "") {
}
// Set ban flag
- return update_data("UPDATE {$CONFIG->dbprefix}users_entity set banned='yes' where guid=$user_guid");
+ $query = "UPDATE {$CONFIG->dbprefix}users_entity set banned='yes' where guid=$user_guid";
+ return update_data($query);
}
return FALSE;
@@ -577,6 +176,8 @@ function ban_user($user_guid, $reason = "") {
* Unban a user.
*
* @param int $user_guid Unban a user.
+ *
+ * @return bool
*/
function unban_user($user_guid) {
global $CONFIG;
@@ -586,8 +187,8 @@ function unban_user($user_guid) {
$user = get_entity($user_guid);
if (($user) && ($user->canEdit()) && ($user instanceof ElggUser)) {
- if (trigger_elgg_event('unban', 'user', $user)) {
- create_metadata($user_guid, 'ban_reason', '','', 0, ACCESS_PUBLIC);
+ if (elgg_trigger_event('unban', 'user', $user)) {
+ create_metadata($user_guid, 'ban_reason', '', '', 0, ACCESS_PUBLIC);
// invalidate memcache for this user
static $newentity_cache;
@@ -599,7 +200,9 @@ function unban_user($user_guid) {
$newentity_cache->delete($user_guid);
}
- return update_data("UPDATE {$CONFIG->dbprefix}users_entity set banned='no' where guid=$user_guid");
+
+ $query = "UPDATE {$CONFIG->dbprefix}users_entity set banned='no' where guid=$user_guid";
+ return update_data($query);
}
return FALSE;
@@ -611,7 +214,8 @@ function unban_user($user_guid) {
/**
* Makes user $guid an admin.
*
- * @param int $guid
+ * @param int $user_guid User guid
+ *
* @return bool
*/
function make_user_admin($user_guid) {
@@ -620,7 +224,7 @@ function make_user_admin($user_guid) {
$user = get_entity((int)$user_guid);
if (($user) && ($user instanceof ElggUser) && ($user->canEdit())) {
- if (trigger_elgg_event('make_admin', 'user', $user)) {
+ if (elgg_trigger_event('make_admin', 'user', $user)) {
// invalidate memcache for this user
static $newentity_cache;
@@ -633,7 +237,7 @@ function make_user_admin($user_guid) {
}
$r = update_data("UPDATE {$CONFIG->dbprefix}users_entity set admin='yes' where guid=$user_guid");
- invalidate_cache_for_entity($user_guid);
+ _elgg_invalidate_cache_for_entity($user_guid);
return $r;
}
@@ -646,7 +250,8 @@ function make_user_admin($user_guid) {
/**
* Removes user $guid's admin flag.
*
- * @param int $guid
+ * @param int $user_guid User GUID
+ *
* @return bool
*/
function remove_user_admin($user_guid) {
@@ -655,7 +260,7 @@ function remove_user_admin($user_guid) {
$user = get_entity((int)$user_guid);
if (($user) && ($user instanceof ElggUser) && ($user->canEdit())) {
- if (trigger_elgg_event('remove_admin', 'user', $user)) {
+ if (elgg_trigger_event('remove_admin', 'user', $user)) {
// invalidate memcache for this user
static $newentity_cache;
@@ -668,7 +273,7 @@ function remove_user_admin($user_guid) {
}
$r = update_data("UPDATE {$CONFIG->dbprefix}users_entity set admin='no' where guid=$user_guid");
- invalidate_cache_for_entity($user_guid);
+ _elgg_invalidate_cache_for_entity($user_guid);
return $r;
}
@@ -679,25 +284,13 @@ function remove_user_admin($user_guid) {
}
/**
- * THIS FUNCTION IS DEPRECATED.
- *
- * Delete a user's extra data.
- *
- * @param int $guid
- */
-function delete_user_entity($guid) {
- system_message(sprintf(elgg_echo('deprecatedfunction'), 'delete_user_entity'));
-
- return 1; // Always return that we have deleted one row in order to not break existing code.
-}
-
-/**
* Get the sites this user is part of
*
* @param int $user_guid The user's GUID
- * @param int $limit Number of results to return
- * @param int $offset Any indexing offset
- * @return false|array On success, an array of ElggSites
+ * @param int $limit Number of results to return
+ * @param int $offset Any indexing offset
+ *
+ * @return ElggSite[]|false On success, an array of ElggSites
*/
function get_user_sites($user_guid, $limit = 10, $offset = 0) {
$user_guid = (int)$user_guid;
@@ -705,21 +298,23 @@ function get_user_sites($user_guid, $limit = 10, $offset = 0) {
$offset = (int)$offset;
return elgg_get_entities_from_relationship(array(
+ 'site_guids' => ELGG_ENTITIES_ANY_VALUE,
'relationship' => 'member_of_site',
'relationship_guid' => $user_guid,
'inverse_relationship' => FALSE,
- 'types' => 'site',
+ 'type' => 'site',
'limit' => $limit,
- 'offset' => $offset)
- );
+ 'offset' => $offset,
+ ));
}
/**
* Adds a user to another user's friends list.
*
- * @param int $user_guid The GUID of the friending user
+ * @param int $user_guid The GUID of the friending user
* @param int $friend_guid The GUID of the user to friend
- * @return true|false Depending on success
+ *
+ * @return bool Depending on success
*/
function user_add_friend($user_guid, $friend_guid) {
$user_guid = (int) $user_guid;
@@ -742,13 +337,12 @@ function user_add_friend($user_guid, $friend_guid) {
/**
* Removes a user from another user's friends list.
*
- * @param int $user_guid The GUID of the friending user
+ * @param int $user_guid The GUID of the friending user
* @param int $friend_guid The GUID of the user on the friends list
- * @return true|false Depending on success
+ *
+ * @return bool Depending on success
*/
function user_remove_friend($user_guid, $friend_guid) {
- global $CONFIG;
-
$user_guid = (int) $user_guid;
$friend_guid = (int) $friend_guid;
@@ -766,29 +360,33 @@ function user_remove_friend($user_guid, $friend_guid) {
/**
* Determines whether or not a user is another user's friend.
*
- * @param int $user_guid The GUID of the user
+ * @param int $user_guid The GUID of the user
* @param int $friend_guid The GUID of the friend
- * @return true|false
+ *
+ * @return bool
*/
function user_is_friend($user_guid, $friend_guid) {
- return check_entity_relationship($user_guid, "friend", $friend_guid);
+ return check_entity_relationship($user_guid, "friend", $friend_guid) !== false;
}
/**
* Obtains a given user's friends
*
- * @param int $user_guid The user's GUID
- * @param string $subtype The subtype of users, if any
- * @param int $limit Number of results to return (default 10)
- * @param int $offset Indexing offset, if any
- * @return false|array Either an array of ElggUsers or false, depending on success
+ * @param int $user_guid The user's GUID
+ * @param string $subtype The subtype of users, if any
+ * @param int $limit Number of results to return (default 10)
+ * @param int $offset Indexing offset, if any
+ *
+ * @return ElggUser[]|false Either an array of ElggUsers or false, depending on success
*/
-function get_user_friends($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10, $offset = 0) {
+function get_user_friends($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10,
+$offset = 0) {
+
return elgg_get_entities_from_relationship(array(
'relationship' => 'friend',
'relationship_guid' => $user_guid,
- 'types' => 'user',
- 'subtypes' => $subtype,
+ 'type' => 'user',
+ 'subtype' => $subtype,
'limit' => $limit,
'offset' => $offset
));
@@ -797,110 +395,45 @@ function get_user_friends($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit
/**
* Obtains the people who have made a given user a friend
*
- * @param int $user_guid The user's GUID
- * @param string $subtype The subtype of users, if any
- * @param int $limit Number of results to return (default 10)
- * @param int $offset Indexing offset, if any
- * @return false|array Either an array of ElggUsers or false, depending on success
+ * @param int $user_guid The user's GUID
+ * @param string $subtype The subtype of users, if any
+ * @param int $limit Number of results to return (default 10)
+ * @param int $offset Indexing offset, if any
+ *
+ * @return ElggUser[]|false Either an array of ElggUsers or false, depending on success
*/
-function get_user_friends_of($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10, $offset = 0) {
+function get_user_friends_of($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10,
+$offset = 0) {
+
return elgg_get_entities_from_relationship(array(
'relationship' => 'friend',
'relationship_guid' => $user_guid,
'inverse_relationship' => TRUE,
- 'types' => 'user',
- 'subtypes' => $subtype,
- 'limit' => $limit,
- 'offset' => $offset
- ));
-}
-
-/**
- * Obtains a list of objects owned by a user
- *
- * @param int $user_guid The GUID of the owning user
- * @param string $subtype Optionally, the subtype of objects
- * @param int $limit The number of results to return (default 10)
- * @param int $offset Indexing offset, if any
- * @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 false|array An array of ElggObjects or false, depending on success
- */
-function get_user_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10, $offset = 0, $timelower = 0, $timeupper = 0) {
- $ntt = elgg_get_entities(array(
- 'type' => 'object',
+ 'type' => 'user',
'subtype' => $subtype,
- 'owner_guid' => $user_guid,
'limit' => $limit,
- 'offset' => $offset,
- 'container_guid' => $user_guid,
- 'created_time_lower' => $timelower,
- 'created_time_upper' => $timeupper
- ));
- return $ntt;
-}
-
-/**
- * Counts the objects (optionally of a particular subtype) owned by a user
- *
- * @param int $user_guid The GUID of the owning user
- * @param string $subtype Optionally, the subtype of objects
- * @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 int The number of objects the user owns (of this subtype)
- */
-function count_user_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $timelower = 0, $timeupper = 0) {
- $total = elgg_get_entities(array(
- 'type' => 'object',
- 'subtype' => $subtype,
- 'owner_guid' => $user_guid,
- 'count' => TRUE,
- 'container_guid' => $user_guid,
- 'created_time_lower' => $timelower,
- 'created_time_upper' => $timeupper
+ 'offset' => $offset
));
- return $total;
}
/**
- * Displays a list of user objects of a particular subtype, with navigation.
+ * Obtains a list of objects owned by a user's friends
*
- * @see elgg_view_entity_list
+ * @param int $user_guid The GUID of the user to get the friends of
+ * @param string $subtype Optionally, the subtype of objects
+ * @param int $limit The number of results to return (default 10)
+ * @param int $offset Indexing offset, if any
+ * @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
*
- * @param int $user_guid The GUID of the user
- * @param string $subtype The object subtype
- * @param int $limit The number of entities to display on a page
- * @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 (default: true)
- * @param true|false $pagination Whether to display pagination (default: true)
- * @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 string The list in a form suitable to display
+ * @return ElggObject[]|false An array of ElggObjects or false, depending on success
*/
-function list_user_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10, $fullview = true, $viewtypetoggle = true, $pagination = true, $timelower = 0, $timeupper = 0) {
- $offset = (int) get_input('offset');
- $limit = (int) $limit;
- $count = (int) count_user_objects($user_guid, $subtype,$timelower,$timeupper);
- $entities = get_user_objects($user_guid, $subtype, $limit, $offset, $timelower, $timeupper);
+function get_user_friends_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10,
+$offset = 0, $timelower = 0, $timeupper = 0) {
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination);
-}
-
-/**
- * Obtains a list of objects owned by a user's friends
- *
- * @param int $user_guid The GUID of the user to get the friends of
- * @param string $subtype Optionally, the subtype of objects
- * @param int $limit The number of results to return (default 10)
- * @param int $offset Indexing offset, if any
- * @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 false|array An array of ElggObjects or false, depending on success
- */
-function get_user_friends_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $limit = 10, $offset = 0, $timelower = 0, $timeupper = 0) {
if ($friends = get_user_friends($user_guid, "", 999999, 0)) {
$friendguids = array();
- foreach($friends as $friend) {
+ foreach ($friends as $friend) {
$friendguids[] = $friend->getGUID();
}
return elgg_get_entities(array(
@@ -920,16 +453,19 @@ function get_user_friends_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE
/**
* Counts the number of objects owned by a user's friends
*
- * @param int $user_guid The GUID of the user to get the friends of
- * @param string $subtype Optionally, the subtype of objects
- * @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
+ * @param int $user_guid The GUID of the user to get the friends of
+ * @param string $subtype Optionally, the subtype of objects
+ * @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 int The number of objects
*/
-function count_user_friends_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE, $timelower = 0, $timeupper = 0) {
+function count_user_friends_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VALUE,
+$timelower = 0, $timeupper = 0) {
+
if ($friends = get_user_friends($user_guid, "", 999999, 0)) {
$friendguids = array();
- foreach($friends as $friend) {
+ foreach ($friends as $friend) {
$friendguids[] = $friend->getGUID();
}
return elgg_get_entities(array(
@@ -950,44 +486,44 @@ function count_user_friends_objects($user_guid, $subtype = ELGG_ENTITIES_ANY_VAL
*
* @see elgg_view_entity_list
*
- * @param int $user_guid The GUID of the user
- * @param string $subtype The object subtype
- * @param int $limit The number of entities to display on a page
- * @param true|false $fullview Whether or not to display the full view (default: true)
- * @param true|false $viewtypetoggle Whether or not to allow you to flip to gallery mode (default: true)
- * @param true|false $pagination Whether to display pagination (default: true)
- * @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 string The list in a form suitable to display
+ * @param int $user_guid The GUID of the user
+ * @param string $subtype The object subtype
+ * @param int $limit The number of entities to display on a page
+ * @param bool $full_view Whether or not to display the full view (default: true)
+ * @param bool $listtypetoggle Whether or not to allow you to flip to gallery mode (default: true)
+ * @param bool $pagination Whether to display pagination (default: true)
+ * @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 string
*/
-function list_user_friends_objects($user_guid, $subtype = "", $limit = 10, $fullview = true, $viewtypetoggle = true, $pagination = true, $timelower = 0, $timeupper = 0) {
- $offset = (int) get_input('offset');
- $limit = (int) $limit;
- $count = (int) count_user_friends_objects($user_guid, $subtype, $timelower, $timeupper);
- $entities = get_user_friends_objects($user_guid, $subtype, $limit, $offset, $timelower, $timeupper);
+function list_user_friends_objects($user_guid, $subtype = "", $limit = 10, $full_view = true,
+$listtypetoggle = true, $pagination = true, $timelower = 0, $timeupper = 0) {
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, $viewtypetoggle, $pagination);
-}
+ $offset = (int)get_input('offset');
+ $limit = (int)$limit;
+ $count = (int)count_user_friends_objects($user_guid, $subtype, $timelower, $timeupper);
-/**
- * Get user objects by an array of metadata
- *
- * @param int $user_guid The GUID of the owning user
- * @param string $subtype Optionally, the subtype of objects
- * @paran array $metadata An array of metadata
- * @param int $limit The number of results to return (default 10)
- * @param int $offset Indexing offset, if any
- * @return false|array An array of ElggObjects or false, depending on success
- */
-function get_user_objects_by_metadata($user_guid, $subtype = "", $metadata = array(), $limit = 0, $offset = 0) {
- return get_entities_from_metadata_multi($metadata,"object",$subtype,$user_guid,$limit,$offset);
+ $entities = get_user_friends_objects($user_guid, $subtype, $limit, $offset,
+ $timelower, $timeupper);
+
+ return elgg_view_entity_list($entities, array(
+ 'count' => $count,
+ 'offset' => $offset,
+ 'limit' => $limit,
+ 'full_view' => $full_view,
+ 'list_type_toggle' => $listtypetoggle,
+ 'pagination' => $pagination,
+ ));
}
/**
* Get a user object from a GUID.
*
* This function returns an ElggUser from a given GUID.
+ *
* @param int $guid The GUID
+ *
* @return ElggUser|false
*/
function get_user($guid) {
@@ -997,7 +533,6 @@ function get_user($guid) {
}
if ((!empty($result)) && (!($result instanceof ElggUser))) {
- //throw new InvalidClassException(sprintf(elgg_echo('InvalidClassException:NotValidElggStar'), $guid, 'ElggUser'));
return false;
}
@@ -1012,32 +547,45 @@ function get_user($guid) {
* Get user by username
*
* @param string $username The user's username
+ *
* @return ElggUser|false Depending on success
*/
function get_user_by_username($username) {
global $CONFIG, $USERNAME_TO_GUID_MAP_CACHE;
+ // Fixes #6052. Username is frequently sniffed from the path info, which,
+ // unlike $_GET, is not URL decoded. If the username was not URL encoded,
+ // this is harmless.
+ $username = rawurldecode($username);
+
$username = sanitise_string($username);
$access = get_access_sql_suffix('e');
// Caching
- if ( (isset($USERNAME_TO_GUID_MAP_CACHE[$username])) && (retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username])) ) {
- return retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username]);
+ if ((isset($USERNAME_TO_GUID_MAP_CACHE[$username]))
+ && (_elgg_retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username]))) {
+ return _elgg_retrieve_cached_entity($USERNAME_TO_GUID_MAP_CACHE[$username]);
}
- $row = get_data_row("SELECT e.* from {$CONFIG->dbprefix}users_entity u join {$CONFIG->dbprefix}entities e on e.guid=u.guid where u.username='$username' and $access ");
- if ($row) {
- $USERNAME_TO_GUID_MAP_CACHE[$username] = $row->guid;
- return new ElggUser($row);
+ $query = "SELECT e.* from {$CONFIG->dbprefix}users_entity u
+ join {$CONFIG->dbprefix}entities e on e.guid=u.guid
+ where u.username='$username' and $access ";
+
+ $entity = get_data_row($query, 'entity_row_to_elggstar');
+ if ($entity) {
+ $USERNAME_TO_GUID_MAP_CACHE[$username] = $entity->guid;
+ } else {
+ $entity = false;
}
- return false;
+ return $entity;
}
/**
* Get user by session code
*
* @param string $code The session code
+ *
* @return ElggUser|false Depending on success
*/
function get_user_by_code($code) {
@@ -1048,24 +596,30 @@ function get_user_by_code($code) {
$access = get_access_sql_suffix('e');
// Caching
- if ( (isset($CODE_TO_GUID_MAP_CACHE[$code])) && (retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code])) ) {
- return retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code]);
+ if ((isset($CODE_TO_GUID_MAP_CACHE[$code]))
+ && (_elgg_retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code]))) {
+
+ return _elgg_retrieve_cached_entity($CODE_TO_GUID_MAP_CACHE[$code]);
}
- $row = get_data_row("SELECT e.* from {$CONFIG->dbprefix}users_entity u join {$CONFIG->dbprefix}entities e on e.guid=u.guid where u.code='$code' and $access");
- if ($row) {
- $CODE_TO_GUID_MAP_CACHE[$code] = $row->guid;
- return new ElggUser($row);
+ $query = "SELECT e.* from {$CONFIG->dbprefix}users_entity u
+ join {$CONFIG->dbprefix}entities e on e.guid=u.guid
+ where u.code='$code' and $access";
+
+ $entity = get_data_row($query, 'entity_row_to_elggstar');
+ if ($entity) {
+ $CODE_TO_GUID_MAP_CACHE[$code] = $entity->guid;
}
- return false;
+ return $entity;
}
/**
- * Get an array of users from their
+ * Get an array of users from an email address
*
* @param string $email Email address.
- * @return Array of users
+ *
+ * @return array
*/
function get_user_by_email($email) {
global $CONFIG;
@@ -1074,125 +628,72 @@ function get_user_by_email($email) {
$access = get_access_sql_suffix('e');
- $query = "SELECT e.* from {$CONFIG->dbprefix}entities e join {$CONFIG->dbprefix}users_entity u on e.guid=u.guid where email='$email' and $access";
+ $query = "SELECT e.* from {$CONFIG->dbprefix}entities e
+ join {$CONFIG->dbprefix}users_entity u on e.guid=u.guid
+ where email='$email' and $access";
return get_data($query, 'entity_row_to_elggstar');
}
/**
- * Searches for a user based on a complete or partial name or username.
- *
- * @param string $criteria The partial or full name or username.
- * @param int $limit Limit of the search.
- * @param int $offset Offset.
- * @param string $order_by The order.
- * @param boolean $count Whether to return the count of results or just the results.
- * @deprecated 1.7
- */
-function search_for_user($criteria, $limit = 10, $offset = 0, $order_by = "", $count = false) {
- elgg_deprecated_notice('search_for_user() was deprecated by new search.', 1.7);
- global $CONFIG;
-
- $criteria = sanitise_string($criteria);
- $limit = (int)$limit;
- $offset = (int)$offset;
- $order_by = sanitise_string($order_by);
-
- $access = get_access_sql_suffix("e");
-
- if ($order_by == "") {
- $order_by = "e.time_created desc";
- }
-
- if ($count) {
- $query = "SELECT count(e.guid) as total ";
- } else {
- $query = "SELECT e.* ";
- }
- $query .= "from {$CONFIG->dbprefix}entities e join {$CONFIG->dbprefix}users_entity u on e.guid=u.guid where ";
- // $query .= " match(u.name,u.username) against ('$criteria') ";
- $query .= "(u.name like \"%{$criteria}%\" or u.username like \"%{$criteria}%\")";
- $query .= " and $access";
-
- if (!$count) {
- $query .= " order by $order_by limit $offset, $limit"; // Add order and limit
- return get_data($query, "entity_row_to_elggstar");
- } else {
- if ($count = get_data_row($query)) {
- return $count->total;
- }
- }
- return false;
-}
-
-/**
- * Displays a list of user objects that have been searched for.
- *
- * @see elgg_view_entity_list
- *
- * @param string $tag Search criteria
- * @param int $limit The number of entities to display on a page
- * @return string The list in a form suitable to display
- * @deprecated 1.7
- */
-function list_user_search($tag, $limit = 10) {
- elgg_deprecated_notice('list_user_search() deprecated by new search', 1.7);
- $offset = (int) get_input('offset');
- $limit = (int) $limit;
- $count = (int) search_for_user($tag, 10, 0, '', true);
- $entities = search_for_user($tag, $limit, $offset);
-
- return elgg_view_entity_list($entities, $count, $offset, $limit, $fullview, false);
-}
-
-/**
* A function that returns a maximum of $limit users who have done something within the last
- * $seconds seconds.
+ * $seconds seconds or the total count of active users.
+ *
+ * @param int $seconds Number of seconds (default 600 = 10min)
+ * @param int $limit Limit, default 10.
+ * @param int $offset Offset, default 0.
+ * @param bool $count Count, default false.
*
- * @param int $seconds Number of seconds (default 600 = 10min)
- * @param int $limit Limit, default 10.
- * @param int $offset Offset, defualt 0.
+ * @return mixed
*/
-function find_active_users($seconds = 600, $limit = 10, $offset = 0) {
- global $CONFIG;
-
+function find_active_users($seconds = 600, $limit = 10, $offset = 0, $count = false) {
$seconds = (int)$seconds;
$limit = (int)$limit;
$offset = (int)$offset;
+ $params = array('seconds' => $seconds, 'limit' => $limit, 'offset' => $offset, 'count' => $count);
+ $data = elgg_trigger_plugin_hook('find_active_users', 'system', $params, NULL);
+ if (!$data) {
+ global $CONFIG;
- $time = time() - $seconds;
-
- $access = get_access_sql_suffix("e");
-
- $query = "SELECT distinct e.* from {$CONFIG->dbprefix}entities e join {$CONFIG->dbprefix}users_entity u on e.guid = u.guid where u.last_action >= {$time} and $access order by u.last_action desc limit {$offset},{$limit}";
+ $time = time() - $seconds;
- return get_data($query, "entity_row_to_elggstar");
+ $data = elgg_get_entities(array(
+ 'type' => 'user',
+ 'limit' => $limit,
+ 'offset' => $offset,
+ 'count' => $count,
+ 'joins' => array("join {$CONFIG->dbprefix}users_entity u on e.guid = u.guid"),
+ 'wheres' => array("u.last_action >= {$time}"),
+ 'order_by' => "u.last_action desc"
+ ));
+ }
+ return $data;
}
/**
* Generate and send a password request email to a given user's registered email address.
*
- * @param int $user_guid
+ * @param int $user_guid User GUID
+ *
+ * @return bool
*/
function send_new_password_request($user_guid) {
- global $CONFIG;
-
$user_guid = (int)$user_guid;
$user = get_entity($user_guid);
- if ($user) {
+ if ($user instanceof ElggUser) {
// generate code
$code = generate_random_cleartext_password();
- //create_metadata($user_guid, 'conf_code', $code,'', 0, ACCESS_PRIVATE);
- set_private_setting($user_guid, 'passwd_conf_code', $code);
+ $user->setPrivateSetting('passwd_conf_code', $code);
// generate link
- $link = $CONFIG->site->url . "pg/resetpassword?u=$user_guid&c=$code";
+ $link = elgg_get_site_url() . "resetpassword?u=$user_guid&c=$code";
// generate email
- $email = sprintf(elgg_echo('email:resetreq:body'), $user->name, $_SERVER['REMOTE_ADDR'], $link);
+ $email = elgg_echo('email:resetreq:body', array($user->name, $_SERVER['REMOTE_ADDR'], $link));
- return notify_user($user->guid, $CONFIG->site->guid, elgg_echo('email:resetreq:subject'), $email, NULL, 'email');
+ return notify_user($user->guid, elgg_get_site_entity()->guid,
+ elgg_echo('email:resetreq:subject'), $email, array(), 'email');
}
return false;
@@ -1203,23 +704,24 @@ function send_new_password_request($user_guid) {
*
* This can only be called from execute_new_password_request().
*
- * @param int $user_guid The user.
- * @param string $password password text (which will then be converted into a hash and stored)
+ * @param int $user_guid The user.
+ * @param string $password Text (which will then be converted into a hash and stored)
+ *
+ * @return bool
*/
function force_user_password_reset($user_guid, $password) {
- global $CONFIG;
-
- if (call_gatekeeper('execute_new_password_request', __FILE__)) {
- $user = get_entity($user_guid);
+ $user = get_entity($user_guid);
+ if ($user instanceof ElggUser) {
+ $ia = elgg_set_ignore_access();
- if ($user) {
- $salt = generate_random_cleartext_password(); // Reset the salt
- $user->salt = $salt;
+ $user->salt = generate_random_cleartext_password();
+ $hash = generate_user_password($user, $password);
+ $user->password = $hash;
+ $result = (bool)$user->save();
- $hash = generate_user_password($user, $password);
+ elgg_set_ignore_access($ia);
- return update_data("UPDATE {$CONFIG->dbprefix}users_entity set password='$hash', salt='$salt' where guid=$user_guid");
- }
+ return $result;
}
return false;
@@ -1228,8 +730,10 @@ function force_user_password_reset($user_guid, $password) {
/**
* Validate and execute a password reset for a user.
*
- * @param int $user_guid The user id
+ * @param int $user_guid The user id
* @param string $conf_code Confirmation code as sent in the request email.
+ *
+ * @return mixed
*/
function execute_new_password_request($user_guid, $conf_code) {
global $CONFIG;
@@ -1237,17 +741,22 @@ function execute_new_password_request($user_guid, $conf_code) {
$user_guid = (int)$user_guid;
$user = get_entity($user_guid);
- $saved_code = get_private_setting($user_guid, 'passwd_conf_code');
-
- if ($user && $saved_code && $saved_code == $conf_code) {
- $password = generate_random_cleartext_password();
+ if ($user instanceof ElggUser) {
+ $saved_code = $user->getPrivateSetting('passwd_conf_code');
- if (force_user_password_reset($user_guid, $password)) {
- remove_private_setting($user_guid, 'passwd_conf_code');
+ if ($saved_code && $saved_code == $conf_code) {
+ $password = generate_random_cleartext_password();
- $email = sprintf(elgg_echo('email:resetpassword:body'), $user->name, $password);
+ if (force_user_password_reset($user_guid, $password)) {
+ remove_private_setting($user_guid, 'passwd_conf_code');
+ // clean the logins failures
+ reset_login_failure_count($user_guid);
+
+ $email = elgg_echo('email:resetpassword:body', array($user->name, $password));
- return notify_user($user->guid, $CONFIG->site->guid, elgg_echo('email:resetpassword:subject'), $email, NULL, 'email');
+ return notify_user($user->guid, $CONFIG->site->guid,
+ elgg_echo('email:resetpassword:subject'), $email, array(), 'email');
+ }
}
}
@@ -1255,130 +764,11 @@ function execute_new_password_request($user_guid, $conf_code) {
}
/**
- * Handles pages for password reset requests.
- *
- * @param unknown_type $page
- * @return unknown_type
- */
-function elgg_user_resetpassword_page_handler($page) {
- global $CONFIG;
-
- $user_guid = get_input('u');
- $code = get_input('c');
-
- $user = get_entity($user_guid);
-
- // don't check code here to avoid automated attacks
- if (!$user instanceof ElggUser) {
- register_error(elgg_echo('user:passwordreset:unknown_user'));
- forward();
- }
-
- $form_body = elgg_echo('user:resetpassword:reset_password_confirm') . "<br />";
-
- $form_body .= elgg_view('input/hidden', array(
- 'internalname' => 'u',
- 'value' => $user_guid
- ));
-
- $form_body .= elgg_view('input/hidden', array(
- 'internalname' => 'c',
- 'value' => $code
- ));
-
- $form_body .= elgg_view('input/submit', array(
- 'value' => elgg_echo('resetpassword')
- ));
-
- $form .= elgg_view('input/form', array(
- 'body' => $form_body,
- 'action' => $CONFIG->site->url . 'action/user/passwordreset'
- ));
-
- $title = elgg_echo('resetpassword');
- $content = elgg_view_title(elgg_echo('resetpassword')) . $form;
-
- page_draw($title, elgg_view_layout('one_column', $content));
-}
-
-/**
- * Set the validation status for a user.
- *
- * @param bool $status Validated (true) or false
- * @param string $method Optional method to say how a user was validated
- * @return bool
- */
-function set_user_validation_status($user_guid, $status, $method = '') {
- if (!$status) {
- $method = '';
- }
-
- if ($status) {
- if (
- (create_metadata($user_guid, 'validated', $status,'', 0, ACCESS_PUBLIC)) &&
- (create_metadata($user_guid, 'validated_method', $method,'', 0, ACCESS_PUBLIC))
- ) {
- return true;
- }
- } else {
- $validated = get_metadata_byname($user_guid, 'validated');
- $validated_method = get_metadata_byname($user_guid, 'validated_method');
-
- if (
- ($validated) &&
- ($validated_method) &&
- (delete_metadata($validated->id)) &&
- (delete_metadata($validated_method->id))
- )
- return true;
- }
-
- return false;
-}
-
-/**
- * Trigger an event requesting that a user guid be validated somehow - either by email address or some other way.
- *
- * This event invalidates any existing values and returns
- *
- * @param unknown_type $user_guid
- */
-function request_user_validation($user_guid) {
- $user = get_entity($user_guid);
-
- if (($user) && ($user instanceof ElggUser)) {
- // invalidate any existing validations
- set_user_validation_status($user_guid, false);
-
- // request validation
- trigger_elgg_event('validate', 'user', $user);
- }
-}
-
-/**
- * Validates an email address.
- *
- * @param string $address Email address.
- * @return bool
- */
-function is_email_address($address) {
- // TODO: Make this better!
-
- if (strpos($address, '@')=== false) {
- return false;
- }
-
- if (strpos($address, '.')=== false) {
- return false;
- }
-
- return true;
-}
-
-/**
- * Simple function that will generate a random clear text password suitable for feeding into generate_user_password().
+ * Simple function that will generate a random clear text password
+ * suitable for feeding into generate_user_password().
*
* @see generate_user_password
+ *
* @return string
*/
function generate_random_cleartext_password() {
@@ -1388,10 +778,10 @@ function generate_random_cleartext_password() {
/**
* Generate a password for a user, currently uses MD5.
*
- * Later may introduce salting etc.
+ * @param ElggUser $user The user this is being generated for.
+ * @param string $password Password in clear text
*
- * @param ElggUser $user The user this is being generated for.
- * @param string $password Password in clear text
+ * @return string
*/
function generate_user_password(ElggUser $user, $password) {
return md5($password . $user->salt);
@@ -1402,7 +792,9 @@ function generate_user_password(ElggUser $user, $password) {
*
* This should only permit chars that are valid on the file system as well.
*
- * @param string $username
+ * @param string $username Username
+ *
+ * @return bool
* @throws RegistrationException on invalid
*/
function validate_username($username) {
@@ -1414,57 +806,80 @@ function validate_username($username) {
}
if (strlen($username) < $CONFIG->minusername) {
- throw new RegistrationException(elgg_echo('registration:usernametooshort'));
+ $msg = elgg_echo('registration:usernametooshort', array($CONFIG->minusername));
+ throw new RegistrationException($msg);
+ }
+
+ // username in the database has a limit of 128 characters
+ if (strlen($username) > 128) {
+ $msg = elgg_echo('registration:usernametoolong', array(128));
+ throw new RegistrationException($msg);
}
// Blacklist for bad characters (partially nicked from mediawiki)
-
$blacklist = '/[' .
- '\x{0080}-\x{009f}' . # iso-8859-1 control chars
- '\x{00a0}' . # non-breaking space
- '\x{2000}-\x{200f}' . # various whitespace
- '\x{2028}-\x{202f}' . # breaks and control chars
- '\x{3000}' . # ideographic space
- '\x{e000}-\x{f8ff}' . # private use
+ '\x{0080}-\x{009f}' . // iso-8859-1 control chars
+ '\x{00a0}' . // non-breaking space
+ '\x{2000}-\x{200f}' . // various whitespace
+ '\x{2028}-\x{202f}' . // breaks and control chars
+ '\x{3000}' . // ideographic space
+ '\x{e000}-\x{f8ff}' . // private use
']/u';
if (
preg_match($blacklist, $username)
) {
+ // @todo error message needs work
throw new RegistrationException(elgg_echo('registration:invalidchars'));
}
- // Belts and braces TODO: Tidy into main unicode
+ // Belts and braces
+ // @todo Tidy into main unicode
$blacklist2 = '\'/\\"*& ?#%^(){}[]~?<>;|¬`@-+=';
- for ($n=0; $n < strlen($blacklist2); $n++) {
- if (strpos($username, $blacklist2[$n])!==false) {
- throw new RegistrationException(sprintf(elgg_echo('registration:invalidchars'), $blacklist2[$n], $blacklist2));
+
+ for ($n = 0; $n < strlen($blacklist2); $n++) {
+ if (strpos($username, $blacklist2[$n]) !== false) {
+ $msg = elgg_echo('registration:invalidchars', array($blacklist2[$n], $blacklist2));
+ $msg = htmlspecialchars($msg, ENT_QUOTES, 'UTF-8');
+ throw new RegistrationException($msg);
}
}
$result = true;
- return trigger_plugin_hook('registeruser:validate:username', 'all', array('username' => $username), $result);
+ return elgg_trigger_plugin_hook('registeruser:validate:username', 'all',
+ array('username' => $username), $result);
}
/**
* Simple validation of a password.
*
- * @param string $password
+ * @param string $password Clear text password
+ *
+ * @return bool
* @throws RegistrationException on invalid
*/
function validate_password($password) {
- if (strlen($password) < 6) {
- throw new RegistrationException(elgg_echo('registration:passwordtooshort'));
+ global $CONFIG;
+
+ if (!isset($CONFIG->min_password_length)) {
+ $CONFIG->min_password_length = 6;
+ }
+
+ if (strlen($password) < $CONFIG->min_password_length) {
+ $msg = elgg_echo('registration:passwordtooshort', array($CONFIG->min_password_length));
+ throw new RegistrationException($msg);
}
$result = true;
- return trigger_plugin_hook('registeruser:validate:password', 'all', array('password' => $password), $result);
+ return elgg_trigger_plugin_hook('registeruser:validate:password', 'all',
+ array('password' => $password), $result);
}
/**
* Simple validation of a email.
*
- * @param string $address
+ * @param string $address Email address
+ *
* @throws RegistrationException on invalid
* @return bool
*/
@@ -1475,27 +890,30 @@ function validate_email_address($address) {
// Got here, so lets try a hook (defaulting to ok)
$result = true;
- return trigger_plugin_hook('registeruser:validate:email', 'all', array('email' => $address), $result);
+ return elgg_trigger_plugin_hook('registeruser:validate:email', 'all',
+ array('email' => $address), $result);
}
/**
* Registers a user, returning false if the username already exists
*
- * @param string $username The username of the new user
- * @param string $password The password
- * @param string $name The user's display name
- * @param string $email Their email address
- * @param bool $allow_multiple_emails Allow the same email address to be registered multiple times?
- * @param int $friend_guid Optionally, GUID of a user this user will friend once fully registered
+ * @param string $username The username of the new user
+ * @param string $password The password
+ * @param string $name The user's display name
+ * @param string $email Their email address
+ * @param bool $allow_multiple_emails Allow the same email address to be
+ * registered multiple times?
+ * @param int $friend_guid GUID of a user to friend once fully registered
+ * @param string $invitecode An invite code from a friend
+ *
* @return int|false The new user's GUID; false on failure
+ * @throws RegistrationException
*/
-function register_user($username, $password, $name, $email, $allow_multiple_emails = false, $friend_guid = 0, $invitecode = '') {
- // Load the configuration
- global $CONFIG;
+function register_user($username, $password, $name, $email,
+$allow_multiple_emails = false, $friend_guid = 0, $invitecode = '') {
- $username = trim($username);
// no need to trim password.
- $password = $password;
+ $username = trim($username);
$name = trim(strip_tags($name));
$email = trim($email);
@@ -1507,39 +925,33 @@ function register_user($username, $password, $name, $email, $allow_multiple_emai
return false;
}
- // See if it exists and is disabled
+ // Make sure a user with conflicting details hasn't registered and been disabled
$access_status = access_get_show_hidden_status();
access_show_hidden_entities(true);
- // Validate email address
if (!validate_email_address($email)) {
throw new RegistrationException(elgg_echo('registration:emailnotvalid'));
}
- // Validate password
if (!validate_password($password)) {
throw new RegistrationException(elgg_echo('registration:passwordnotvalid'));
}
- // Validate the username
if (!validate_username($username)) {
throw new RegistrationException(elgg_echo('registration:usernamenotvalid'));
}
- // Check to see if $username exists already
if ($user = get_user_by_username($username)) {
- //return false;
throw new RegistrationException(elgg_echo('registration:userexists'));
}
- // If we're not allowed multiple emails then see if this address has been used before
if ((!$allow_multiple_emails) && (get_user_by_email($email))) {
throw new RegistrationException(elgg_echo('registration:dupeemail'));
}
access_show_hidden_entities($access_status);
- // Otherwise ...
+ // Create user
$user = new ElggUser();
$user->username = $username;
$user->email = $email;
@@ -1549,6 +961,7 @@ function register_user($username, $password, $name, $email, $allow_multiple_emai
$user->password = generate_user_password($user, $password);
$user->owner_guid = 0; // Users aren't owned by anyone, even if they are admin created.
$user->container_guid = 0; // Users aren't contained by anyone, even if they are admin created.
+ $user->language = get_current_language();
$user->save();
// If $friend_guid has been set, make mutual friends
@@ -1559,26 +972,12 @@ function register_user($username, $password, $name, $email, $allow_multiple_emai
$friend_user->addFriend($user->guid);
// @todo Should this be in addFriend?
- add_to_river('friends/river/create', 'friend', $user->getGUID(), $friend_guid);
- add_to_river('friends/river/create', 'friend', $friend_guid, $user->getGUID());
+ add_to_river('river/relationship/friend/create', 'friend', $user->getGUID(), $friend_guid);
+ add_to_river('river/relationship/friend/create', 'friend', $friend_guid, $user->getGUID());
}
}
}
- // Check to see if we've registered the first admin yet.
- // If not, this is the first admin user!
- $have_admin = datalist_get('admin_registered');
- global $registering_admin;
-
- if (!$have_admin) {
- $user->makeAdmin();
- set_user_validation_status($user->getGUID(), TRUE, 'first_run');
- datalist_set('admin_registered', 1);
- $registering_admin = true;
- } else {
- $registering_admin = false;
- }
-
// Turn on email notifications by default
set_user_notification_setting($user->getGUID(), 'email', true);
@@ -1589,6 +988,7 @@ function register_user($username, $password, $name, $email, $allow_multiple_emai
* Generates a unique invite code for a user
*
* @param string $username The username of the user sending the invitation
+ *
* @return string Invite code
*/
function generate_invite_code($username) {
@@ -1597,289 +997,607 @@ function generate_invite_code($username) {
}
/**
- * Adds collection submenu items
+ * Set the validation status for a user.
*
+ * @param int $user_guid The user's GUID
+ * @param bool $status Validated (true) or unvalidated (false)
+ * @param string $method Optional method to say how a user was validated
+ * @return bool
+ * @since 1.8.0
*/
-function collections_submenu_items() {
- global $CONFIG;
- $user = get_loggedin_user();
- add_submenu_item(elgg_echo('friends:collections'), $CONFIG->wwwroot . "pg/collections/" . $user->username);
- add_submenu_item(elgg_echo('friends:collections:add'), $CONFIG->wwwroot . "pg/collections/add");
+function elgg_set_user_validation_status($user_guid, $status, $method = '') {
+ $result1 = create_metadata($user_guid, 'validated', $status, '', 0, ACCESS_PUBLIC, false);
+ $result2 = create_metadata($user_guid, 'validated_method', $method, '', 0, ACCESS_PUBLIC, false);
+ if ($result1 && $result2) {
+ return true;
+ } else {
+ return false;
+ }
}
/**
- * Page handler for friends
+ * Gets the validation status of a user.
*
+ * @param int $user_guid The user's GUID
+ * @return bool|null Null means status was not set for this user.
+ * @since 1.8.0
*/
-function friends_page_handler($page_elements) {
- if (isset($page_elements[0]) && $user = get_user_by_username($page_elements[0])) {
- set_page_owner($user->getGUID());
+function elgg_get_user_validation_status($user_guid) {
+ $md = elgg_get_metadata(array(
+ 'guid' => $user_guid,
+ 'metadata_name' => 'validated'
+ ));
+ if ($md == false) {
+ return null;
}
- if (get_loggedin_userid() == page_owner()) {
- // collections_submenu_items(); disabled for now as we no longer use friends collections (replaced by shared access)
+
+ if ($md[0]->value) {
+ return true;
}
- require_once(dirname(dirname(dirname(__FILE__))) . "/friends/index.php");
+
+ return false;
}
/**
- * Page handler for friends of
+ * Adds collection submenu items
*
+ * @return void
+ * @access private
*/
-function friends_of_page_handler($page_elements) {
- if (isset($page_elements[0]) && $user = get_user_by_username($page_elements[0])) {
- set_page_owner($user->getGUID());
- }
- if (get_loggedin_userid() == page_owner()) {
- // collections_submenu_items(); disabled for now as we no longer use friends collections (replaced by shared access)
+function collections_submenu_items() {
+
+ $user = elgg_get_logged_in_user_entity();
+
+ elgg_register_menu_item('page', array(
+ 'name' => 'friends:view:collections',
+ 'text' => elgg_echo('friends:collections'),
+ 'href' => "collections/$user->username",
+ ));
+}
+
+/**
+ * Page handler for friends-related pages
+ *
+ * @param array $segments URL segments
+ * @param string $handler The first segment in URL used for routing
+ *
+ * @return bool
+ * @access private
+ */
+function friends_page_handler($segments, $handler) {
+ elgg_set_context('friends');
+
+ if (isset($segments[0]) && $user = get_user_by_username($segments[0])) {
+ elgg_set_page_owner_guid($user->getGUID());
+ }
+ if (elgg_get_logged_in_user_guid() == elgg_get_page_owner_guid()) {
+ collections_submenu_items();
+ }
+
+ switch ($handler) {
+ case 'friends':
+ require_once(dirname(dirname(dirname(__FILE__))) . "/pages/friends/index.php");
+ break;
+ case 'friendsof':
+ require_once(dirname(dirname(dirname(__FILE__))) . "/pages/friends/of.php");
+ break;
+ default:
+ return false;
}
- require_once(dirname(dirname(dirname(__FILE__))) . "/friends/of.php");
+ return true;
}
/**
* Page handler for friends collections
*
+ * @param array $page_elements Page elements
+ *
+ * @return bool
+ * @access private
*/
function collections_page_handler($page_elements) {
+ gatekeeper();
+ elgg_set_context('friends');
+ $base = elgg_get_config('path');
if (isset($page_elements[0])) {
if ($page_elements[0] == "add") {
- set_page_owner(get_loggedin_userid());
+ elgg_set_page_owner_guid(elgg_get_logged_in_user_guid());
collections_submenu_items();
- require_once(dirname(dirname(dirname(__FILE__))) . "/friends/add.php");
+ require_once "{$base}pages/friends/collections/add.php";
+ return true;
} else {
- if ($user = get_user_by_username($page_elements[0])) {
- set_page_owner($user->getGUID());
- if (get_loggedin_userid() == page_owner()) {
+ $user = get_user_by_username($page_elements[0]);
+ if ($user) {
+ elgg_set_page_owner_guid($user->getGUID());
+ if (elgg_get_logged_in_user_guid() == elgg_get_page_owner_guid()) {
collections_submenu_items();
}
- require_once(dirname(dirname(dirname(__FILE__))) . "/friends/collections.php");
+ require_once "{$base}pages/friends/collections/view.php";
+ return true;
}
}
}
+ return false;
}
/**
- * Page handler for dashboard
- */
-function dashboard_page_handler($page_elements) {
- require_once(dirname(dirname(dirname(__FILE__))) . "/dashboard/index.php");
-}
-
-
-/**
- * Page handler for registration
- */
-function registration_page_handler($page_elements) {
- require_once(dirname(dirname(dirname(__FILE__))) . "/account/register.php");
-}
-
-/**
- * Display a login box.
+ * Page handler for account related pages
+ *
+ * @param array $page_elements Page elements
+ * @param string $handler The handler string
*
- * This is a fallback for non-JS users who click on the
- * dropdown login link.
+ * @return bool
+ * @access private
*/
-function elgg_user_login_page_handler() {
- $content = elgg_view_layout('one_column', elgg_view('account/forms/login'));
- $content = '
- <div id="elgg_content" class="clearfloat">
- ' . elgg_view('account/forms/login') . '
- </div>
- ';
- page_draw('test', $content);
+function elgg_user_account_page_handler($page_elements, $handler) {
+
+ $base_dir = elgg_get_root_path() . 'pages/account';
+ switch ($handler) {
+ case 'login':
+ require_once("$base_dir/login.php");
+ break;
+ case 'forgotpassword':
+ require_once("$base_dir/forgotten_password.php");
+ break;
+ case 'resetpassword':
+ require_once("$base_dir/reset_password.php");
+ break;
+ case 'register':
+ require_once("$base_dir/register.php");
+ break;
+ default:
+ return false;
+ }
+ return true;
}
/**
* Sets the last action time of the given user to right now.
*
* @param int $user_guid The user GUID
+ *
+ * @return void
*/
function set_last_action($user_guid) {
$user_guid = (int) $user_guid;
global $CONFIG;
$time = time();
- execute_delayed_write_query("UPDATE {$CONFIG->dbprefix}users_entity set prev_last_action = last_action, last_action = {$time} where guid = {$user_guid}");
+ $query = "UPDATE {$CONFIG->dbprefix}users_entity
+ set prev_last_action = last_action,
+ last_action = {$time} where guid = {$user_guid}";
+
+ execute_delayed_write_query($query);
}
/**
* Sets the last logon time of the given user to right now.
*
* @param int $user_guid The user GUID
+ *
+ * @return void
*/
function set_last_login($user_guid) {
$user_guid = (int) $user_guid;
global $CONFIG;
$time = time();
- execute_delayed_write_query("UPDATE {$CONFIG->dbprefix}users_entity set prev_last_login = last_login, last_login = {$time} where guid = {$user_guid}");
+ $query = "UPDATE {$CONFIG->dbprefix}users_entity
+ set prev_last_login = last_login, last_login = {$time} where guid = {$user_guid}";
+
+ execute_delayed_write_query($query);
}
/**
- * A permissions plugin hook that grants access to users if they are newly created - allows
- * for email activation.
+ * Creates a relationship between this site and the user.
*
- * TODO: Do this in a better way!
+ * @param string $event create
+ * @param string $object_type user
+ * @param ElggUser $object User object
*
- * @param unknown_type $hook
- * @param unknown_type $entity_type
- * @param unknown_type $returnvalue
- * @param unknown_type $params
+ * @return void
+ * @access private
*/
-function new_user_enable_permissions_check($hook, $entity_type, $returnvalue, $params) {
- $entity = $params['entity'];
- $user = $params['user'];
- if (($entity) && ($entity instanceof ElggUser)) {
- if (
- (($entity->disable_reason == 'new_user') || (
- // if this isn't set at all they're a "new user"
- !$entity->validated
- ))
- && (!isloggedin())) {
- return true;
+function user_create_hook_add_site_relationship($event, $object_type, $object) {
+ add_entity_relationship($object->getGUID(), 'member_of_site', elgg_get_site_entity()->guid);
+}
+
+/**
+ * Serves the user's avatar
+ *
+ * @param string $hook
+ * @param string $entity_type
+ * @param string $returnvalue
+ * @param array $params
+ * @return string
+ * @access private
+ */
+function user_avatar_hook($hook, $entity_type, $returnvalue, $params) {
+ $user = $params['entity'];
+ $size = $params['size'];
+
+ if (isset($user->icontime)) {
+ return "avatar/view/$user->username/$size/$user->icontime";
+ } else {
+ return "_graphics/icons/user/default{$size}.gif";
+ }
+}
+
+/**
+ * Setup the default user hover menu
+ * @access private
+ */
+function elgg_user_hover_menu($hook, $type, $return, $params) {
+ $user = $params['entity'];
+ /* @var ElggUser $user */
+
+ if (elgg_is_logged_in()) {
+ if (elgg_get_logged_in_user_guid() != $user->guid) {
+ if ($user->isFriend()) {
+ $url = "action/friends/remove?friend={$user->guid}";
+ $text = elgg_echo('friend:remove');
+ $name = 'remove_friend';
+ } else {
+ $url = "action/friends/add?friend={$user->guid}";
+ $text = elgg_echo('friend:add');
+ $name = 'add_friend';
+ }
+ $url = elgg_add_action_tokens_to_url($url);
+ $item = new ElggMenuItem($name, $text, $url);
+ $item->setSection('action');
+ $return[] = $item;
+ } else {
+ $url = "profile/$user->username/edit";
+ $item = new ElggMenuItem('profile:edit', elgg_echo('profile:edit'), $url);
+ $item->setSection('action');
+ $return[] = $item;
+
+ $url = "avatar/edit/$user->username";
+ $item = new ElggMenuItem('avatar:edit', elgg_echo('avatar:edit'), $url);
+ $item->setSection('action');
+ $return[] = $item;
+ }
+ }
+
+ // prevent admins from banning or deleting themselves
+ if (elgg_get_logged_in_user_guid() == $user->guid) {
+ return $return;
+ }
+
+ if (elgg_is_admin_logged_in()) {
+ $actions = array();
+ if (!$user->isBanned()) {
+ $actions[] = 'ban';
+ } else {
+ $actions[] = 'unban';
+ }
+ $actions[] = 'delete';
+ $actions[] = 'resetpassword';
+ if (!$user->isAdmin()) {
+ $actions[] = 'makeadmin';
+ } else {
+ $actions[] = 'removeadmin';
+ }
+
+ foreach ($actions as $action) {
+ $url = "action/admin/user/$action?guid={$user->guid}";
+ $url = elgg_add_action_tokens_to_url($url);
+ $item = new ElggMenuItem($action, elgg_echo($action), $url);
+ $item->setSection('admin');
+ $item->setLinkClass('elgg-requires-confirmation');
+
+ $return[] = $item;
}
+
+ $url = "profile/$user->username/edit";
+ $item = new ElggMenuItem('profile:edit', elgg_echo('profile:edit'), $url);
+ $item->setSection('admin');
+ $return[] = $item;
+
+ $url = "settings/user/$user->username";
+ $item = new ElggMenuItem('settings:edit', elgg_echo('settings:edit'), $url);
+ $item->setSection('admin');
+ $return[] = $item;
}
- return $returnvalue;
+ return $return;
}
/**
- * Creates a relationship between this site and the user.
+ * Setup the menu shown with an entity
*
- * @param $event
- * @param $object_type
- * @param $object
- * @return bool
+ * @param string $hook
+ * @param string $type
+ * @param array $return
+ * @param array $params
+ * @return array
+ *
+ * @access private
*/
-function user_create_hook_add_site_relationship($event, $object_type, $object) {
- global $CONFIG;
+function elgg_users_setup_entity_menu($hook, $type, $return, $params) {
+ if (elgg_in_context('widgets')) {
+ return $return;
+ }
- add_entity_relationship($object->getGUID(), 'member_of_site', $CONFIG->site->getGUID());
+ $entity = $params['entity'];
+ if (!elgg_instanceof($entity, 'user')) {
+ return $return;
+ }
+ /* @var ElggUser $entity */
+
+ if ($entity->isBanned()) {
+ $banned = elgg_echo('banned');
+ $options = array(
+ 'name' => 'banned',
+ 'text' => "<span>$banned</span>",
+ 'href' => false,
+ 'priority' => 0,
+ );
+ $return = array(ElggMenuItem::factory($options));
+ } else {
+ $return = array();
+ if (isset($entity->location)) {
+ $location = htmlspecialchars($entity->location, ENT_QUOTES, 'UTF-8', false);
+ $options = array(
+ 'name' => 'location',
+ 'text' => "<span>$location</span>",
+ 'href' => false,
+ 'priority' => 150,
+ );
+ $return[] = ElggMenuItem::factory($options);
+ }
+ }
+
+ return $return;
}
/**
- * Sets up user-related menu items
+ * This function loads a set of default fields into the profile, then triggers a hook letting other plugins to edit
+ * add and delete fields.
*
+ * Note: This is a secondary system:init call and is run at a super low priority to guarantee that it is called after all
+ * other plugins have initialised.
+ * @access private
*/
-function users_pagesetup() {
- // Load config
+function elgg_profile_fields_setup() {
global $CONFIG;
- //add submenu options
- if (get_context() == "friends" || get_context() == "friendsof") { // || get_context() == "collections") { - disabled as we no longer use collections
- add_submenu_item(elgg_echo('friends'),$CONFIG->wwwroot."pg/friends/" . page_owner_entity()->username);
- add_submenu_item(elgg_echo('friends:of'),$CONFIG->wwwroot."pg/friendsof/" . page_owner_entity()->username);
- if(is_plugin_enabled('members'))
- add_submenu_item(elgg_echo('members:browse'), $CONFIG->wwwroot . "mod/members/index.php");
+ $profile_defaults = array (
+ 'description' => 'longtext',
+ 'briefdescription' => 'text',
+ 'location' => 'location',
+ 'interests' => 'tags',
+ 'skills' => 'tags',
+ 'contactemail' => 'email',
+ 'phone' => 'text',
+ 'mobile' => 'text',
+ 'website' => 'url',
+ 'twitter' => 'text'
+ );
+
+ $loaded_defaults = array();
+ if ($fieldlist = elgg_get_config('profile_custom_fields')) {
+ if (!empty($fieldlist)) {
+ $fieldlistarray = explode(',', $fieldlist);
+ foreach ($fieldlistarray as $listitem) {
+ if ($translation = elgg_get_config("admin_defined_profile_{$listitem}")) {
+ $type = elgg_get_config("admin_defined_profile_type_{$listitem}");
+ $loaded_defaults["admin_defined_profile_{$listitem}"] = $type;
+ add_translation(get_current_language(), array("profile:admin_defined_profile_{$listitem}" => $translation));
+ }
+ }
+ }
+ }
+
+ if (count($loaded_defaults)) {
+ $CONFIG->profile_using_custom = true;
+ $profile_defaults = $loaded_defaults;
+ }
+
+ $CONFIG->profile_fields = elgg_trigger_plugin_hook('profile:fields', 'profile', NULL, $profile_defaults);
+
+ // register any tag metadata names
+ foreach ($CONFIG->profile_fields as $name => $type) {
+ if ($type == 'tags' || $type == 'location' || $type == 'tag') {
+ elgg_register_tag_metadata_name($name);
+ // register a tag name translation
+ add_translation(get_current_language(), array("tag_names:$name" => elgg_echo("profile:$name")));
+ }
}
}
/**
- * Users initialisation function, which establishes the page handler
+ * Avatar page handler
*
+ * /avatar/edit/<username>
+ * /avatar/view/<username>/<size>/<icontime>
+ *
+ * @param array $page
+ * @return bool
+ * @access private
*/
-function users_init() {
- // Load config
+function elgg_avatar_page_handler($page) {
global $CONFIG;
- // add Friends to tools menu - if profile mod is running
- // now added to toolbar
- /*
- if ( isloggedin() && is_plugin_enabled('profile') ) {
- $user = get_loggedin_user();
- add_menu(elgg_echo('friends'), $CONFIG->wwwroot . "pg/friends/" . $user->username, array(), 'core:friends');
+ $user = get_user_by_username($page[1]);
+ if ($user) {
+ elgg_set_page_owner_guid($user->getGUID());
}
- */
-
- register_page_handler('friends', 'friends_page_handler');
- register_page_handler('friendsof', 'friends_of_page_handler');
- register_page_handler('dashboard', 'dashboard_page_handler');
- register_page_handler('register', 'registration_page_handler');
- register_page_handler('resetpassword', 'elgg_user_resetpassword_page_handler');
- register_page_handler('login', 'elgg_user_login_page_handler');
-
- register_action("register", true);
- register_action("useradd", true);
- register_action("friends/add");
- register_action("friends/remove");
- //register_action('friends/addcollection');
- //register_action('friends/deletecollection');
- //register_action('friends/editcollection');
- //register_action("user/spotlight");
- register_action("usersettings/save");
-
- register_action("user/passwordreset", TRUE);
- register_action("user/requestnewpassword", TRUE);
+ if ($page[0] == 'edit') {
+ require_once("{$CONFIG->path}pages/avatar/edit.php");
+ return true;
+ } else {
+ set_input('size', $page[2]);
+ require_once("{$CONFIG->path}pages/avatar/view.php");
+ return true;
+ }
+ return false;
+}
- // User name change
- extend_elgg_settings_page('user/settings/name', 'usersettings/user', 1);
- //register_action("user/name");
+/**
+ * Profile page handler
+ *
+ * @param array $page
+ * @return bool
+ * @access private
+ */
+function elgg_profile_page_handler($page) {
+ global $CONFIG;
- // User password change
- extend_elgg_settings_page('user/settings/password', 'usersettings/user', 1);
- //register_action("user/password");
+ $user = get_user_by_username($page[0]);
+ elgg_set_page_owner_guid($user->guid);
- // Add email settings
- extend_elgg_settings_page('user/settings/email', 'usersettings/user', 1);
- //register_action("email/save");
+ if ($page[1] == 'edit') {
+ require_once("{$CONFIG->path}pages/profile/edit.php");
+ return true;
+ }
+ return false;
+}
- // Add language settings
- extend_elgg_settings_page('user/settings/language', 'usersettings/user', 1);
+/**
+ * Sets up user-related menu items
+ *
+ * @return void
+ * @access private
+ */
+function users_pagesetup() {
- // Add default access settings
- extend_elgg_settings_page('user/settings/default_access', 'usersettings/user', 1);
+ $owner = elgg_get_page_owner_entity();
+ $viewer = elgg_get_logged_in_user_entity();
+
+ if ($owner) {
+ $params = array(
+ 'name' => 'friends',
+ 'text' => elgg_echo('friends'),
+ 'href' => 'friends/' . $owner->username,
+ 'contexts' => array('friends')
+ );
+ elgg_register_menu_item('page', $params);
+
+ $params = array(
+ 'name' => 'friends:of',
+ 'text' => elgg_echo('friends:of'),
+ 'href' => 'friendsof/' . $owner->username,
+ 'contexts' => array('friends')
+ );
+ elgg_register_menu_item('page', $params);
+
+ elgg_register_menu_item('page', array(
+ 'name' => 'edit_avatar',
+ 'href' => "avatar/edit/{$owner->username}",
+ 'text' => elgg_echo('avatar:edit'),
+ 'contexts' => array('profile_edit'),
+ ));
- //register_action("user/language");
+ elgg_register_menu_item('page', array(
+ 'name' => 'edit_profile',
+ 'href' => "profile/{$owner->username}/edit",
+ 'text' => elgg_echo('profile:edit'),
+ 'contexts' => array('profile_edit'),
+ ));
+ }
- // Register the user type
- register_entity_type('user','');
+ // topbar
+ if ($viewer) {
+ elgg_register_menu_item('topbar', array(
+ 'name' => 'profile',
+ 'href' => $viewer->getURL(),
+ 'text' => elgg_view('output/img', array(
+ 'src' => $viewer->getIconURL('topbar'),
+ 'alt' => $viewer->name,
+ 'title' => elgg_echo('profile'),
+ 'class' => 'elgg-border-plain elgg-transition',
+ )),
+ 'priority' => 100,
+ 'link_class' => 'elgg-topbar-avatar',
+ ));
- register_plugin_hook('usersettings:save','user','users_settings_save');
+ elgg_register_menu_item('topbar', array(
+ 'name' => 'friends',
+ 'href' => "friends/{$viewer->username}",
+ 'text' => elgg_view_icon('users'),
+ 'title' => elgg_echo('friends'),
+ 'priority' => 300,
+ ));
- register_elgg_event_handler('create', 'user', 'user_create_hook_add_site_relationship');
+ elgg_register_menu_item('topbar', array(
+ 'name' => 'usersettings',
+ 'href' => "settings/user/{$viewer->username}",
+ 'text' => elgg_view_icon('settings') . elgg_echo('settings'),
+ 'priority' => 500,
+ 'section' => 'alt',
+ ));
- // Handle a special case for newly created users when the user is not logged in
- // TODO: handle this better!
- register_plugin_hook('permissions_check','all','new_user_enable_permissions_check');
+ elgg_register_menu_item('topbar', array(
+ 'name' => 'logout',
+ 'href' => "action/logout",
+ 'text' => elgg_echo('logout'),
+ 'is_action' => TRUE,
+ 'priority' => 1000,
+ 'section' => 'alt',
+ ));
+ }
}
/**
- * Returns a formatted list of users suitable for injecting into search.
- * @deprecated 1.7
+ * Users initialisation function, which establishes the page handler
+ *
+ * @return void
+ * @access private
*/
-function search_list_users_by_name($hook, $user, $returnvalue, $tag) {
- elgg_deprecated_notice('search_list_users_by_name() was deprecated by new search', 1.7);
- // Change this to set the number of users that display on the search page
- $threshold = 4;
+function users_init() {
- $object = get_input('object');
+ elgg_register_page_handler('friends', 'friends_page_handler');
+ elgg_register_page_handler('friendsof', 'friends_page_handler');
+ elgg_register_page_handler('register', 'elgg_user_account_page_handler');
+ elgg_register_page_handler('forgotpassword', 'elgg_user_account_page_handler');
+ elgg_register_page_handler('resetpassword', 'elgg_user_account_page_handler');
+ elgg_register_page_handler('login', 'elgg_user_account_page_handler');
+ elgg_register_page_handler('avatar', 'elgg_avatar_page_handler');
+ elgg_register_page_handler('profile', 'elgg_profile_page_handler');
+ elgg_register_page_handler('collections', 'collections_page_handler');
- if (!get_input('offset') && (empty($object) || $object == 'user')) {
- if ($users = search_for_user($tag,$threshold)) {
- $countusers = search_for_user($tag,0,0,"",true);
+ elgg_register_plugin_hook_handler('register', 'menu:user_hover', 'elgg_user_hover_menu');
- $return = elgg_view('user/search/startblurb',array('count' => $countusers, 'tag' => $tag));
- foreach($users as $user) {
- $return .= elgg_view_entity($user);
- }
- $return .= elgg_view('user/search/finishblurb',array('count' => $countusers, 'threshold' => $threshold, 'tag' => $tag));
- return $return;
+ elgg_register_action('register', '', 'public');
+ elgg_register_action('useradd', '', 'admin');
+ elgg_register_action('friends/add');
+ elgg_register_action('friends/remove');
+ elgg_register_action('avatar/upload');
+ elgg_register_action('avatar/crop');
+ elgg_register_action('avatar/remove');
+ elgg_register_action('profile/edit');
- }
- }
-}
+ elgg_register_action('friends/collections/add');
+ elgg_register_action('friends/collections/delete');
+ elgg_register_action('friends/collections/edit');
-function users_settings_save() {
- global $CONFIG;
- include($CONFIG->path . "actions/user/name.php");
- include($CONFIG->path . "actions/user/password.php");
- include($CONFIG->path . "actions/email/save.php");
- include($CONFIG->path . "actions/user/language.php");
- include($CONFIG->path . "actions/user/default_access.php");
+ elgg_register_plugin_hook_handler('entity:icon:url', 'user', 'user_avatar_hook');
+
+ elgg_register_action('user/passwordreset', '', 'public');
+ elgg_register_action('user/requestnewpassword', '', 'public');
+
+ elgg_register_widget_type('friends', elgg_echo('friends'), elgg_echo('friends:widget:description'));
+
+ // Register the user type
+ elgg_register_entity_type('user', '');
+
+ elgg_register_plugin_hook_handler('register', 'menu:entity', 'elgg_users_setup_entity_menu', 501);
+
+ elgg_register_event_handler('create', 'user', 'user_create_hook_add_site_relationship');
}
/**
* Runs unit tests for ElggObject
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
*/
function users_test($hook, $type, $value, $params) {
global $CONFIG;
@@ -1887,7 +1605,7 @@ function users_test($hook, $type, $value, $params) {
return $value;
}
-//register actions *************************************************************
-register_elgg_event_handler('init','system','users_init',0);
-register_elgg_event_handler('pagesetup','system','users_pagesetup',0);
-register_plugin_hook('unit_test', 'system', 'users_test'); \ No newline at end of file
+elgg_register_event_handler('init', 'system', 'users_init', 0);
+elgg_register_event_handler('init', 'system', 'elgg_profile_fields_setup', 10000); // Ensure this runs after other plugins
+elgg_register_event_handler('pagesetup', 'system', 'users_pagesetup', 0);
+elgg_register_plugin_hook_handler('unit_test', 'system', 'users_test');
diff --git a/engine/lib/usersettings.php b/engine/lib/usersettings.php
deleted file mode 100644
index baaf41562..000000000
--- a/engine/lib/usersettings.php
+++ /dev/null
@@ -1,76 +0,0 @@
-<?php
-/**
- * Elgg user settings functions.
- * Functions for adding and manipulating options on the user settings panel.
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
- */
-
-/**
- * Register a user settings page with the admin panel.
- * This function extends the view "usersettings/main" with the provided view. This view should provide a description
- * and either a control or a link to.
- *
- * Usage:
- * - To add a control to the main admin panel then extend usersettings/main
- * - To add a control to a new page create a page which renders a view usersettings/subpage (where subpage is your new page -
- * nb. some pages already exist that you can extend), extend the main view to point to it, and add controls to your
- * new view.
- *
- * At the moment this is essentially a wrapper around elgg_extend_view().
- *
- * @param string $new_settings_view The view associated with the control you're adding
- * @param string $view The view to extend, by default this is 'usersettings/main'.
- * @param int $priority Optional priority to govern the appearance in the list.
- */
-function extend_elgg_settings_page( $new_settings_view, $view = 'usersettings/main', $priority = 500) {
- return elgg_extend_view($view, $new_settings_view, $priority);
-}
-
-function usersettings_pagesetup() {
- // Get config
- global $CONFIG;
-
- // Menu options
- if (get_context() == "settings") {
- $user = get_loggedin_user();
- add_submenu_item(elgg_echo('usersettings:user:opt:linktext'),$CONFIG->wwwroot . "pg/settings/user/{$user->username}/");
- add_submenu_item(elgg_echo('usersettings:plugins:opt:linktext'),$CONFIG->wwwroot . "pg/settings/plugins/{$user->username}/");
- add_submenu_item(elgg_echo('usersettings:statistics:opt:linktext'),$CONFIG->wwwroot . "pg/settings/statistics/{$user->username}/");
- }
-}
-
-function usersettings_page_handler($page) {
- global $CONFIG;
-
- $path = $CONFIG->path . "settings/index.php";
-
- if ($page[0]) {
- switch ($page[0]) {
- case 'user' : $path = $CONFIG->path . "settings/user.php"; break;
- case 'statistics' : $path = $CONFIG->path . "settings/statistics.php"; break;
- case 'plugins' : $path = $CONFIG->path . "settings/plugins.php"; break;
- }
- }
-
- if ($page[1]) {
- set_input('username', $page[1]);
- }
-
- include($path);
-}
-
-/**
- * Initialise the admin page.
- */
-function usersettings_init() {
- // Page handler
- register_page_handler('settings','usersettings_page_handler');
-}
-
-/// Register init function
-register_elgg_event_handler('init','system','usersettings_init');
-register_elgg_event_handler('pagesetup','system','usersettings_pagesetup'); \ No newline at end of file
diff --git a/engine/lib/version.php b/engine/lib/version.php
deleted file mode 100644
index 5322e5afa..000000000
--- a/engine/lib/version.php
+++ /dev/null
@@ -1,132 +0,0 @@
-<?php
-/**
- * Elgg version library.
- * Contains code for handling versioning and upgrades.
- *
- * @package Elgg
- * @subpackage Core
- * @link http://elgg.org/
- */
-
-/**
- * Run any php upgrade scripts which are required
- *
- * @param int $version Version upgrading from.
- * @param bool $quiet Suppress errors. Don't use this.
- */
-function upgrade_code($version, $quiet = FALSE) {
- global $CONFIG;
-
- // Elgg and its database must be installed to upgrade it!
- if (!is_db_installed() || !is_installed()) {
- return FALSE;
- }
-
- $version = (int) $version;
-
- if ($handle = opendir($CONFIG->path . 'engine/lib/upgrades/')) {
- $upgrades = array();
-
- while ($updatefile = readdir($handle)) {
- // Look for upgrades and add to upgrades list
- if (!is_dir($CONFIG->path . 'engine/lib/upgrades/' . $updatefile)) {
- if (preg_match('/^([0-9]{10})\.(php)$/', $updatefile, $matches)) {
- $core_version = (int) $matches[1];
- if ($core_version > $version) {
- $upgrades[] = $updatefile;
- }
- }
- }
- }
-
- // Sort and execute
- asort($upgrades);
-
- if (sizeof($upgrades) > 0) {
- foreach($upgrades as $upgrade) {
- // hide all errors.
- if ($quiet) {
- // hide include errors as well as any exceptions that might happen
- try {
- if (!@include($CONFIG->path . 'engine/lib/upgrades/' . $upgrade)) {
- error_log($e->getmessage());
- }
- } catch (Exception $e) {
- error_log($e->getmessage());
- }
- } else {
- include($CONFIG->path . 'engine/lib/upgrades/' . $upgrade);
- }
- }
- }
-
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * Get the current version information
- *
- * @param true|false $humanreadable Whether to return a human readable version (default: false)
- * @return string|false Depending on success
- */
-function get_version($humanreadable = false) {
- global $CONFIG;
-
- if (include($CONFIG->path . "version.php")) {
- return (!$humanreadable) ? $version : $release;
- }
-
- return FALSE;
-}
-
-/**
- * Determines whether or not the database needs to be upgraded.
- *
- * @return true|false Depending on whether or not the db version matches the code version
- */
-function version_upgrade_check() {
- $dbversion = (int) datalist_get('version');
- $version = get_version();
-
- if ($version > $dbversion) {
- return TRUE;
- }
-
- return FALSE;
-}
-
-/**
- * Upgrades Elgg
- *
- */
-function version_upgrade() {
- $dbversion = (int) datalist_get('version');
-
- // No version number? Oh snap...this is an upgrade from a clean installation < 1.7.
- // Run all upgrades without error reporting and hope for the best.
- // See http://trac.elgg.org/elgg/ticket/1432 for more.
- $quiet = !$dbversion;
-
- // Upgrade database
- if (db_upgrade($dbversion, '', $quiet)) {
- system_message(elgg_echo('upgrade:db'));
- }
-
- // Upgrade core
- if (upgrade_code($dbversion, $quiet)) {
- system_message(elgg_echo('upgrade:core'));
- }
-
- // Now we trigger an event to give the option for plugins to do something
- $upgrade_details = new stdClass;
- $upgrade_details->from = $dbversion;
- $upgrade_details->to = get_version();
-
- trigger_elgg_event('upgrade', 'upgrade', $upgrade_details);
-
- // Update the version
- datalist_set('version', get_version());
-}
diff --git a/engine/lib/views.php b/engine/lib/views.php
index c1c07024a..1142461fe 100644
--- a/engine/lib/views.php
+++ b/engine/lib/views.php
@@ -1,20 +1,74 @@
-<?php
+<?php
/**
- * Provides interfaces for Elgg's views system
- *
- * @package Elgg
+ * Elgg's view system.
+ *
+ * The view system is the primary templating engine in Elgg and renders
+ * all output. Views are short, parameterised PHP scripts for displaying
+ * output that can be regsitered, overridden, or extended. The view type
+ * determines the output format and location of the files that renders the view.
+ *
+ * Elgg uses a two step process to render full output: first
+ * content-specific elements are rendered, then the resulting
+ * content is inserted into a layout and displayed. This makes it
+ * easy to maintain a consistent look on all pages.
+ *
+ * A view corresponds to a single file on the filesystem and the views
+ * name is its directory structure. A file in
+ * <code>mod/plugins/views/default/myplugin/example.php</code>
+ * is called by saying (with the default viewtype):
+ * <code>echo elgg_view('myplugin/example');</code>
+ *
+ * View names that are registered later override those that are
+ * registered earlier. For plugins this corresponds directly
+ * to their load order: views in plugins lower in the list override
+ * those higher in the list.
+ *
+ * Plugin views belong in the views/ directory under an appropriate
+ * viewtype. Views are automatically registered.
+ *
+ * Views can be embedded-you can call a view from within a view.
+ * Views can also be prepended or extended by any other view.
+ *
+ * Any view can extend any other view if registered with
+ * {@link elgg_extend_view()}.
+ *
+ * View types are set by passing $_REQUEST['view']. The view type
+ * 'default' is a standard HTML view. Types can be defined on the fly
+ * and you can get the current view type with {@link get_current_view()}.
+ *
+ * @internal Plugin views are autoregistered before their init functions
+ * are called, so the init order doesn't affect views.
+ *
+ * @internal The file that determines the output of the view is the last
+ * registered by {@link elgg_set_view_location()}.
+ *
+ * @package Elgg.Core
+ * @subpackage Views
+ * @link http://docs.elgg.org/Views
*/
+/**
+ * The view type override.
+ *
+ * @global string $CURRENT_SYSTEM_VIEWTYPE
+ * @see elgg_set_viewtype()
+ */
+global $CURRENT_SYSTEM_VIEWTYPE;
$CURRENT_SYSTEM_VIEWTYPE = "";
/**
- * Override the view mode detection for the elgg view system.
+ * Manually set the viewtype.
+ *
+ * View types are detected automatically. This function allows
+ * you to force subsequent views to use a different viewtype.
*
- * This function will force any further views to be rendered using $viewtype. Remember to call elgg_set_viewtype() with
- * no parameters to reset.
+ * @tip Call elgg_set_viewtype() with no parameter to reset.
*
* @param string $viewtype The view type, e.g. 'rss', or 'default'.
+ *
* @return bool
+ * @link http://docs.elgg.org/Views/Viewtype
+ * @example views/viewtype.php
*/
function elgg_set_viewtype($viewtype = "") {
global $CURRENT_SYSTEM_VIEWTYPE;
@@ -25,48 +79,93 @@ function elgg_set_viewtype($viewtype = "") {
}
/**
- * Return the current view type used by the elgg view system.
+ * Return the current view type.
+ *
+ * View types are automatically detected and can be set with $_REQUEST['view']
+ * or {@link elgg_set_viewtype()}.
*
- * By default, this function will return a value based on the default for your system or from the command line
- * view parameter. However, you may force a given view type by calling elgg_set_viewtype()
+ * @internal View type is determined in this order:
+ * - $CURRENT_SYSTEM_VIEWTYPE Any overrides by {@link elgg_set_viewtype()}
+ * - $CONFIG->view The default view as saved in the DB.
+ * - $_SESSION['view']
*
* @return string The view.
+ * @see elgg_set_viewtype()
+ * @link http://docs.elgg.org/Views
+ * @todo This function's sessions stuff needs rewritten, removed, or explained.
*/
function elgg_get_viewtype() {
global $CURRENT_SYSTEM_VIEWTYPE, $CONFIG;
- $viewtype = NULL;
-
if ($CURRENT_SYSTEM_VIEWTYPE != "") {
return $CURRENT_SYSTEM_VIEWTYPE;
}
- if ((empty($_SESSION['view'])) || ( (trim($CONFIG->view!="")) && ($_SESSION['view']!=$CONFIG->view) )) {
- $_SESSION['view'] = "default";
- // If we have a config default view for this site then use that instead of 'default'
- if (/*(is_installed()) && */(!empty($CONFIG->view)) && (trim($CONFIG->view)!="")) {
- $_SESSION['view'] = $CONFIG->view;
+ $viewtype = get_input('view', '', false);
+ if (is_string($viewtype) && $viewtype !== '') {
+ // only word characters allowed.
+ if (!preg_match('/\W/', $viewtype)) {
+ return $viewtype;
}
}
- if (empty($viewtype) && is_callable('get_input')) {
- $viewtype = get_input('view');
+ if (!empty($CONFIG->view)) {
+ return $CONFIG->view;
}
- if (empty($viewtype)) {
- $viewtype = $_SESSION['view'];
+ return 'default';
+}
+
+/**
+ * Register a view type as valid.
+ *
+ * @param string $view_type The view type to register
+ * @return bool
+ */
+function elgg_register_viewtype($view_type) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->view_types) || !is_array($CONFIG->view_types)) {
+ $CONFIG->view_types = array();
}
- return $viewtype;
+ if (!in_array($view_type, $CONFIG->view_types)) {
+ $CONFIG->view_types[] = $view_type;
+ }
+
+ return true;
}
/**
- * Register a viewtype to fall back to a default view if view does not exist in
- * that viewtype.
+ * Checks if $view_type is valid on this installation.
*
- * This is useful for alternate html viewtypes (such as for mobile devices)
+ * @param string $view_type View type
+ *
+ * @return bool
+ * @since 1.7.2
+ * @access private
+ */
+function elgg_is_valid_view_type($view_type) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->view_types) || !is_array($CONFIG->view_types)) {
+ return FALSE;
+ }
+
+ return in_array($view_type, $CONFIG->view_types);
+}
+
+/**
+ * Register a viewtype to fall back to a default view if a view isn't
+ * found for that viewtype.
+ *
+ * @tip This is useful for alternate html viewtypes (such as for mobile devices).
*
* @param string $viewtype The viewtype to register
+ *
+ * @return void
+ * @since 1.7.2
+ * @example views/viewtype_fallback.php Fallback from mobile to default.
*/
function elgg_register_viewtype_fallback($viewtype) {
global $CONFIG;
@@ -83,10 +182,12 @@ function elgg_register_viewtype_fallback($viewtype) {
}
/**
- * Checks if this viewtype falls back to default
+ * Checks if a viewtype falls back to default.
+ *
+ * @param string $viewtype Viewtype
*
- * @param string $viewtype
* @return boolean
+ * @since 1.7.2
*/
function elgg_does_viewtype_fallback($viewtype) {
global $CONFIG;
@@ -94,16 +195,52 @@ function elgg_does_viewtype_fallback($viewtype) {
if (isset($CONFIG->viewtype) && isset($CONFIG->viewtype->fallback)) {
return in_array($viewtype, $CONFIG->viewtype->fallback);
}
-
+
return FALSE;
}
+/**
+ * Register a view to be available for ajax calls
+ *
+ * @param string $view The view name
+ * @return void
+ * @since 1.8.3
+ */
+function elgg_register_ajax_view($view) {
+ global $CONFIG;
+
+ if (!isset($CONFIG->allowed_ajax_views)) {
+ $CONFIG->allowed_ajax_views = array();
+ }
+
+ $CONFIG->allowed_ajax_views[$view] = true;
+}
+
+/**
+ * Unregister a view for ajax calls
+ *
+ * @param string $view The view name
+ * @return void
+ * @since 1.8.3
+ */
+function elgg_unregister_ajax_view($view) {
+ global $CONFIG;
+
+ if (isset($CONFIG->allowed_ajax_views[$view])) {
+ unset($CONFIG->allowed_ajax_views[$view]);
+ }
+}
/**
- * Return the location of a given view.
+ * Returns the file location for a view.
*
- * @param string $view The view.
+ * @warning This doesn't check if the file exists, but only
+ * constructs (or extracts) the path and returns it.
+ *
+ * @param string $view The view.
* @param string $viewtype The viewtype
+ *
+ * @return string
*/
function elgg_get_view_location($view, $viewtype = '') {
global $CONFIG;
@@ -121,130 +258,246 @@ function elgg_get_view_location($view, $viewtype = '') {
} else {
return $CONFIG->views->locations[$viewtype][$view];
}
+}
- return false;
+/**
+ * Set an alternative base location for a view.
+ *
+ * Views are expected to be in plugin_name/views/. This function can
+ * be used to change that location.
+ *
+ * @internal Core view locations are stored in $CONFIG->viewpath.
+ *
+ * @tip This is useful to optionally register views in a plugin.
+ *
+ * @param string $view The name of the view
+ * @param string $location The base location path
+ * @param string $viewtype The view type
+ *
+ * @return void
+ */
+function elgg_set_view_location($view, $location, $viewtype = '') {
+ global $CONFIG;
+
+ if (empty($viewtype)) {
+ $viewtype = 'default';
+ }
+
+ if (!isset($CONFIG->views)) {
+ $CONFIG->views = new stdClass;
+ }
+
+ if (!isset($CONFIG->views->locations)) {
+ $CONFIG->views->locations = array($viewtype => array($view => $location));
+
+ } else if (!isset($CONFIG->views->locations[$viewtype])) {
+ $CONFIG->views->locations[$viewtype] = array($view => $location);
+
+ } else {
+ $CONFIG->views->locations[$viewtype][$view] = $location;
+ }
}
/**
- * Handles templating views
+ * Returns whether the specified view exists
*
- * @see set_template_handler
+ * @note If $recurse is true, also checks if a view exists only as an extension.
+ *
+ * @param string $view The view name
+ * @param string $viewtype If set, forces the viewtype
+ * @param bool $recurse If false, do not check extensions
*
- * @param string $view The name and location of the view to use
- * @param array $vars Any variables that the view requires, passed as an array
- * @param boolean $bypass If set to true, elgg_view will bypass any specified alternative template handler; by default, it will hand off to this if requested (see set_template_handler)
- * @param boolean $debug If set to true, the viewer will complain if it can't find a view
- * @param string $viewtype If set, forces the viewtype for the elgg_view call to be this value (default: standard detection)
- * @return string The HTML content
+ * @return bool
*/
-function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $viewtype = '') {
+function elgg_view_exists($view, $viewtype = '', $recurse = true) {
global $CONFIG;
- static $usercache;
- $view = (string)$view;
+ // Detect view type
+ if (empty($viewtype)) {
+ $viewtype = elgg_get_viewtype();
+ }
- // basic checking for bad paths
- if (strpos($view, '..') !== false) {
- return false;
+ if (!isset($CONFIG->views->locations[$viewtype][$view])) {
+ if (!isset($CONFIG->viewpath)) {
+ $location = dirname(dirname(dirname(__FILE__))) . "/views/";
+ } else {
+ $location = $CONFIG->viewpath;
+ }
+ } else {
+ $location = $CONFIG->views->locations[$viewtype][$view];
}
- $view_orig = $view;
+ if (file_exists("{$location}{$viewtype}/{$view}.php")) {
+ return true;
+ }
- // Trigger the pagesetup event
- if (!isset($CONFIG->pagesetupdone)) {
- trigger_elgg_event('pagesetup','system');
- $CONFIG->pagesetupdone = true;
+ // If we got here then check whether this exists as an extension
+ // We optionally recursively check whether the extended view exists also for the viewtype
+ if ($recurse && isset($CONFIG->views->extensions[$view])) {
+ foreach ($CONFIG->views->extensions[$view] as $view_extension) {
+ // do not recursively check to stay away from infinite loops
+ if (elgg_view_exists($view_extension, $viewtype, false)) {
+ return true;
+ }
+ }
}
- if (!is_array($usercache)) {
- $usercache = array();
+ // Now check if the default view exists if the view is registered as a fallback
+ if ($viewtype != 'default' && elgg_does_viewtype_fallback($viewtype)) {
+ return elgg_view_exists($view, 'default');
}
- if (!is_array($vars)) {
- elgg_log('Vars in views must be an array!', 'ERROR');
- $vars = array();
+ return false;
+}
+
+/**
+ * Return a parsed view.
+ *
+ * Views are rendered by a template handler and returned as strings.
+ *
+ * Views are called with a special $vars variable set,
+ * which includes any variables passed as the second parameter.
+ * For backward compatbility, the following variables are also set but we
+ * recommend that you do not use them:
+ * - $vars['config'] The $CONFIG global. (Use {@link elgg_get_config()} instead).
+ * - $vars['url'] The site URL. (use {@link elgg_get_site_url()} instead).
+ * - $vars['user'] The logged in user. (use {@link elgg_get_logged_in_user_entity()} instead).
+ *
+ * Custom template handlers can be set with {@link set_template_handler()}.
+ *
+ * The output of views can be intercepted by registering for the
+ * view, $view_name plugin hook.
+ *
+ * @warning Any variables in $_SESSION will override passed vars
+ * upon name collision. See https://github.com/Elgg/Elgg/issues/2124
+ *
+ * @param string $view The name and location of the view to use
+ * @param array $vars Variables to pass to the view.
+ * @param boolean $bypass If set to true, elgg_view will bypass any specified
+ * alternative template handler; by default, it will
+ * hand off to this if requested (see set_template_handler)
+ * @param boolean $ignored This argument is ignored and will be removed eventually
+ * @param string $viewtype If set, forces the viewtype for the elgg_view call to be
+ * this value (default: standard detection)
+ *
+ * @return string The parsed view
+ * @see set_template_handler()
+ * @example views/elgg_view.php
+ * @link http://docs.elgg.org/View
+ */
+function elgg_view($view, $vars = array(), $bypass = false, $ignored = false, $viewtype = '') {
+ global $CONFIG;
+
+ if (!is_string($view) || !is_string($viewtype)) {
+ elgg_log("View and Viewtype in views must be a strings: $view", 'NOTICE');
+ return '';
+ }
+ // basic checking for bad paths
+ if (strpos($view, '..') !== false) {
+ return '';
}
- if (empty($vars)) {
+ if (!is_array($vars)) {
+ elgg_log("Vars in views must be an array: $view", 'ERROR');
$vars = array();
}
- // Load session and configuration variables into $vars
- // $_SESSION will always be an array if it is set
- if (isset($_SESSION) /*&& is_array($_SESSION)*/ ) {
- //= array_merge($vars, $_SESSION);
- $vars += $_SESSION;
+ // Get the current viewtype
+ if ($viewtype === '') {
+ $viewtype = elgg_get_viewtype();
+ } elseif (preg_match('/\W/', $viewtype)) {
+ // Viewtypes can only be alphanumeric
+ return '';
}
- $vars['config'] = array();
+ $view_orig = $view;
- if (!empty($CONFIG)) {
- $vars['config'] = $CONFIG;
+ // Trigger the pagesetup event
+ if (!isset($CONFIG->pagesetupdone) && $CONFIG->boot_complete) {
+ $CONFIG->pagesetupdone = true;
+ elgg_trigger_event('pagesetup', 'system');
}
- $vars['url'] = $CONFIG->url;
+ // @warning - plugin authors: do not expect user, config, and url to be
+ // set by elgg_view() in the future. Instead, use elgg_get_logged_in_user_entity(),
+ // elgg_get_config(), and elgg_get_site_url() in your views.
+ if (!isset($vars['user'])) {
+ $vars['user'] = elgg_get_logged_in_user_entity();
+ }
+ if (!isset($vars['config'])) {
+ $vars['config'] = $CONFIG;
+ }
+ if (!isset($vars['url'])) {
+ $vars['url'] = elgg_get_site_url();
+ }
- // Load page owner variables into $vars
- if (is_callable('page_owner')) {
- $vars['page_owner'] = page_owner();
- } else {
- $vars['page_owner'] = -1;
+ // full_view is the new preferred key for full view on entities @see elgg_view_entity()
+ // check if full_view is set because that means we've already rewritten it and this is
+ // coming from another view passing $vars directly.
+ if (isset($vars['full']) && !isset($vars['full_view'])) {
+ elgg_deprecated_notice("Use \$vars['full_view'] instead of \$vars['full']", 1.8, 2);
+ $vars['full_view'] = $vars['full'];
+ }
+ if (isset($vars['full_view'])) {
+ $vars['full'] = $vars['full_view'];
}
- if (($vars['page_owner'] != -1) && (is_installed())) {
- if (!isset($usercache[$vars['page_owner']])) {
- $vars['page_owner_user'] = get_entity($vars['page_owner']);
- $usercache[$vars['page_owner']] = $vars['page_owner_user'];
- } else {
- $vars['page_owner_user'] = $usercache[$vars['page_owner']];
+ // internalname => name (1.8)
+ if (isset($vars['internalname']) && !isset($vars['__ignoreInternalname']) && !isset($vars['name'])) {
+ elgg_deprecated_notice('You should pass $vars[\'name\'] now instead of $vars[\'internalname\']', 1.8, 2);
+ $vars['name'] = $vars['internalname'];
+ } elseif (isset($vars['name'])) {
+ if (!isset($vars['internalname'])) {
+ $vars['__ignoreInternalname'] = '';
}
+ $vars['internalname'] = $vars['name'];
}
- if (!isset($vars['js'])) {
- $vars['js'] = "";
+ // internalid => id (1.8)
+ if (isset($vars['internalid']) && !isset($vars['__ignoreInternalid']) && !isset($vars['name'])) {
+ elgg_deprecated_notice('You should pass $vars[\'id\'] now instead of $vars[\'internalid\']', 1.8, 2);
+ $vars['id'] = $vars['internalid'];
+ } elseif (isset($vars['id'])) {
+ if (!isset($vars['internalid'])) {
+ $vars['__ignoreInternalid'] = '';
+ }
+ $vars['internalid'] = $vars['id'];
}
// If it's been requested, pass off to a template handler instead
if ($bypass == false && isset($CONFIG->template_handler) && !empty($CONFIG->template_handler)) {
$template_handler = $CONFIG->template_handler;
if (is_callable($template_handler)) {
- return $template_handler($view, $vars);
+ return call_user_func($template_handler, $view, $vars);
}
}
- // Get the current viewtype
- if (empty($viewtype)) {
- $viewtype = elgg_get_viewtype();
- }
-
- // Viewtypes can only be alphanumeric
- if (preg_match('[\W]', $viewtype)) {
- return '';
- }
-
// Set up any extensions to the requested view
if (isset($CONFIG->views->extensions[$view])) {
$viewlist = $CONFIG->views->extensions[$view];
} else {
$viewlist = array(500 => $view);
}
+
// Start the output buffer, find the requested view file, and execute it
ob_start();
- foreach($viewlist as $priority => $view) {
+ foreach ($viewlist as $priority => $view) {
+
$view_location = elgg_get_view_location($view, $viewtype);
$view_file = "$view_location$viewtype/$view.php";
-
- $default_location = elgg_get_view_location($view, 'default');
- $default_view_file = "{$default_location}default/$view.php";
-
+
// try to include view
if (!file_exists($view_file) || !include($view_file)) {
// requested view does not exist
$error = "$viewtype/$view view does not exist.";
// attempt to load default view
- if ($viewtype != 'default' && elgg_does_viewtype_fallback($viewtype)) {
+ if ($viewtype !== 'default' && elgg_does_viewtype_fallback($viewtype)) {
+
+ $default_location = elgg_get_view_location($view, 'default');
+ $default_view_file = "{$default_location}default/$view.php";
+
if (file_exists($default_view_file) && include($default_view_file)) {
// default view found
$error .= " Using default/$view instead.";
@@ -263,337 +516,350 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie
$content = ob_get_clean();
// Plugin hook
- $content = trigger_plugin_hook('view', $view_orig,
- array('view' => $view_orig, 'vars' => $vars), $content);
+ $params = array('view' => $view_orig, 'vars' => $vars, 'viewtype' => $viewtype);
+ $content = elgg_trigger_plugin_hook('view', $view_orig, $params, $content);
- // backward compatibility with less grandular hook will be gone in 2.0
- $content_tmp = trigger_plugin_hook('display', 'view', array('view' => $view_orig, 'vars' => $vars), $content);
+ // backward compatibility with less granular hook will be gone in 2.0
+ $content_tmp = elgg_trigger_plugin_hook('display', 'view', $params, $content);
- if ($content_tmp != $content) {
+ if ($content_tmp !== $content) {
$content = $content_tmp;
- elgg_deprecated_notice('The display:view plugin hook is deprecated by view:view_name or view:all', 1.8);
+ elgg_deprecated_notice('The display:view plugin hook is deprecated by view:view_name', 1.8);
}
- // Return $content
return $content;
}
/**
- * Returns whether the specified view exists
+ * Extends a view with another view.
*
- * @param string $view The view name
- * @param string $viewtype If set, forces the viewtype
- * @param bool $recurse If false, do not recursively check extensions
- * @return true|false Depending on success
+ * The output of any view can be prepended or appended to any other view.
+ *
+ * The default action is to append a view. If the priority is less than 500,
+ * the output of the extended view will be appended to the original view.
+ *
+ * Priority can be specified and affects the order in which extensions
+ * are appended or prepended.
+ *
+ * @internal View extensions are stored in
+ * $CONFIG->views->extensions[$view][$priority] = $view_extension
+ *
+ * @param string $view The view to extend.
+ * @param string $view_extension This view is added to $view
+ * @param int $priority The priority, from 0 to 1000,
+ * to add at (lowest numbers displayed first)
+ *
+ * @return void
+ * @since 1.7.0
+ * @link http://docs.elgg.org/Views/Extend
+ * @example views/extend.php
*/
-function elgg_view_exists($view, $viewtype = '', $recurse = true) {
+function elgg_extend_view($view, $view_extension, $priority = 501) {
global $CONFIG;
- // Detect view type
- if (empty($viewtype)) {
- $viewtype = elgg_get_viewtype();
- }
-
- if (!isset($CONFIG->views->locations[$viewtype][$view])) {
- if (!isset($CONFIG->viewpath)) {
- $location = dirname(dirname(dirname(__FILE__))) . "/views/";
- } else {
- $location = $CONFIG->viewpath;
- }
+ if (!isset($CONFIG->views)) {
+ $CONFIG->views = (object) array(
+ 'extensions' => array(),
+ );
+ $CONFIG->views->extensions[$view][500] = (string)$view;
} else {
- $location = $CONFIG->views->locations[$viewtype][$view];
- }
-
- if (file_exists($location . "{$viewtype}/{$view}.php")) {
- return true;
+ if (!isset($CONFIG->views->extensions[$view])) {
+ $CONFIG->views->extensions[$view][500] = (string)$view;
+ }
}
- // If we got here then check whether this exists as an extension
- // We optionally recursively check whether the extended view exists also for the viewtype
- if ($recurse && isset($CONFIG->views->extensions[$view])) {
- foreach( $CONFIG->views->extensions[$view] as $view_extension ) {
- // do not recursively check to stay away from infinite loops
- if (elgg_view_exists($view_extension, $viewtype, false)) {
- return true;
- }
- }
+ // raise priority until it doesn't match one already registered
+ while (isset($CONFIG->views->extensions[$view][$priority])) {
+ $priority++;
}
- return false;
+ $CONFIG->views->extensions[$view][$priority] = (string)$view_extension;
+ ksort($CONFIG->views->extensions[$view]);
}
/**
- * Registers a view to be simply cached
- *
- * Views cached in this manner must take no parameters and be login agnostic -
- * that is to say, they look the same no matter who is logged in (or logged out).
+ * Unextends a view.
*
- * CSS and the basic jS views are automatically cached like this.
+ * @param string $view The view that was extended.
+ * @param string $view_extension This view that was added to $view
*
- * @param string $viewname View name
+ * @return bool
+ * @since 1.7.2
*/
-function elgg_view_register_simplecache($viewname) {
+function elgg_unextend_view($view, $view_extension) {
global $CONFIG;
- if (!isset($CONFIG->views)) {
- $CONFIG->views = new stdClass;
+ if (!isset($CONFIG->views->extensions[$view])) {
+ return FALSE;
}
- if (!isset($CONFIG->views->simplecache)) {
- $CONFIG->views->simplecache = array();
+ $priority = array_search($view_extension, $CONFIG->views->extensions[$view]);
+ if ($priority === FALSE) {
+ return FALSE;
}
- //if (elgg_view_exists($viewname))
- $CONFIG->views->simplecache[] = $viewname;
+ unset($CONFIG->views->extensions[$view][$priority]);
+
+ return TRUE;
}
/**
- * Regenerates the simple cache.
+ * Assembles and outputs a full page.
+ *
+ * A "page" in Elgg is determined by the current view type and
+ * can be HTML for a browser, RSS for a feed reader, or
+ * Javascript, PHP and a number of other formats.
*
- * @param string $viewtype Optional viewtype to regenerate
- * @see elgg_view_register_simplecache
+ * @param string $title Title
+ * @param string $body Body
+ * @param string $page_shell Optional page shell to use. See page/shells view directory
+ * @param array $vars Optional vars array to pass to the page
+ * shell. Automatically adds title, body, and sysmessages
*
+ * @return string The contents of the page
+ * @since 1.8
*/
-function elgg_view_regenerate_simplecache($viewtype = NULL) {
- global $CONFIG;
-
- if (!isset($CONFIG->views->simplecache) || !is_array($CONFIG->views->simplecache)) {
- return;
- }
-
- $lastcached = time();
-
- // @todo elgg_view() checks if the page set is done (isset($CONFIG->pagesetupdone)) and
- // triggers an event if it's not. Calling elgg_view() here breaks submenus
- // (at least) because the page setup hook is called before any
- // contexts can be correctly set (since this is called before page_handler()).
- // To avoid this, lie about $CONFIG->pagehandlerdone to force
- // the trigger correctly when the first view is actually being output.
- $CONFIG->pagesetupdone = TRUE;
-
- if (!file_exists($CONFIG->dataroot . 'views_simplecache')) {
- mkdir($CONFIG->dataroot . 'views_simplecache');
+function elgg_view_page($title, $body, $page_shell = 'default', $vars = array()) {
+
+ $messages = null;
+ if (count_messages()) {
+ // get messages - try for errors first
+ $messages = system_messages(NULL, "error");
+ if (count($messages["error"]) == 0) {
+ // no errors so grab rest of messages
+ $messages = system_messages(null, "");
+ } else {
+ // we have errors - clear out remaining messages
+ system_messages(null, "");
+ }
}
- if (isset($viewtype)) {
- $viewtypes = array($viewtype);
- } else {
- $viewtypes = $CONFIG->view_types;
- }
+ $vars['title'] = $title;
+ $vars['body'] = $body;
+ $vars['sysmessages'] = $messages;
- $original_viewtype = elgg_get_viewtype();
+ $vars = elgg_trigger_plugin_hook('output:before', 'page', null, $vars);
- foreach ($viewtypes as $viewtype) {
- elgg_set_viewtype($viewtype);
- foreach ($CONFIG->views->simplecache as $view) {
- $viewcontents = elgg_view($view);
- $viewname = md5(elgg_get_viewtype() . $view);
- if ($handle = fopen($CONFIG->dataroot . 'views_simplecache/' . $viewname, 'w')) {
- fwrite($handle, $viewcontents);
- fclose($handle);
- }
- }
-
- datalist_set("simplecache_lastupdate_$viewtype", $lastcached);
- datalist_set("simplecache_lastcached_$viewtype", $lastcached);
+ // check for deprecated view
+ if ($page_shell == 'default' && elgg_view_exists('pageshells/pageshell')) {
+ elgg_deprecated_notice("pageshells/pageshell is deprecated by page/$page_shell", 1.8);
+ $output = elgg_view('pageshells/pageshell', $vars);
+ } else {
+ $output = elgg_view("page/$page_shell", $vars);
}
- elgg_set_viewtype($original_viewtype);
-
- // needs to be set for links in html head
- $CONFIG->lastcache = $lastcached;
+ $vars['page_shell'] = $page_shell;
- unset($CONFIG->pagesetupdone);
+ // Allow plugins to mod output
+ return elgg_trigger_plugin_hook('output', 'page', $vars, $output);
}
/**
- * Enables the simple cache.
+ * Displays a layout with optional parameters.
*
- * @see elgg_view_register_simplecache
+ * Layouts provide consistent organization of pages and other blocks of content.
+ * There are a few default layouts in core:
+ * - admin A special layout for the admin area.
+ * - one_column A single content column.
+ * - one_sidebar A content column with sidebar.
+ * - two_sidebar A content column with two sidebars.
+ * - widgets A widget canvas.
*
- */
-
-function elgg_view_enable_simplecache() {
- global $CONFIG;
-
- datalist_set('simplecache_enabled',1);
- $CONFIG->simplecache_enabled = 1;
- elgg_view_regenerate_simplecache();
-}
-
-/**
- * Disables the simple cache.
+ * The layout views take the form page/layouts/$layout_name
+ * See the individual layouts for what options are supported. The three most
+ * common layouts have these parameters:
+ * one_column
+ * content => string
+ * one_sidebar
+ * content => string
+ * sidebar => string (optional)
+ * content
+ * content => string
+ * sidebar => string (optional)
+ * buttons => string (override the default add button)
+ * title => string (override the default title)
+ * filter_context => string (selected content filter)
+ * See the content layout view for more parameters
*
- * @see elgg_view_register_simplecache
+ * @param string $layout_name The name of the view in page/layouts/.
+ * @param array $vars Associative array of parameters for the layout view
*
+ * @return string The layout
*/
-function elgg_view_disable_simplecache() {
- global $CONFIG;
- if ($CONFIG->simplecache_enabled) {
- datalist_set('simplecache_enabled',0);
- $CONFIG->simplecache_enabled = 0;
-
- // purge simple cache
- if ($handle = opendir($CONFIG->dataroot.'views_simplecache')) {
- while (false !== ($file = readdir($handle))) {
- if ($file != "." && $file != "..") {
- unlink($CONFIG->dataroot.'views_simplecache/'.$file);
- }
- }
- closedir($handle);
+function elgg_view_layout($layout_name, $vars = array()) {
+
+ if (is_string($vars) || $vars === null) {
+ elgg_deprecated_notice("The use of unlimited optional string arguments in elgg_view_layout() was deprecated in favor of an options array", 1.8);
+ $arg = 1;
+ $param_array = array();
+ while ($arg < func_num_args()) {
+ $param_array['area' . $arg] = func_get_arg($arg);
+ $arg++;
}
+ } else {
+ $param_array = $vars;
}
-}
+ $params = elgg_trigger_plugin_hook('output:before', 'layout', null, $param_array);
-/**
- * Internal function for retrieving views used by elgg_view_tree
- *
- * @param unknown_type $dir
- * @param unknown_type $base
- * @return unknown
- */
-function elgg_get_views($dir, $base) {
- $return = array();
- if (file_exists($dir) && is_dir($dir)) {
- if ($handle = opendir($dir)) {
- while ($view = readdir($handle)) {
- if (!in_array($view, array('.','..','.svn','CVS'))) {
- if (is_dir($dir . '/' . $view)) {
- if ($val = elgg_get_views($dir . '/' . $view, $base . '/' . $view)) {
- $return = array_merge($return, $val);
- }
- } else {
- $view = str_replace('.php','',$view);
- $return[] = $base . '/' . $view;
- }
- }
- }
- }
+ // check deprecated location
+ if (elgg_view_exists("canvas/layouts/$layout_name")) {
+ elgg_deprecated_notice("canvas/layouts/$layout_name is deprecated by page/layouts/$layout_name", 1.8);
+ $output = elgg_view("canvas/layouts/$layout_name", $params);
+ } elseif (elgg_view_exists("page/layouts/$layout_name")) {
+ $output = elgg_view("page/layouts/$layout_name", $params);
+ } else {
+ $output = elgg_view("page/layouts/default", $params);
}
- return $return;
-}
-/**
- * @deprecated 1.7. Use elgg_get_views().
- * @param $dir
- * @param $base
- */
-function get_views($dir, $base) {
- elgg_deprecated_notice('get_views() was deprecated by elgg_get_views()!', 1.7);
- elgg_get_views($dir, $base);
+ return elgg_trigger_plugin_hook('output:after', 'layout', $params, $output);
}
/**
- * When given a partial view root (eg 'js' or 'page_elements'), returns an array of views underneath it
+ * Render a menu
*
- * @param string $view_root The root view
- * @param string $viewtype Optionally specify a view type other than the current one.
- * @return array A list of view names underneath that root view
+ * @see elgg_register_menu_item() for documentation on adding menu items and
+ * navigation.php for information on the different menus available.
+ *
+ * This function triggers a 'register', 'menu:<menu name>' plugin hook that enables
+ * plugins to add menu items just before a menu is rendered. This is used by
+ * dynamic menus (menus that change based on some input such as the user hover
+ * menu). Using elgg_register_menu_item() in response to the hook can cause
+ * incorrect links to show up. See the blog plugin's blog_owner_block_menu()
+ * for an example of using this plugin hook.
+ *
+ * An additional hook is the 'prepare', 'menu:<menu name>' which enables plugins
+ * to modify the structure of the menu (sort it, remove items, set variables on
+ * the menu items).
+ *
+ * elgg_view_menu() uses views in navigation/menu
+ *
+ * @param string $menu_name The name of the menu
+ * @param array $vars An associative array of display options for the menu.
+ * Options include:
+ * sort_by => string or php callback
+ * string options: 'name', 'priority', 'title' (default),
+ * 'register' (registration order) or a
+ * php callback (a compare function for usort)
+ * handler: string the page handler to build action URLs
+ * entity: ElggEntity to use to build action URLs
+ * class: string the class for the entire menu.
+ * show_section_headers: bool show headers before menu sections.
+ *
+ * @return string
+ * @since 1.8.0
*/
-function elgg_view_tree($view_root, $viewtype = "") {
+function elgg_view_menu($menu_name, array $vars = array()) {
global $CONFIG;
- static $treecache;
- // Get viewtype
- if (!$viewtype) {
- $viewtype = elgg_get_viewtype();
- }
+ $vars['name'] = $menu_name;
- // Has the treecache been initialised?
- if (!isset($treecache)) {
- $treecache = array();
- }
- // A little light internal caching
- if (!empty($treecache[$view_root])) {
- return $treecache[$view_root];
- }
+ $sort_by = elgg_extract('sort_by', $vars, 'text');
- // Examine $CONFIG->views->locations
- if (isset($CONFIG->views->locations[$viewtype])) {
- foreach($CONFIG->views->locations[$viewtype] as $view => $path) {
- $pos = strpos($view,$view_root);
- if ($pos === 0) {
- $treecache[$view_root][] = $view;
- }
- }
+ if (isset($CONFIG->menus[$menu_name])) {
+ $menu = $CONFIG->menus[$menu_name];
+ } else {
+ $menu = array();
}
- // Now examine core
- $location = $CONFIG->viewpath;
- $viewtype = elgg_get_viewtype();
- $root = $location . $viewtype . '/' . $view_root;
+ // Give plugins a chance to add menu items just before creation.
+ // This supports dynamic menus (example: user_hover).
+ $menu = elgg_trigger_plugin_hook('register', "menu:$menu_name", $vars, $menu);
- if (file_exists($root) && is_dir($root)) {
- $val = elgg_get_views($root, $view_root);
- if (!is_array($treecache[$view_root])) {
- $treecache[$view_root] = array();
- }
- $treecache[$view_root] = array_merge($treecache[$view_root], $val);
- }
+ $builder = new ElggMenuBuilder($menu);
+ $vars['menu'] = $builder->getMenu($sort_by);
+ $vars['selected_item'] = $builder->getSelected();
- return $treecache[$view_root];
+ // Let plugins modify the menu
+ $vars['menu'] = elgg_trigger_plugin_hook('prepare', "menu:$menu_name", $vars, $vars['menu']);
+
+ if (elgg_view_exists("navigation/menu/$menu_name")) {
+ return elgg_view("navigation/menu/$menu_name", $vars);
+ } else {
+ return elgg_view("navigation/menu/default", $vars);
+ }
}
/**
- * When given an entity, views it intelligently.
+ * Returns a string of a rendered entity.
*
- * Expects a view to exist called entity-type/subtype, or for the entity to have a parameter
- * 'view' which lists a different view to display. In both cases, elgg_view will be called with
- * array('entity' => $entity, 'full' => $full) as its parameters, and therefore this is what
- * the view should expect to receive.
+ * Entity views are either determined by setting the view property on the entity
+ * or by having a view named after the entity $type/$subtype. Entities that have
+ * neither a view property nor a defined $type/$subtype view will fall back to
+ * using the $type/default view.
+ *
+ * The entity view is called with the following in $vars:
+ * - ElggEntity 'entity' The entity being viewed
+ *
+ * Other common view $vars paramters:
+ * - bool 'full_view' Whether to show a full or condensed view.
+ *
+ * @tip This function can automatically appends annotations to entities if in full
+ * view and a handler is registered for the entity:annotate. See https://github.com/Elgg/Elgg/issues/964 and
+ * {@link elgg_view_entity_annotations()}.
*
* @param ElggEntity $entity The entity to display
- * @param boolean $full Determines whether or not to display the full version of an object, or a smaller version for use in aggregators etc
- * @param boolean $bypass If set to true, elgg_view will bypass any specified alternative template handler; by default, it will hand off to this if requested (see set_template_handler)
- * @param boolean $debug If set to true, the viewer will complain if it can't find a view
+ * @param array $vars Array of variables to pass to the entity view.
+ * In Elgg 1.7 and earlier it was the boolean $full_view
+ * @param boolean $bypass If false, will not pass to a custom template handler.
+ * {@see set_template_handler()}
+ * @param boolean $debug Complain if views are missing
+ *
* @return string HTML to display or false
+ * @link http://docs.elgg.org/Views/Entity
+ * @link http://docs.elgg.org/Entities
+ * @todo The annotation hook might be better as a generic plugin hook to append content.
*/
-function elgg_view_entity(ElggEntity $entity, $full = false, $bypass = true, $debug = false) {
- global $autofeed;
- $autofeed = true;
+function elgg_view_entity(ElggEntity $entity, $vars = array(), $bypass = true, $debug = false) {
// No point continuing if entity is null
- if (!$entity) {
- return '';
+ if (!$entity || !($entity instanceof ElggEntity)) {
+ return false;
}
- if (!($entity instanceof ElggEntity)) {
- return false;
+ global $autofeed;
+ $autofeed = true;
+
+ $defaults = array(
+ 'full_view' => false,
+ );
+
+ if (is_array($vars)) {
+ $vars = array_merge($defaults, $vars);
+ } else {
+ elgg_deprecated_notice("Update your use of elgg_view_entity()", 1.8);
+ $vars = array(
+ 'full_view' => $vars,
+ );
}
+ $vars['entity'] = $entity;
+
+
// if this entity has a view defined, use it
$view = $entity->view;
if (is_string($view)) {
- return elgg_view($view,
- array('entity' => $entity, 'full' => $full),
- $bypass,
- $debug);
+ return elgg_view($view, $vars, $bypass, $debug);
}
$entity_type = $entity->getType();
$subtype = $entity->getSubtype();
if (empty($subtype)) {
- $subtype = $entity_type;
+ $subtype = 'default';
}
$contents = '';
- if (elgg_view_exists("{$entity_type}/{$subtype}")) {
- $contents = elgg_view("{$entity_type}/{$subtype}", array(
- 'entity' => $entity,
- 'full' => $full
- ), $bypass, $debug);
+ if (elgg_view_exists("$entity_type/$subtype")) {
+ $contents = elgg_view("$entity_type/$subtype", $vars, $bypass, $debug);
}
if (empty($contents)) {
- $contents = elgg_view("{$entity_type}/default",array(
- 'entity' => $entity,
- 'full' => $full
- ), $bypass, $debug);
+ $contents = elgg_view("$entity_type/default", $vars, $bypass, $debug);
}
+
// Marcus Povey 20090616 : Speculative and low impact approach for fixing #964
- if ($full) {
- $annotations = elgg_view_entity_annotations($entity, $full);
+ if ($vars['full_view']) {
+ $annotations = elgg_view_entity_annotations($entity, $vars['full_view']);
if ($annotations) {
$contents .= $annotations;
@@ -603,163 +869,242 @@ function elgg_view_entity(ElggEntity $entity, $full = false, $bypass = true, $de
}
/**
- * When given an annotation, views it intelligently.
+ * View the icon of an entity
+ *
+ * Entity views are determined by having a view named after the entity $type/$subtype.
+ * Entities that do not have a defined icon/$type/$subtype view will fall back to using
+ * the icon/$type/default view.
*
- * This function expects annotation views to be of the form annotation/name, where name
- * is the type of annotation.
+ * @param ElggEntity $entity The entity to display
+ * @param string $size The size: tiny, small, medium, large
+ * @param array $vars An array of variables to pass to the view. Some possible
+ * variables are img_class and link_class. See the
+ * specific icon view for more parameters.
+ *
+ * @return string HTML to display or false
+ */
+function elgg_view_entity_icon(ElggEntity $entity, $size = 'medium', $vars = array()) {
+
+ // No point continuing if entity is null
+ if (!$entity || !($entity instanceof ElggEntity)) {
+ return false;
+ }
+
+ $vars['entity'] = $entity;
+ $vars['size'] = $size;
+
+ $entity_type = $entity->getType();
+
+ $subtype = $entity->getSubtype();
+ if (empty($subtype)) {
+ $subtype = 'default';
+ }
+
+ $contents = '';
+ if (elgg_view_exists("icon/$entity_type/$subtype")) {
+ $contents = elgg_view("icon/$entity_type/$subtype", $vars);
+ }
+ if (empty($contents)) {
+ $contents = elgg_view("icon/$entity_type/default", $vars);
+ }
+ if (empty($contents)) {
+ $contents = elgg_view("icon/default", $vars);
+ }
+
+ return $contents;
+}
+
+/**
+ * Returns a string of a rendered annotation.
+ *
+ * Annotation views are expected to be in annotation/$annotation_name.
+ * If a view is not found for $annotation_name, the default annotation/default
+ * will be used.
+ *
+ * @warning annotation/default is not currently defined in core.
+ *
+ * The annotation view is called with the following in $vars:
+ * - ElggEntity 'annotation' The annotation being viewed.
*
* @param ElggAnnotation $annotation The annotation to display
- * @param boolean $full Determines whether or not to display the full version of an object, or a smaller version for use in aggregators etc
- * @param boolean $bypass If set to true, elgg_view will bypass any specified alternative template handler; by default, it will hand off to this if requested (see set_template_handler)
- * @param boolean $debug If set to true, the viewer will complain if it can't find a view
- * @return string HTML (etc) to display
+ * @param array $vars Variable array for view.
+ * @param bool $bypass If false, will not pass to a custom
+ * template handler. {@see set_template_handler()}
+ * @param bool $debug Complain if views are missing
+ *
+ * @return string/false Rendered annotation
*/
-function elgg_view_annotation(ElggAnnotation $annotation, $bypass = true, $debug = false) {
+function elgg_view_annotation(ElggAnnotation $annotation, array $vars = array(), $bypass = true, $debug = false) {
global $autofeed;
$autofeed = true;
+ $defaults = array(
+ 'full_view' => true,
+ );
+
+ $vars = array_merge($defaults, $vars);
+ $vars['annotation'] = $annotation;
+
+ // @todo setting the view on an annotation is not advertised anywhere
+ // do we want to keep this?
$view = $annotation->view;
if (is_string($view)) {
- return elgg_view($view,array('annotation' => $annotation), $bypass, $debug);
+ return elgg_view($view, $vars, $bypass, $debug);
}
$name = $annotation->name;
- $intname = (int) $name;
- if ("{$intname}" == "{$name}") {
- $name = get_metastring($intname);
- }
if (empty($name)) {
- return "";
+ return false;
}
- if (elgg_view_exists("annotation/{$name}")) {
- return elgg_view("annotation/{$name}",array('annotation' => $annotation), $bypass, $debug);
+ if (elgg_view_exists("annotation/$name")) {
+ return elgg_view("annotation/$name", $vars, $bypass, $debug);
} else {
- return elgg_view("annotation/default",array('annotation' => $annotation), $bypass, $debug);
+ return elgg_view("annotation/default", $vars, $bypass, $debug);
}
}
-
/**
- * Returns a view of a list of entities, plus navigation. It is intended that this function
- * be called from other wrapper functions.
- *
- * @see list_entities
- * @see list_user_objects
- * @see list_user_friends_objects
- * @see list_entities_from_metadata
- * @see list_entities_from_metadata_multi
- * @see list_entities_from_relationships
- * @see list_site_members
- *
- * @param array $entities List of entities
- * @param int $count The total number of entities across all pages
- * @param int $offset The current indexing offset
- * @param int $limit The number of entities to display per page
- * @param true|false $fullview Whether or not to display the full view (default: true)
- * @param true|false $viewtypetoggle Whether or not to allow users to toggle to gallery view
- * @param bool $pagination Whether pagination is offered.
- * @return string The list of entities
+ * Returns a rendered list of entities with pagination. This function should be
+ * called by wrapper functions.
+ *
+ * @see elgg_list_entities()
+ * @see list_user_friends_objects()
+ * @see elgg_list_entities_from_metadata()
+ * @see elgg_list_entities_from_relationships()
+ * @see elgg_list_entities_from_annotations()
+ *
+ * @param array $entities Array of entities
+ * @param array $vars Display variables
+ * 'count' The total number of entities across all pages
+ * 'offset' The current indexing offset
+ * 'limit' The number of entities to display per page
+ * 'full_view' Display the full view of the entities?
+ * 'list_class' CSS class applied to the list
+ * 'item_class' CSS class applied to the list items
+ * 'pagination' Display pagination?
+ * 'list_type' List type: 'list' (default), 'gallery'
+ * 'list_type_toggle' Display the list type toggle?
+ *
+ * @return string The rendered list of entities
+ * @access private
*/
-function elgg_view_entity_list($entities, $count, $offset, $limit, $fullview = true, $viewtypetoggle = true, $pagination = true) {
- $count = (int) $count;
- $limit = (int) $limit;
-
- // do not require views to explicitly pass in the offset
- if (!$offset = (int) $offset) {
- $offset = sanitise_int(get_input('offset', 0));
- }
-
- $context = get_context();
-
- $html = elgg_view('entities/entity_list',array(
- 'entities' => $entities,
- 'count' => $count,
- 'offset' => $offset,
- 'limit' => $limit,
- 'baseurl' => $_SERVER['REQUEST_URI'],
- 'fullview' => $fullview,
- 'context' => $context,
- 'viewtypetoggle' => $viewtypetoggle,
- 'viewtype' => get_input('search_viewtype','list'),
- 'pagination' => $pagination
- ));
-
- return $html;
+function elgg_view_entity_list($entities, $vars = array(), $offset = 0, $limit = 10, $full_view = true,
+$list_type_toggle = true, $pagination = true) {
+
+ if (!$vars["limit"] && !$vars["offset"]) {
+ // no need for pagination if listing is unlimited
+ $vars["pagination"] = false;
+ }
+
+ if (!is_int($offset)) {
+ $offset = (int)get_input('offset', 0);
+ }
+
+ // list type can be passed as request parameter
+ $list_type = get_input('list_type', 'list');
+ if (get_input('listtype')) {
+ elgg_deprecated_notice("'listtype' has been deprecated by 'list_type' for lists", 1.8);
+ $list_type = get_input('listtype');
+ }
+
+ if (is_array($vars)) {
+ // new function
+ $defaults = array(
+ 'items' => $entities,
+ 'list_class' => 'elgg-list-entity',
+ 'full_view' => true,
+ 'pagination' => true,
+ 'list_type' => $list_type,
+ 'list_type_toggle' => false,
+ 'offset' => $offset,
+ );
+
+ $vars = array_merge($defaults, $vars);
+
+ } else {
+ // old function parameters
+ elgg_deprecated_notice("Please update your use of elgg_view_entity_list()", 1.8);
+
+ $vars = array(
+ 'items' => $entities,
+ 'count' => (int) $vars, // the old count parameter
+ 'offset' => $offset,
+ 'limit' => (int) $limit,
+ 'full_view' => $full_view,
+ 'pagination' => $pagination,
+ 'list_type' => $list_type,
+ 'list_type_toggle' => $list_type_toggle,
+ 'list_class' => 'elgg-list-entity',
+ );
+ }
+
+ if ($vars['list_type'] != 'list') {
+ return elgg_view('page/components/gallery', $vars);
+ } else {
+ return elgg_view('page/components/list', $vars);
+ }
}
/**
- * Returns a view of a list of annotations, plus navigation. It is intended that this function
- * be called from other wrapper functions.
+ * Returns a rendered list of annotations, plus pagination. This function
+ * should be called by wrapper functions.
+ *
+ * @param array $annotations Array of annotations
+ * @param array $vars Display variables
+ * 'count' The total number of annotations across all pages
+ * 'offset' The current indexing offset
+ * 'limit' The number of annotations to display per page
+ * 'full_view' Display the full view of the annotation?
+ * 'list_class' CSS Class applied to the list
+ * 'offset_key' The url parameter key used for offset
*
- * @param array $annotations List of annotations
- * @param int $count The total number of annotations across all pages
- * @param int $offset The current indexing offset
- * @param int $limit The number of annotations to display per page
* @return string The list of annotations
+ * @access private
*/
-function elgg_view_annotation_list($annotations, $count, $offset, $limit) {
- $count = (int) $count;
- $offset = (int) $offset;
- $limit = (int) $limit;
-
- $html = "";
-
- $nav = elgg_view('navigation/pagination',array(
- 'baseurl' => $_SERVER['REQUEST_URI'],
- 'offset' => $offset,
- 'count' => $count,
- 'limit' => $limit,
- 'word' => 'annoff',
- 'nonefound' => false,
- ));
-
- $html .= $nav;
-
- if (is_array($annotations) && sizeof($annotations) > 0) {
- foreach($annotations as $annotation) {
- $html .= elgg_view_annotation($annotation, "", false);
- }
- }
-
- if ($count) {
- $html .= $nav;
+function elgg_view_annotation_list($annotations, array $vars = array()) {
+ $defaults = array(
+ 'items' => $annotations,
+ 'list_class' => 'elgg-list-annotation elgg-annotation-list', // @todo remove elgg-annotation-list in Elgg 1.9
+ 'full_view' => true,
+ 'offset_key' => 'annoff',
+ );
+
+ $vars = array_merge($defaults, $vars);
+
+ if (!$vars["limit"] && !$vars["offset"]) {
+ // no need for pagination if listing is unlimited
+ $vars["pagination"] = false;
}
- return $html;
+ return elgg_view('page/components/list', $vars);
}
/**
- * Display a selective rendered list of annotations for a given entity.
+ * Display a plugin-specified rendered list of annotations for an entity.
*
- * The list is produced as the result of the entity:annotate plugin hook
- * and is designed to provide a more generic framework to allow plugins
- * to extend the generic display of entities with their own annotation
- * renderings.
+ * This displays the output of functions registered to the entity:annotation,
+ * $entity_type plugin hook.
*
- * This is called automatically by the framework from elgg_view_entity()
+ * This is called automatically by the framework from {@link elgg_view_entity()}
*
- * @param ElggEntity $entity
- * @param bool $full
- * @return string or false on failure
+ * @param ElggEntity $entity Entity
+ * @param bool $full_view Display full view?
+ *
+ * @return mixed string or false on failure
+ * @todo Change the hook name.
*/
-function elgg_view_entity_annotations(ElggEntity $entity, $full = true) {
-
- // No point continuing if entity is null
- if (!$entity) {
- return false;
- }
-
+function elgg_view_entity_annotations(ElggEntity $entity, $full_view = true) {
if (!($entity instanceof ElggEntity)) {
return false;
}
$entity_type = $entity->getType();
- $annotations = trigger_plugin_hook('entity:annotate', $entity_type,
+ $annotations = elgg_trigger_plugin_hook('entity:annotate', $entity_type,
array(
'entity' => $entity,
- 'full' => $full,
+ 'full_view' => $full_view,
)
);
@@ -767,235 +1112,428 @@ function elgg_view_entity_annotations(ElggEntity $entity, $full = true) {
}
/**
- * Displays an internal layout for the use of a plugin canvas.
- * Takes a variable number of parameters, which are made available
- * in the views as $vars['area1'] .. $vars['areaN'].
+ * Renders a title.
*
- * @param string $layout The name of the views in canvas/layouts/.
- * @return string The layout
+ * This is a shortcut for {@elgg_view page/elements/title}.
+ *
+ * @param string $title The page title
+ * @param array $vars View variables (was submenu be displayed? (deprecated))
+ *
+ * @return string The HTML (etc)
*/
-function elgg_view_layout($layout) {
- $arg = 1;
- $param_array = array();
- while ($arg < func_num_args()) {
- $param_array['area' . $arg] = func_get_arg($arg);
- $arg++;
+function elgg_view_title($title, $vars = array()) {
+ if (!is_array($vars)) {
+ elgg_deprecated_notice('setting $submenu in elgg_view_title() is deprecated', 1.8);
+ $vars = array('submenu' => $vars);
}
- if (elgg_view_exists("canvas/layouts/{$layout}")) {
- return elgg_view("canvas/layouts/{$layout}",$param_array);
- } else {
- return elgg_view("canvas/default",$param_array);
- }
+ $vars['title'] = $title;
+
+ return elgg_view('page/elements/title', $vars);
}
/**
- * Returns a view for the page title
+ * Displays a UNIX timestamp in a friendly way
*
- * @param string $title The page title
- * @param string $submenu Should a submenu be displayed? (default false, use not recommended)
- * @return string The HTML (etc)
+ * @see elgg_get_friendly_time()
+ *
+ * @param int $time A UNIX epoch timestamp
+ *
+ * @return string The friendly time HTML
+ * @since 1.7.2
*/
-function elgg_view_title($title, $submenu = false) {
- $title = elgg_view('page_elements/title', array('title' => $title, 'submenu' => $submenu));
-
- return $title;
+function elgg_view_friendly_time($time) {
+ return elgg_view('output/friendlytime', array('time' => $time));
}
/**
- * Automatically views comments and a comment form relating to the given entity
+ * Returns rendered comments and a comment form for an entity.
+ *
+ * @tip Plugins can override the output by registering a handler
+ * for the comments, $entity_type hook. The handler is responsible
+ * for formatting the comments and the add comment form.
*
- * @param ElggEntity $entity The entity to comment on
- * @param $add_comment Whether or not you want users to add more comments
- * @return string|false The HTML (etc) for the comments, or false on failure
+ * @param ElggEntity $entity The entity to view comments of
+ * @param bool $add_comment Include a form to add comments?
+ * @param array $vars Variables to pass to comment view
+ *
+ * @return string|false Rendered comments or false on failure
+ * @link http://docs.elgg.org/Entities/Comments
+ * @link http://docs.elgg.org/Annotations/Comments
*/
-function elgg_view_comments($entity, $add_comment = true){
-
+function elgg_view_comments($entity, $add_comment = true, array $vars = array()) {
if (!($entity instanceof ElggEntity)) {
return false;
}
- if ($comments = trigger_plugin_hook('comments',$entity->getType(),array('entity' => $entity),false)) {
- return $comments;
- } else {
- $comments = list_annotations($entity->getGUID(),'generic_comment');
-
- //display the new comment form if required
- if($add_comment){
- $comments .= elgg_view('comments/forms/edit',array('entity' => $entity));
- }
+ $vars['entity'] = $entity;
+ $vars['show_add_form'] = $add_comment;
+ $vars['class'] = elgg_extract('class', $vars, "{$entity->getSubtype()}-comments");
- return $comments;
+ $output = elgg_trigger_plugin_hook('comments', $entity->getType(), $vars, false);
+ if ($output) {
+ return $output;
+ } else {
+ return elgg_view('page/elements/comments', $vars);
}
}
-
/**
- * Wrapper function to display search listings.
+ * Wrapper function for the image block display pattern.
*
- * @param string $icon The icon for the listing
- * @param string $info Any information that needs to be displayed.
- * @return string The HTML (etc) representing the listing
+ * Fixed width media on the side (image, icon, flash, etc.).
+ * Descriptive content filling the rest of the column.
+ *
+ * This is a shortcut for {@elgg_view page/components/image_block}.
+ *
+ * @param string $image The icon and other information
+ * @param string $body Description content
+ * @param array $vars Additional parameters for the view
+ *
+ * @return string
+ * @since 1.8.0
*/
-function elgg_view_listing($icon, $info) {
- return elgg_view('entities/entity_listing',array('icon' => $icon, 'info' => $info));
+function elgg_view_image_block($image, $body, $vars = array()) {
+ $vars['image'] = $image;
+ $vars['body'] = $body;
+ return elgg_view('page/components/image_block', $vars);
}
/**
- * Sets an alternative function to handle templates, which will be passed to by elgg_view.
- * This function must take the $view and $vars parameters from elgg_view:
+ * Wrapper function for the module display pattern.
*
- * function my_template_function(string $view, array $vars = array())
+ * Box with header, body, footer
*
- * @see elgg_view
+ * This is a shortcut for {@elgg_view page/components/module}.
*
- * @param string $function_name The name of the function to pass to.
- * @return true|false
+ * @param string $type The type of module (main, info, popup, aside, etc.)
+ * @param string $title A title to put in the header
+ * @param string $body Content of the module
+ * @param array $vars Additional parameters for the module
+ *
+ * @return string
+ * @since 1.8.0
*/
-function set_template_handler($function_name) {
- global $CONFIG;
- if (!empty($function_name) && is_callable($function_name)) {
- $CONFIG->template_handler = $function_name;
- return true;
- }
- return false;
+function elgg_view_module($type, $title, $body, array $vars = array()) {
+ $vars['class'] = elgg_extract('class', $vars, '') . " elgg-module-$type";
+ $vars['title'] = $title;
+ $vars['body'] = $body;
+ return elgg_view('page/components/module', $vars);
}
/**
- * Extends a view.
+ * Renders a human-readable representation of a river item
*
- * The addititional views are displayed before or after the primary view.
- * Priorities less than 500 are displayed before the primary view and
- * greater than 500 after. The default priority is 501.
+ * @param ElggRiverItem $item A river item object
+ * @param array $vars An array of variables for the view
*
- * @param string $view The view to extend.
- * @param string $view_extension This view is added to $view
- * @param int $priority The priority, from 0 to 1000, to add at (lowest numbers displayed first)
- * @param string $viewtype Not used
+ * @return string returns empty string if could not be rendered
*/
-function elgg_extend_view($view, $view_extension, $priority = 501, $viewtype = '') {
- global $CONFIG;
-
- if (!isset($CONFIG->views)) {
- $CONFIG->views = new stdClass;
+function elgg_view_river_item($item, array $vars = array()) {
+ if (!($item instanceof ElggRiverItem)) {
+ return '';
}
-
- if (!isset($CONFIG->views->extensions)) {
- $CONFIG->views->extensions = array();
+ // checking default viewtype since some viewtypes do not have unique views per item (rss)
+ $view = $item->getView();
+ if (!$view || !elgg_view_exists($view, 'default')) {
+ return '';
}
- if (!isset($CONFIG->views->extensions[$view])) {
- $CONFIG->views->extensions[$view][500] = "{$view}";
+ $subject = $item->getSubjectEntity();
+ $object = $item->getObjectEntity();
+ if (!$subject || !$object) {
+ // subject is disabled or subject/object deleted
+ return '';
}
- while(isset($CONFIG->views->extensions[$view][$priority])) {
- $priority++;
- }
+ // @todo this needs to be cleaned up
+ // Don't hide objects in closed groups that a user can see.
+ // see https://github.com/elgg/elgg/issues/4789
+ // else {
+ // // hide based on object's container
+ // $visibility = ElggGroupItemVisibility::factory($object->container_guid);
+ // if ($visibility->shouldHideItems) {
+ // return '';
+ // }
+ // }
- $CONFIG->views->extensions[$view][$priority] = "{$view_extension}";
- ksort($CONFIG->views->extensions[$view]);
+ $vars['item'] = $item;
+
+ return elgg_view('river/item', $vars);
}
/**
- * Unextends a view.
+ * Convenience function for generating a form from a view in a standard location.
*
- * @param string $view The view that was extended.
- * @param string $view_extension This view that was added to $view
- * @return bool
- * @since 1.7.2
+ * This function assumes that the body of the form is located at "forms/$action" and
+ * sets the action by default to "action/$action". Automatically wraps the forms/$action
+ * view with a <form> tag and inserts the anti-csrf security tokens.
+ *
+ * @tip This automatically appends elgg-form-action-name to the form's class. It replaces any
+ * slashes with dashes (blog/save becomes elgg-form-blog-save)
+ *
+ * @example
+ * <code>echo elgg_view_form('login');</code>
+ *
+ * This would assume a "login" form body to be at "forms/login" and would set the action
+ * of the form to "http://yoursite.com/action/login".
+ *
+ * If elgg_view('forms/login') is:
+ * <input type="text" name="username" />
+ * <input type="password" name="password" />
+ *
+ * Then elgg_view_form('login') generates:
+ * <form action="http://yoursite.com/action/login" method="post">
+ * ...security tokens...
+ * <input type="text" name="username" />
+ * <input type="password" name="password" />
+ * </form>
+ *
+ * @param string $action The name of the action. An action name does not include
+ * the leading "action/". For example, "login" is an action name.
+ * @param array $form_vars $vars environment passed to the "input/form" view
+ * @param array $body_vars $vars environment passed to the "forms/$action" view
+ *
+ * @return string The complete form
*/
-function elgg_unextend_view($view, $view_extension) {
+function elgg_view_form($action, $form_vars = array(), $body_vars = array()) {
global $CONFIG;
- if (!isset($CONFIG->views)) {
- return FALSE;
+ $defaults = array(
+ 'action' => $CONFIG->wwwroot . "action/$action",
+ 'body' => elgg_view("forms/$action", $body_vars)
+ );
+
+ $form_class = 'elgg-form-' . preg_replace('/[^a-z0-9]/i', '-', $action);
+
+ // append elgg-form class to any class options set
+ if (isset($form_vars['class'])) {
+ $form_vars['class'] = $form_vars['class'] . " $form_class";
+ } else {
+ $form_vars['class'] = $form_class;
}
- if (!isset($CONFIG->views->extensions)) {
- return FALSE;
+ return elgg_view('input/form', array_merge($defaults, $form_vars));
+}
+
+/**
+ * View an item in a list
+ *
+ * @param ElggEntity|ElggAnnotation $item
+ * @param array $vars Additional parameters for the rendering
+ *
+ * @return string
+ * @since 1.8.0
+ * @access private
+ */
+function elgg_view_list_item($item, array $vars = array()) {
+ global $CONFIG;
+
+ $type = $item->getType();
+ if (in_array($type, $CONFIG->entity_types)) {
+ return elgg_view_entity($item, $vars);
+ } else if ($type == 'annotation') {
+ return elgg_view_annotation($item, $vars);
+ } else if ($type == 'river') {
+ return elgg_view_river_item($item, $vars);
}
- if (!isset($CONFIG->views->extensions[$view])) {
- return FALSE;
+ return '';
+}
+
+/**
+ * View one of the elgg sprite icons
+ *
+ * Shorthand for <span class="elgg-icon elgg-icon-$name"></span>
+ *
+ * @param string $name The specific icon to display
+ * @param string $class Additional class: float, float-alt, or custom class
+ *
+ * @return string The html for displaying an icon
+ */
+function elgg_view_icon($name, $class = '') {
+ // @todo deprecate boolean in Elgg 1.9
+ if ($class === true) {
+ $class = 'float';
}
+ return "<span class=\"elgg-icon elgg-icon-$name $class\"></span>";
+}
- $priority = array_search($view_extension, $CONFIG->views->extensions[$view]);
- if ($priority === FALSE) {
- return FALSE;
+/**
+ * Displays a user's access collections, using the core/friends/collections view
+ *
+ * @param int $owner_guid The GUID of the owning user
+ *
+ * @return string A formatted rendition of the collections
+ * @todo Move to the friends/collection.php page.
+ * @access private
+ */
+function elgg_view_access_collections($owner_guid) {
+ if ($collections = get_user_access_collections($owner_guid)) {
+ foreach ($collections as $key => $collection) {
+ $collections[$key]->members = get_members_of_access_collection($collection->id, true);
+ $collections[$key]->entities = get_user_friends($owner_guid, "", 9999);
+ }
}
- unset($CONFIG->views->extensions[$view][$priority]);
-
- return TRUE;
+ return elgg_view('core/friends/collections', array('collections' => $collections));
}
/**
- * @deprecated 1.7. Use elgg_extend_view().
- * @param $view
- * @param $view_name
- * @param $priority
- * @param $viewtype
+ * Registers a function to handle templates.
+ *
+ * Alternative template handlers can be registered to handle
+ * all output functions. By default, {@link elgg_view()} will
+ * simply include the view file. If an alternate template handler
+ * is registered, the view name and passed $vars will be passed to the
+ * registered function, which is then responsible for generating and returning
+ * output.
+ *
+ * Template handlers need to accept two arguments: string $view_name and array
+ * $vars.
+ *
+ * @warning This is experimental.
+ *
+ * @param string $function_name The name of the function to pass to.
+ *
+ * @return bool
+ * @see elgg_view()
+ * @link http://docs.elgg.org/Views/TemplateHandlers
*/
-function extend_view($view, $view_name, $priority = 501, $viewtype = '') {
- elgg_deprecated_notice('extend_view() was deprecated by elgg_extend_view()!', 1.7);
- elgg_extend_view($view, $view_name, $priority, $viewtype);
+function set_template_handler($function_name) {
+ global $CONFIG;
+
+ if (is_callable($function_name)) {
+ $CONFIG->template_handler = $function_name;
+ return true;
+ }
+ return false;
}
/**
- * Set an alternative base location for a view (as opposed to the default of $CONFIG->viewpath)
+ * Returns the name of views for in a directory.
*
- * @param string $view The name of the view
- * @param string $location The base location path
+ * Use this to get all namespaced views under the first element.
+ *
+ * @param string $dir The main directory that holds the views. (mod/profile/views/)
+ * @param string $base The root name of the view to use, without the viewtype. (profile)
+ *
+ * @return array
+ * @since 1.7.0
+ * @todo Why isn't this used anywhere else but in elgg_view_tree()?
+ * Seems like a useful function for autodiscovery.
+ * @access private
+ */
+function elgg_get_views($dir, $base) {
+ $return = array();
+ if (file_exists($dir) && is_dir($dir)) {
+ if ($handle = opendir($dir)) {
+ while ($view = readdir($handle)) {
+ if (!in_array($view, array('.', '..', '.svn', 'CVS'))) {
+ if (is_dir($dir . '/' . $view)) {
+ if ($val = elgg_get_views($dir . '/' . $view, $base . '/' . $view)) {
+ $return = array_merge($return, $val);
+ }
+ } else {
+ $view = str_replace('.php', '', $view);
+ $return[] = $base . '/' . $view;
+ }
+ }
+ }
+ }
+ }
+
+ return $return;
+}
+
+/**
+ * Returns all views below a partial view.
+ *
+ * Settings $view_root = 'profile' will show all available views under
+ * the "profile" namespace.
+ *
+ * @param string $view_root The root view
+ * @param string $viewtype Optionally specify a view type
+ * other than the current one.
+ *
+ * @return array A list of view names underneath that root view
+ * @todo This is used once in the deprecated get_activity_stream_data() function.
+ * @access private
*/
-function set_view_location($view, $location, $viewtype = '') {
+function elgg_view_tree($view_root, $viewtype = "") {
global $CONFIG;
+ static $treecache = array();
- if (empty($viewtype)) {
- $viewtype = 'default';
+ // Get viewtype
+ if (!$viewtype) {
+ $viewtype = elgg_get_viewtype();
}
- if (!isset($CONFIG->views)) {
- $CONFIG->views = new stdClass;
+ // A little light internal caching
+ if (!empty($treecache[$view_root])) {
+ return $treecache[$view_root];
}
- if (!isset($CONFIG->views->locations)) {
- $CONFIG->views->locations = array($viewtype => array($view => $location));
+ // Examine $CONFIG->views->locations
+ if (isset($CONFIG->views->locations[$viewtype])) {
+ foreach ($CONFIG->views->locations[$viewtype] as $view => $path) {
+ $pos = strpos($view, $view_root);
+ if ($pos === 0) {
+ $treecache[$view_root][] = $view;
+ }
+ }
+ }
- } else if (!isset($CONFIG->views->locations[$viewtype])) {
- $CONFIG->views->locations[$viewtype] = array($view => $location);
+ // Now examine core
+ $location = $CONFIG->viewpath;
+ $viewtype = elgg_get_viewtype();
+ $root = $location . $viewtype . '/' . $view_root;
- } else {
- $CONFIG->views->locations[$viewtype][$view] = $location;
+ if (file_exists($root) && is_dir($root)) {
+ $val = elgg_get_views($root, $view_root);
+ if (!is_array($treecache[$view_root])) {
+ $treecache[$view_root] = array();
+ }
+ $treecache[$view_root] = array_merge($treecache[$view_root], $val);
}
+
+ return $treecache[$view_root];
}
/**
- * Auto-registers views from a particular starting location
+ * Auto-registers views from a location.
+ *
+ * @note Views in plugin/views/ are automatically registered for active plugins.
+ * Plugin authors would only need to call this if optionally including
+ * an entire views structure.
*
- * @param string $view_base The base of the view name
- * @param string $folder The folder to begin looking in
- * @param string $base_location_path The base views directory to use with set_view_location
- * @param string $viewtype The type of view we're looking at (default, rss, etc)
+ * @param string $view_base Optional The base of the view name without the view type.
+ * @param string $folder Required The folder to begin looking in
+ * @param string $base_location_path The base views directory to use with elgg_set_view_location()
+ * @param string $viewtype The type of view we're looking at (default, rss, etc)
+ *
+ * @return bool returns false if folder can't be read
+ * @since 1.7.0
+ * @see elgg_set_view_location()
+ * @todo This seems overly complicated.
+ * @access private
*/
function autoregister_views($view_base, $folder, $base_location_path, $viewtype) {
- if (!isset($i)) {
- $i = 0;
- }
-
if ($handle = opendir($folder)) {
while ($view = readdir($handle)) {
- if (!in_array($view,array('.','..','.svn','CVS')) && !is_dir($folder . "/" . $view)) {
+ if (!in_array($view, array('.', '..', '.svn', 'CVS')) && !is_dir($folder . "/" . $view)) {
// this includes png files because some icons are stored within view directories.
// See commit [1705]
- if ((substr_count($view,".php") > 0) || (substr_count($view,".png") > 0)) {
+ if ((substr_count($view, ".php") > 0) || (substr_count($view, ".png") > 0)) {
if (!empty($view_base)) {
$view_base_new = $view_base . "/";
} else {
$view_base_new = "";
}
- set_view_location($view_base_new . str_replace('.php', '', $view), $base_location_path, $viewtype);
+ elgg_set_view_location($view_base_new . str_replace('.php', '', $view),
+ $base_location_path, $viewtype);
}
} else if (!in_array($view, array('.', '..', '.svn', 'CVS')) && is_dir($folder . "/" . $view)) {
if (!empty($view_base)) {
@@ -1003,7 +1541,8 @@ function autoregister_views($view_base, $folder, $base_location_path, $viewtype)
} else {
$view_base_new = "";
}
- autoregister_views($view_base_new . $view, $folder . "/" . $view, $base_location_path, $viewtype);
+ autoregister_views($view_base_new . $view, $folder . "/" . $view,
+ $base_location_path, $viewtype);
}
}
return TRUE;
@@ -1013,47 +1552,114 @@ function autoregister_views($view_base, $folder, $base_location_path, $viewtype)
}
/**
- * Returns a representation of a full 'page' (which might be an HTML page, RSS file, etc, depending on the current view)
+ * Add the rss link to the extras when if needed
*
- * @param unknown_type $title
- * @param unknown_type $body
- * @return unknown
+ * @return void
+ * @access private
*/
-function page_draw($title, $body, $sidebar = "", $page_shell = 'page_shells/default') {
+function elgg_views_add_rss_link() {
+ global $autofeed;
+ if (isset($autofeed) && $autofeed == true) {
+ $url = current_page_url();
+ if (substr_count($url, '?')) {
+ $url .= "&view=rss";
+ } else {
+ $url .= "?view=rss";
+ }
- // get messages - try for errors first
- $sysmessages = system_messages(null, "errors");
- if (count($sysmessages["errors"]) == 0) {
- // no errors so grab rest of messages
- $sysmessages = system_messages(null, "");
- } else {
- // we have errors - clear out remaining messages
- system_messages(null, "");
+ $url = elgg_format_url($url);
+ elgg_register_menu_item('extras', array(
+ 'name' => 'rss',
+ 'text' => elgg_view_icon('rss'),
+ 'href' => $url,
+ 'title' => elgg_echo('feed:rss'),
+ ));
}
+}
- // Draw the page
- $output = elgg_view($page_shell, array(
- 'title' => $title,
- 'body' => $body,
- 'sidebar' => $sidebar,
- 'sysmessages' => $sysmessages,
- )
- );
- $split_output = str_split($output, 1024);
-
- foreach($split_output as $chunk) {
- echo $chunk;
+/**
+ * Registers deprecated views to avoid making some pages from older plugins
+ * completely empty.
+ *
+ * @access private
+ */
+function elgg_views_handle_deprecated_views() {
+ $location = elgg_get_view_location('page_elements/contentwrapper');
+ if ($location === "/var/www/views/") {
+ elgg_extend_view('page_elements/contentwrapper', 'page/elements/wrapper');
}
}
/**
- * Checks if $view_type is valid on this installation.
+ * Initialize viewtypes on system boot event
+ * This ensures simplecache is cleared during upgrades. See #2252
*
- * @param string $view_type
- * @return bool
+ * @return void
+ * @access private
+ * @elgg_event_handler boot system
*/
-function elgg_is_valid_view_type($view_type) {
+function elgg_views_boot() {
global $CONFIG;
- return in_array($view_type, $CONFIG->view_types);
-} \ No newline at end of file
+ elgg_register_simplecache_view('css/ie');
+ elgg_register_simplecache_view('css/ie6');
+ elgg_register_simplecache_view('css/ie7');
+
+ elgg_register_js('jquery', '/vendors/jquery/jquery-1.6.4.min.js', 'head');
+ elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.16.min.js', 'head');
+ elgg_register_js('jquery.form', '/vendors/jquery/jquery.form.js');
+
+ elgg_register_simplecache_view('js/elgg');
+ $elgg_js_url = elgg_get_simplecache_url('js', 'elgg');
+ elgg_register_js('elgg', $elgg_js_url, 'head');
+
+ elgg_load_js('jquery');
+ elgg_load_js('jquery-ui');
+ elgg_load_js('elgg');
+
+ elgg_register_simplecache_view('js/lightbox');
+ $lightbox_js_url = elgg_get_simplecache_url('js', 'lightbox');
+ elgg_register_js('lightbox', $lightbox_js_url);
+
+ elgg_register_simplecache_view('css/lightbox');
+ $lightbox_css_url = elgg_get_simplecache_url('css', 'lightbox');
+ elgg_register_css('lightbox', $lightbox_css_url);
+
+ elgg_register_simplecache_view('css/elgg');
+ $elgg_css_url = elgg_get_simplecache_url('css', 'elgg');
+ elgg_register_css('elgg', $elgg_css_url);
+
+ elgg_load_css('elgg');
+
+ elgg_register_ajax_view('js/languages');
+
+ elgg_register_plugin_hook_handler('output:before', 'layout', 'elgg_views_add_rss_link');
+
+ // discover the built-in view types
+ // @todo the cache is loaded in load_plugins() but we need to know view_types earlier
+ $view_path = $CONFIG->viewpath;
+
+ $views = scandir($view_path);
+
+ foreach ($views as $view) {
+ if ($view[0] !== '.' && is_dir($view_path . $view)) {
+ elgg_register_viewtype($view);
+ }
+ }
+
+ // set default icon sizes - can be overridden in settings.php or with plugin
+ if (!isset($CONFIG->icon_sizes)) {
+ $icon_sizes = array(
+ 'topbar' => array('w' => 16, 'h' => 16, 'square' => TRUE, 'upscale' => TRUE),
+ 'tiny' => array('w' => 25, 'h' => 25, 'square' => TRUE, 'upscale' => TRUE),
+ 'small' => array('w' => 40, 'h' => 40, 'square' => TRUE, 'upscale' => TRUE),
+ 'medium' => array('w' => 100, 'h' => 100, 'square' => TRUE, 'upscale' => TRUE),
+ 'large' => array('w' => 200, 'h' => 200, 'square' => FALSE, 'upscale' => FALSE),
+ 'master' => array('w' => 550, 'h' => 550, 'square' => FALSE, 'upscale' => FALSE),
+ );
+ elgg_set_config('icon_sizes', $icon_sizes);
+ }
+}
+
+elgg_register_event_handler('boot', 'system', 'elgg_views_boot');
+elgg_register_event_handler('init', 'system', 'elgg_views_handle_deprecated_views');
diff --git a/engine/lib/api.php b/engine/lib/web_services.php
index 0da0c82f0..51cad6f39 100644
--- a/engine/lib/api.php
+++ b/engine/lib/web_services.php
@@ -1,286 +1,13 @@
<?php
/**
- * Elgg API
- * Functions and objects which make up the API engine.
+ * Elgg web services API
+ * Functions and objects for exposing custom web services.
*
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd <info@elgg.com>
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage WebServicesAPI
*/
-// Result classes /////////////////////////////////////////////////////////////////////////
-
-/**
- * GenericResult Result superclass.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Core
- */
-abstract class GenericResult {
- /**
- * The status of the result.
- * @var int
- */
- private $status_code;
-
- /**
- * Message returned along with the status which is almost always an error message.
- * This must be human readable, understandable and localised.
- * @var string
- */
- private $message;
-
- /**
- * Result store.
- * Attach result specific informaton here.
- *
- * @var mixed. Should probably be an object of some sort.
- */
- private $result;
-
- /**
- * Set a status code and optional message.
- *
- * @param int $status The status code.
- * @param string $message The message.
- */
- protected function setStatusCode($status, $message = "") {
- $this->status_code = $status;
- $this->message = $message;
- }
-
- /**
- * Set the result.
- *
- * @param mixed $result
- */
- protected function setResult($result) {
- $this->result = $result;
- }
-
- protected function getStatusCode() {
- return $this->status_code;
- }
-
- protected function getStatusMessage() {
- return $this->message;
- }
-
- protected function getResult() {
- return $this->result;
- }
-
- /**
- * Serialise to a standard class.
- *
- * DEVNOTE: The API is only interested in data, we can not easily serialise
- * custom classes without the need for 1) the other side being PHP, 2) you need to have the class
- * definition installed, 3) its the right version!
- *
- * Therefore, I'm not bothering.
- *
- * Override this to include any more specific information, however api results should be attached to the
- * class using setResult().
- *
- * if $CONFIG->debug is set then additional information about the runtime environment and authentication will be
- * returned.
- *
- * @return stdClass Object containing the serialised result.
- */
- public function export() {
- global $ERRORS, $CONFIG, $_PAM_HANDLERS_MSG;
-
- $result = new stdClass;
-
- $result->status = $this->getStatusCode();
- if ($this->getStatusMessage()!="") {
- $result->message = $this->getStatusMessage();
- }
-
- $resultdata = $this->getResult();
- if (isset($resultdata)) {
- $result->result = $resultdata;
- }
-
- if (isset($CONFIG->debug)) {
- if (count($ERRORS)) {
- $result->runtime_errors = $ERRORS;
- }
-
- if (count($_PAM_HANDLERS_MSG)) {
- $result->pam = $_PAM_HANDLERS_MSG;
- }
- }
-
- return $result;
- }
-}
-
-/**
- * SuccessResult
- * Generic success result class, extend if you want to do something special.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Core
- */
-class SuccessResult extends GenericResult {
- public static $RESULT_SUCCESS = 0; // Do not change this from 0
-
- public function SuccessResult($result) {
- $this->setResult($result);
- $this->setStatusCode(SuccessResult::$RESULT_SUCCESS);
- }
-
- public static function getInstance($result) {
- // Return a new error object.
- return new SuccessResult($result);
- }
-}
-
-/**
- * ErrorResult
- * The error result class.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage Core
- */
-class ErrorResult extends GenericResult {
- // Fail with no specific code
- public static $RESULT_FAIL = -1 ;
-
- public static $RESULT_FAIL_APIKEY_DISABLED = -30;
- public static $RESULT_FAIL_APIKEY_INACTIVE = -31;
- public static $RESULT_FAIL_APIKEY_INVALID = -32;
-
- // Invalid, expired or missing auth token
- public static $RESULT_FAIL_AUTHTOKEN = -20;
-
- public function ErrorResult($message, $code = "", Exception $exception = NULL) {
- if ($code == "") {
- $code = ErrorResult::$RESULT_FAIL;
- }
-
- if ($exception!=NULL) {
- $this->setResult($exception->__toString());
- }
-
- $this->setStatusCode($code, $message);
- }
-
- /**
- * Get a new instance of the ErrorResult.
- *
- * @param string $message
- * @param int $code
- * @param Exception $exception Optional exception for generating a stack trace.
- */
- public static function getInstance($message, $code = "", Exception $exception = NULL) {
- // Return a new error object.
- return new ErrorResult($message, $code, $exception);
- }
-}
-
-// Caching of HMACs ///////////////////////////////////////////////////////////////////////
-
-/**
- * ElggHMACCache
- * Store cached data in a temporary database, only used by the HMAC stuff.
- *
- * @author Curverider Ltd <info@elgg.com>
- * @package Elgg
- * @subpackage API
- */
-class ElggHMACCache extends ElggCache {
- /**
- * Set the Elgg cache.
- *
- * @param int $max_age Maximum age in seconds, 0 if no limit.
- */
- function __construct($max_age = 0) {
- $this->set_variable("max_age", $max_age);
- }
-
- /**
- * Save a key
- *
- * @param string $key
- * @param string $data
- * @return boolean
- */
- public function save($key, $data) {
- global $CONFIG;
-
- $key = sanitise_string($key);
- $time = time();
-
- return insert_data("INSERT into {$CONFIG->dbprefix}hmac_cache (hmac, ts) VALUES ('$key', '$time')");
- }
-
- /**
- * Load a key
- *
- * @param string $key
- * @param int $offset
- * @param int $limit
- * @return string
- */
- public function load($key, $offset = 0, $limit = null) {
- global $CONFIG;
-
- $key = sanitise_string($key);
-
- $row = get_data_row("SELECT * from {$CONFIG->dbprefix}hmac_cache where hmac='$key'");
- if ($row) {
- return $row->hmac;
- }
-
- return false;
- }
-
- /**
- * Invalidate a given key.
- *
- * @param string $key
- * @return bool
- */
- public function delete($key) {
- global $CONFIG;
-
- $key = sanitise_string($key);
-
- return delete_data("DELETE from {$CONFIG->dbprefix}hmac_cache where hmac='$key'");
- }
-
- /**
- * Clear out all the contents of the cache.
- *
- * Not currently implemented in this cache type.
- */
- public function clear() {
- return true;
- }
-
- /**
- * Clean out old stuff.
- *
- */
- public function __destruct() {
- global $CONFIG;
-
- $time = time();
- $age = (int)$this->get_variable("max_age");
-
- $expires = $time-$age;
-
- delete_data("DELETE from {$CONFIG->dbprefix}hmac_cache where ts<$expires");
- }
-}
-
-// Primary Services API Server functions /////////////////////////////////////////////////////////////////////
+// Primary Services API Server functions
/**
* A global array holding API methods.
@@ -290,9 +17,10 @@ class ElggHMACCache extends ElggCache {
* "description" => "Some human readable description"
* "function" = 'my_function_callback'
* "parameters" = array (
- * "variable" = array ( // NB, the order should be the same as the function callback
+ * "variable" = array ( // the order should be the same as the function callback
* type => 'int' | 'bool' | 'float' | 'string'
* required => true (default) | false
+ * default => value // optional
* )
* )
* "call_method" = 'GET' | 'POST'
@@ -301,6 +29,7 @@ class ElggHMACCache extends ElggCache {
* )
* )
*/
+global $API_METHODS;
$API_METHODS = array();
/**
@@ -310,28 +39,38 @@ $API_METHODS = array();
* It also cannot handle arrays of bools or arrays of arrays.
* Also, input will be filtered to protect against XSS attacks through the API.
*
- * @param string $method The api name to expose - for example "myapi.dosomething"
- * @param string $function Your function callback.
- * @param array $parameters (optional) List of parameters in the same order as in your function.
- * Default values may be set for parameters which would allow REST api users flexibility in
- * what parameters are passed. Generally, optional parameters should be after required parameters.
- * This array should be in the format
- * "variable" = array (
- * type => 'int' | 'bool' | 'float' | 'string' | 'array'
- * required => true (default) | false
- * default => value (optional)
- * )
- * @param string $description (optional) human readable description of the function.
- * @param string $call_method (optional) Define what http method must be used for this function. Default: GET
- * @param bool $require_api_auth (optional) (default is false) Does this method require API authorization? (example: API key)
- * @param bool $require_user_auth (optional) (default is false) Does this method require user authorization?
+ * @param string $method The api name to expose - for example "myapi.dosomething"
+ * @param string $function Your function callback.
+ * @param array $parameters (optional) List of parameters in the same order as in
+ * your function. Default values may be set for parameters which
+ * allow REST api users flexibility in what parameters are passed.
+ * Generally, optional parameters should be after required
+ * parameters.
+ *
+ * This array should be in the format
+ * "variable" = array (
+ * type => 'int' | 'bool' | 'float' | 'string' | 'array'
+ * required => true (default) | false
+ * default => value (optional)
+ * )
+ * @param string $description (optional) human readable description of the function.
+ * @param string $call_method (optional) Define what http method must be used for
+ * this function. Default: GET
+ * @param bool $require_api_auth (optional) (default is false) Does this method
+ * require API authorization? (example: API key)
+ * @param bool $require_user_auth (optional) (default is false) Does this method
+ * require user authorization?
+ *
* @return bool
*/
-function expose_function($method, $function, array $parameters = NULL, $description = "", $call_method = "GET", $require_api_auth = false, $require_user_auth = false) {
+function expose_function($method, $function, array $parameters = NULL, $description = "",
+$call_method = "GET", $require_api_auth = false, $require_user_auth = false) {
+
global $API_METHODS;
if (($method == "") || ($function == "")) {
- throw new InvalidParameterException(elgg_echo('InvalidParameterException:APIMethodOrFunctionNotSet'));
+ $msg = elgg_echo('InvalidParameterException:APIMethodOrFunctionNotSet');
+ throw new InvalidParameterException($msg);
}
// does not check whether this method has already been exposed - good idea?
@@ -344,13 +83,15 @@ function expose_function($method, $function, array $parameters = NULL, $descript
if ($parameters != NULL) {
if (!is_array($parameters)) {
- throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:APIParametersArrayStructure'), $method));
+ $msg = elgg_echo('InvalidParameterException:APIParametersArrayStructure', array($method));
+ throw new InvalidParameterException($msg);
}
// catch common mistake of not setting up param array correctly
$first = current($parameters);
if (!is_array($first)) {
- throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:APIParametersArrayStructure'), $method));
+ $msg = elgg_echo('InvalidParameterException:APIParametersArrayStructure', array($method));
+ throw new InvalidParameterException($msg);
}
}
@@ -375,7 +116,10 @@ function expose_function($method, $function, array $parameters = NULL, $descript
$API_METHODS[$method]["call_method"] = 'GET';
break;
default :
- throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:UnrecognisedHttpMethod'), $call_method, $method));
+ $msg = elgg_echo('InvalidParameterException:UnrecognisedHttpMethod',
+ array($call_method, $method));
+
+ throw new InvalidParameterException($msg);
}
$API_METHODS[$method]["require_api_auth"] = $require_api_auth;
@@ -387,7 +131,12 @@ function expose_function($method, $function, array $parameters = NULL, $descript
/**
* Unregister an API method
+ *
* @param string $method The api name that was exposed
+ *
+ * @since 1.7.0
+ *
+ * @return void
*/
function unexpose_function($method) {
global $API_METHODS;
@@ -399,36 +148,37 @@ function unexpose_function($method) {
/**
* Check that the method call has the proper API and user authentication
+ *
* @param string $method The api name that was exposed
+ *
* @return true or throws an exception
* @throws APIException
+ * @since 1.7.0
+ * @access private
*/
function authenticate_method($method) {
global $API_METHODS;
// method must be exposed
if (!isset($API_METHODS[$method])) {
- throw new APIException(sprintf(elgg_echo('APIException:MethodCallNotImplemented'), $method));
- }
-
- // make sure that POST variables are available if relevant
- if (get_call_method() === 'POST') {
- include_post_data();
+ throw new APIException(elgg_echo('APIException:MethodCallNotImplemented', array($method)));
}
// check API authentication if required
if ($API_METHODS[$method]["require_api_auth"] == true) {
- if (pam_authenticate(null, "api") == false) {
+ $api_pam = new ElggPAM('api');
+ if ($api_pam->authenticate() !== true) {
throw new APIException(elgg_echo('APIException:APIAuthenticationFailed'));
}
}
- $user_auth_result = pam_authenticate();
+ $user_pam = new ElggPAM('user');
+ $user_auth_result = $user_pam->authenticate(array());
// check if user authentication is required
if ($API_METHODS[$method]["require_user_auth"] == true) {
if ($user_auth_result == false) {
- throw new APIException(elgg_echo('APIException:UserAuthenticationFailed'));
+ throw new APIException($user_pam->getFailureMessage(), ErrorResult::$RESULT_FAIL_AUTHTOKEN);
}
}
@@ -440,25 +190,34 @@ function authenticate_method($method) {
* A method is a function which you have previously exposed using expose_function.
*
* @param string $method Method, e.g. "foo.bar"
+ *
* @return GenericResult The result of the execution.
* @throws APIException, CallException
+ * @access private
*/
function execute_method($method) {
global $API_METHODS, $CONFIG;
// method must be exposed
if (!isset($API_METHODS[$method])) {
- throw new APIException(sprintf(elgg_echo('APIException:MethodCallNotImplemented'), $method));
+ $msg = elgg_echo('APIException:MethodCallNotImplemented', array($method));
+ throw new APIException($msg);
}
// function must be callable
- if (!(isset($API_METHODS[$method]["function"])) || !(is_callable($API_METHODS[$method]["function"]))) {
- throw new APIException(sprintf(elgg_echo('APIException:FunctionDoesNotExist'), $method));
+ if (!(isset($API_METHODS[$method]["function"]))
+ || !(is_callable($API_METHODS[$method]["function"]))) {
+
+ $msg = elgg_echo('APIException:FunctionDoesNotExist', array($method));
+ throw new APIException($msg);
}
// check http call method
if (strcmp(get_call_method(), $API_METHODS[$method]["call_method"]) != 0) {
- throw new CallException(sprintf(elgg_echo('CallException:InvalidCallMethod'), $method, $API_METHODS[$method]["call_method"]));
+ $msg = elgg_echo('CallException:InvalidCallMethod', array($method,
+ $API_METHODS[$method]["call_method"]));
+
+ throw new CallException($msg);
}
$parameters = get_parameters_for_method($method);
@@ -473,6 +232,7 @@ function execute_method($method) {
$function = $API_METHODS[$method]["function"];
$serialised_parameters = trim($serialised_parameters, ", ");
+ // @todo document why we cannot use call_user_func_array here
$result = eval("return $function($serialised_parameters);");
// Sanity check result
@@ -482,12 +242,14 @@ function execute_method($method) {
}
if ($result === false) {
- throw new APIException(sprintf(elgg_echo('APIException:FunctionParseError'), $function, $serialised_parameters));
+ $msg = elgg_echo('APIException:FunctionParseError', array($function, $serialised_parameters));
+ throw new APIException($msg);
}
- if ($result === NULL) {
+ if ($result === NULL) {
// If no value
- throw new APIException(sprintf(elgg_echo('APIException:FunctionNoReturn'), $function, $serialised_parameters));
+ $msg = elgg_echo('APIException:FunctionNoReturn', array($function, $serialised_parameters));
+ throw new APIException($msg);
}
// Otherwise assume that the call was successful and return it as a success object.
@@ -496,7 +258,9 @@ function execute_method($method) {
/**
* Get the request method.
+ *
* @return string HTTP request method
+ * @access private
*/
function get_call_method() {
return $_SERVER['REQUEST_METHOD'];
@@ -509,7 +273,9 @@ function get_call_method() {
* an associated array.
*
* @param string $method The method
+ *
* @return array containing parameters as key => value
+ * @access private
*/
function get_parameters_for_method($method) {
global $API_METHODS;
@@ -520,7 +286,7 @@ function get_parameters_for_method($method) {
if (isset($API_METHODS[$method]['parameters'])) {
foreach ($API_METHODS[$method]['parameters'] as $k => $v) {
$param = get_input($k); // Make things go through the sanitiser
- if ($param !== '') {
+ if ($param !== '' && $param !== null) {
$sanitised[$k] = $param;
} else {
// parameter wasn't passed so check for default
@@ -537,46 +303,27 @@ function get_parameters_for_method($method) {
/**
* Get POST data
* Since this is called through a handler, we need to manually get the post data
- * @return POST data from PHP
+ *
+ * @return POST data as string encoded as multipart/form-data
+ * @access private
*/
function get_post_data() {
- global $GLOBALS;
- $postdata = '';
- if (isset($GLOBALS['HTTP_RAW_POST_DATA']))
- $postdata = $GLOBALS['HTTP_RAW_POST_DATA'];
-
- // Attempt another method to return post data (incase always_populate_raw_post_data is switched off)
- if (!$postdata) {
- $postdata = file_get_contents('php://input');
- }
+ $postdata = file_get_contents('php://input');
return $postdata;
}
/**
- * This fixes the post parameters that are munged due to page handler
- */
-function include_post_data() {
-
- $postdata = get_post_data();
-
- if (isset($postdata)) {
- $query_arr = elgg_parse_str($postdata);
- if (is_array($query_arr)) {
- foreach($query_arr as $name => $val) {
- set_input($name, $val);
- }
- }
- }
-}
-
-/**
* Verify that the required parameters are present
- * @param $method
- * @param $parameters
+ *
+ * @param string $method Method name
+ * @param array $parameters List of expected parameters
+ *
* @return true on success or exception
* @throws APIException
+ * @since 1.7.0
+ * @access private
*/
function verify_parameters($method, $parameters) {
global $API_METHODS;
@@ -590,12 +337,15 @@ function verify_parameters($method, $parameters) {
foreach ($API_METHODS[$method]['parameters'] as $key => $value) {
// this tests the expose structure: must be array to describe parameter and type must be defined
if (!is_array($value) || !isset($value['type'])) {
- throw new APIException(sprintf(elgg_echo('APIException:InvalidParameter'), $key, $method));
+
+ $msg = elgg_echo('APIException:InvalidParameter', array($key, $method));
+ throw new APIException($msg);
}
// Check that the variable is present in the request if required
if ($value['required'] && !array_key_exists($key, $parameters)) {
- throw new APIException(sprintf(elgg_echo('APIException:MissingParameterInMethod'), $key, $method));
+ $msg = elgg_echo('APIException:MissingParameterInMethod', array($key, $method));
+ throw new APIException($msg);
}
}
@@ -605,10 +355,13 @@ function verify_parameters($method, $parameters) {
/**
* Serialize an array of parameters for an API method call
*
- * @param string $method API method name
- * @param array $parameters Array of parameters
+ * @param string $method API method name
+ * @param array $parameters Array of parameters
+ *
* @return string or exception
* @throws APIException
+ * @since 1.7.0
+ * @access private
*/
function serialise_parameters($method, $parameters) {
global $API_METHODS;
@@ -654,7 +407,8 @@ function serialise_parameters($method, $parameters) {
case 'array':
// we can handle an array of strings, maybe ints, definitely not booleans or other arrays
if (!is_array($parameters[$key])) {
- throw new APIException(sprintf(elgg_echo('APIException:ParameterNotArray'), $key));
+ $msg = elgg_echo('APIException:ParameterNotArray', array($key));
+ throw new APIException($msg);
}
$array = "array(";
@@ -666,7 +420,7 @@ function serialise_parameters($method, $parameters) {
$array .= "'$k'=>'$v',";
}
- $array = trim($array,",");
+ $array = trim($array, ",");
$array .= ")";
$array = ",$array";
@@ -674,7 +428,8 @@ function serialise_parameters($method, $parameters) {
$serialised_parameters .= $array;
break;
default:
- throw new APIException(sprintf(elgg_echo('APIException:UnrecognisedTypeCast'), $value['type'], $key, $method));
+ $msg = elgg_echo('APIException:UnrecognisedTypeCast', array($value['type'], $key, $method));
+ throw new APIException($msg);
}
}
@@ -685,8 +440,13 @@ function serialise_parameters($method, $parameters) {
/**
* PAM: Confirm that the call includes a valid API key
+ *
* @return true if good API key - otherwise throws exception
+ *
+ * @return mixed
* @throws APIException
+ * @since 1.7.0
+ * @access private
*/
function api_auth_key() {
global $CONFIG;
@@ -706,14 +466,18 @@ function api_auth_key() {
// can be used for keeping stats
// plugin can also return false to fail this authentication method
- return trigger_plugin_hook('api_key', 'use', $api_key, true);
+ return elgg_trigger_plugin_hook('api_key', 'use', $api_key, true);
}
/**
* PAM: Confirm the HMAC signature
+ *
* @return true if success - otherwise throws exception
+ *
* @throws SecurityException
+ * @since 1.7.0
+ * @access private
*/
function api_auth_hmac() {
global $CONFIG;
@@ -725,7 +489,8 @@ function api_auth_hmac() {
$api_user = get_api_user($CONFIG->site_id, $api_header->api_key);
if (!$api_user) {
- throw new SecurityException(elgg_echo('SecurityException:InvalidAPIKey'), ErrorResult::$RESULT_FAIL_APIKEY_INVALID);
+ throw new SecurityException(elgg_echo('SecurityException:InvalidAPIKey'),
+ ErrorResult::$RESULT_FAIL_APIKEY_INVALID);
}
// Get the secret key
@@ -754,12 +519,15 @@ function api_auth_hmac() {
}
// Validate post data
- if ($api_header->method=="POST") {
+ if ($api_header->method == "POST") {
$postdata = get_post_data();
$calculated_posthash = calculate_posthash($postdata, $api_header->posthash_algo);
- if (strcmp($api_header->posthash, $calculated_posthash)!=0) {
- throw new SecurityException(sprintf(elgg_echo('SecurityException:InvalidPostHash'), $calculated_posthash, $api_header->posthash));
+ if (strcmp($api_header->posthash, $calculated_posthash) != 0) {
+ $msg = elgg_echo('SecurityException:InvalidPostHash',
+ array($calculated_posthash, $api_header->posthash));
+
+ throw new SecurityException($msg);
}
}
@@ -774,6 +542,7 @@ function api_auth_hmac() {
*
* @return stdClass Containing all the values.
* @throws APIException Detailing any error.
+ * @access private
*/
function get_and_validate_api_headers() {
$result = new stdClass;
@@ -809,7 +578,7 @@ function get_and_validate_api_headers() {
// This values determines how long the HMAC cache needs to store previous
// signatures. Heavy use of HMAC is better handled with a shorter sig lifetime.
// See cache_hmac_check_replay()
- if (($result->time<(time()-90000)) || ($result->time>(time()+90000))) {
+ if (($result->time < (time() - 90000)) || ($result->time > (time() + 90000))) {
throw new APIException(elgg_echo('APIException:TemporalDrift'));
}
@@ -843,13 +612,15 @@ function get_and_validate_api_headers() {
* This also gives us an easy way to disable algorithms.
*
* @param string $algo The algorithm
+ *
* @return string The php algorithm
* @throws APIException if an algorithm is not supported.
+ * @access private
*/
function map_api_hash($algo) {
$algo = strtolower(sanitise_string($algo));
$supported_algos = array(
- "md5" => "md5", // TODO: Consider phasing this out
+ "md5" => "md5", // @todo Consider phasing this out
"sha" => "sha1", // alias for sha1
"sha1" => "sha1",
"sha256" => "sha256"
@@ -859,7 +630,7 @@ function map_api_hash($algo) {
return $supported_algos[$algo];
}
- throw new APIException(sprintf(elgg_echo('APIException:AlgorithmNotSupported'), $algo));
+ throw new APIException(elgg_echo('APIException:AlgorithmNotSupported', array($algo)));
}
/**
@@ -867,15 +638,21 @@ function map_api_hash($algo) {
* This function signs an api request using the information provided. The signature returned
* has been base64 encoded and then url encoded.
*
- * @param string $algo The HMAC algorithm used
- * @param string $time String representation of unix time
- * @param string $api_key Your api key
- * @param string $secret Your private key
- * @param string $get_variables URLEncoded string representation of the get variable parameters, eg "method=user&guid=2"
- * @param string $post_hash Optional sha1 hash of the post data.
+ * @param string $algo The HMAC algorithm used
+ * @param string $time String representation of unix time
+ * @param string $nonce Nonce
+ * @param string $api_key Your api key
+ * @param string $secret_key Your private key
+ * @param string $get_variables URLEncoded string representation of the get variable parameters,
+ * eg "method=user&guid=2"
+ * @param string $post_hash Optional sha1 hash of the post data.
+ *
* @return string The HMAC signature
+ * @access private
*/
-function calculate_hmac($algo, $time, $nonce, $api_key, $secret_key, $get_variables, $post_hash = "") {
+function calculate_hmac($algo, $time, $nonce, $api_key, $secret_key,
+$get_variables, $post_hash = "") {
+
global $CONFIG;
elgg_log("HMAC Parts: $algo, $time, $api_key, $secret_key, $get_variables, $post_hash");
@@ -886,7 +663,7 @@ function calculate_hmac($algo, $time, $nonce, $api_key, $secret_key, $get_variab
hash_update($ctx, trim($nonce));
hash_update($ctx, trim($api_key));
hash_update($ctx, trim($get_variables));
- if (trim($post_hash)!="") {
+ if (trim($post_hash) != "") {
hash_update($ctx, trim($post_hash));
}
@@ -896,11 +673,13 @@ function calculate_hmac($algo, $time, $nonce, $api_key, $secret_key, $get_variab
/**
* Calculate a hash for some post data.
*
- * TODO: Work out how to handle really large bits of data.
+ * @todo Work out how to handle really large bits of data.
+ *
+ * @param string $postdata The post data.
+ * @param string $algo The algorithm used.
*
- * @param string $postdata string The post data.
- * @param string $algo The algorithm used.
* @return string The hash.
+ * @access private
*/
function calculate_posthash($postdata, $algo) {
$ctx = hash_init(map_api_hash($algo));
@@ -915,7 +694,9 @@ function calculate_posthash($postdata, $algo) {
* hasn't been seen before, and secondly it will add the given hmac to the cache.
*
* @param string $hmac The hmac string.
+ *
* @return bool True if replay detected, false if not.
+ * @access private
*/
function cache_hmac_check_replay($hmac) {
// cache lifetime is 25 hours (this should be related to the time drift
@@ -937,6 +718,7 @@ function cache_hmac_check_replay($hmac) {
* Generate a new API user for a site, returning a new keypair on success.
*
* @param int $site_guid The GUID of the site. (default is current site)
+ *
* @return stdClass object or false
*/
function create_api_user($site_guid) {
@@ -948,8 +730,8 @@ function create_api_user($site_guid) {
$site_guid = (int)$site_guid;
- $public = sha1(rand().$site_guid.microtime());
- $secret = sha1(rand().$site_guid.microtime().$public);
+ $public = sha1(rand() . $site_guid . microtime());
+ $secret = sha1(rand() . $site_guid . microtime() . $public);
$insert = insert_data("INSERT into {$CONFIG->dbprefix}api_users
(site_guid, api_key, secret) values
@@ -963,10 +745,12 @@ function create_api_user($site_guid) {
}
/**
- * Find an API User's details based on the provided public api key. These users are not users in the traditional sense.
+ * Find an API User's details based on the provided public api key.
+ * These users are not users in the traditional sense.
+ *
+ * @param int $site_guid The GUID of the site.
+ * @param string $api_key The API Key
*
- * @param int $site_guid The GUID of the site.
- * @param string $api_key The API Key
* @return mixed stdClass representing the database row or false.
*/
function get_api_user($site_guid, $api_key) {
@@ -975,14 +759,18 @@ function get_api_user($site_guid, $api_key) {
$api_key = sanitise_string($api_key);
$site_guid = (int)$site_guid;
- return get_data_row("SELECT * from {$CONFIG->dbprefix}api_users where api_key='$api_key' and site_guid=$site_guid and active=1");
+ $query = "SELECT * from {$CONFIG->dbprefix}api_users"
+ . " where api_key='$api_key' and site_guid=$site_guid and active=1";
+
+ return get_data_row($query);
}
/**
* Revoke an api user key.
*
- * @param int $site_guid The GUID of the site.
- * @param string $api_key The API Key (public).
+ * @param int $site_guid The GUID of the site.
+ * @param string $api_key The API Key (public).
+ *
* @return bool
*/
function remove_api_user($site_guid, $api_key) {
@@ -997,7 +785,7 @@ function remove_api_user($site_guid, $api_key) {
}
-// User Authorization functions ////////////////////////////////////////////////////////////////
+// User Authorization functions
/**
* Check the user token
@@ -1005,10 +793,10 @@ function remove_api_user($site_guid, $api_key) {
* it is present and is valid. The user gets logged in so with the current
* session code of Elgg, that user will be logged out of all other sessions.
*
- * @param array/mixed $credentials
* @return bool
+ * @access private
*/
-function pam_auth_usertoken($credentials = NULL) {
+function pam_auth_usertoken() {
global $CONFIG;
$token = get_input('auth_token');
@@ -1027,7 +815,7 @@ function pam_auth_usertoken($credentials = NULL) {
}
// Not an elgg user
- if ( (!$u instanceof ElggUser)) {
+ if ((!$u instanceof ElggUser)) {
return false;
}
@@ -1049,19 +837,22 @@ function pam_auth_usertoken($credentials = NULL) {
/**
* See if the user has a valid login sesson
+ *
* @return bool
+ * @access private
*/
-function pam_auth_session($credentials = NULL) {
- return isloggedin();
+function pam_auth_session() {
+ return elgg_is_logged_in();
}
-// user token functions /////////////////////////////////////////////////////////////////////
+// user token functions
/**
* Obtain a token for a user.
*
* @param string $username The username
- * @param int $expire minutes until token expires (default is 60 minutes)
+ * @param int $expire Minutes until token expires (default is 60 minutes)
+ *
* @return bool
*/
function create_user_token($username, $expire = 60) {
@@ -1071,7 +862,7 @@ function create_user_token($username, $expire = 60) {
$user = get_user_by_username($username);
$time = time();
$time += 60 * $expire;
- $token = md5(rand(). microtime() . $username . $time . $site_guid);
+ $token = md5(rand() . microtime() . $username . $time . $site_guid);
if (!$user) {
return false;
@@ -1079,7 +870,8 @@ function create_user_token($username, $expire = 60) {
if (insert_data("INSERT into {$CONFIG->dbprefix}users_apisessions
(user_guid, site_guid, token, expires) values
- ({$user->guid}, $site_guid, '$token', '$time') on duplicate key update token='$token', expires='$time'")) {
+ ({$user->guid}, $site_guid, '$token', '$time')
+ on duplicate key update token='$token', expires='$time'")) {
return $token;
}
@@ -1091,8 +883,10 @@ function create_user_token($username, $expire = 60) {
*
* @param int $user_guid The user GUID
* @param int $site_guid The ID of the site (default is current site)
+ *
* @return false if none available or array of stdClass objects
* (see users_apisessions schema for available variables in objects)
+ * @since 1.7.0
*/
function get_user_tokens($user_guid, $site_guid) {
global $CONFIG;
@@ -1113,11 +907,12 @@ function get_user_tokens($user_guid, $site_guid) {
/**
* Validate a token against a given site.
*
- * A token registered with one site can not be used from a different apikey(site), so be aware of this
- * during development.
+ * A token registered with one site can not be used from a
+ * different apikey(site), so be aware of this during development.
+ *
+ * @param string $token The Token.
+ * @param int $site_guid The ID of the site (default is current site)
*
- * @param string $token The Token.
- * @param int $site_guid The ID of the site (default is current site)
* @return mixed The user id attached to the token if not expired or false.
*/
function validate_user_token($token, $site_guid) {
@@ -1145,9 +940,11 @@ function validate_user_token($token, $site_guid) {
/**
* Remove user token
*
- * @param string $token
- * @param int $site_guid The ID of the site (default is current site)
+ * @param string $token The toekn
+ * @param int $site_guid The ID of the site (default is current site)
+ *
* @return bool
+ * @since 1.7.0
*/
function remove_user_token($token, $site_guid) {
global $CONFIG;
@@ -1167,6 +964,7 @@ function remove_user_token($token, $site_guid) {
* Remove expired tokens
*
* @return bool
+ * @since 1.7.0
*/
function remove_expired_user_tokens() {
global $CONFIG;
@@ -1179,13 +977,15 @@ function remove_expired_user_tokens() {
where site_guid=$site_guid and expires < $time");
}
-// Client api functions ///////////////////////////////////////////////////////////////////
+// Client api functions
/**
* Utility function to serialise a header array into its text representation.
*
* @param array $headers The array of headers "key" => "value"
+ *
* @return string
+ * @access private
*/
function serialise_api_headers(array $headers) {
$headers_str = "";
@@ -1200,15 +1000,18 @@ function serialise_api_headers(array $headers) {
/**
* Send a raw API call to an elgg api endpoint.
*
- * @param array $keys The api keys.
- * @param string $url URL of the endpoint.
- * @param array $call Associated array of "variable" => "value"
- * @param string $method GET or POST
- * @param string $post_data The post data
+ * @param array $keys The api keys.
+ * @param string $url URL of the endpoint.
+ * @param array $call Associated array of "variable" => "value"
+ * @param string $method GET or POST
+ * @param string $post_data The post data
* @param string $content_type The content type
+ *
* @return string
*/
-function send_api_call(array $keys, $url, array $call, $method = 'GET', $post_data = '', $content_type = 'application/octet-stream') {
+function send_api_call(array $keys, $url, array $call, $method = 'GET', $post_data = '',
+$content_type = 'application/octet-stream') {
+
global $CONFIG;
$headers = array();
@@ -1220,7 +1023,7 @@ function send_api_call(array $keys, $url, array $call, $method = 'GET', $post_da
case 'POST' :
break;
default:
- $msg = sprintf(elgg_echo('NotImplementedException:CallMethodNotImplemented'), $method);
+ $msg = elgg_echo('NotImplementedException:CallMethodNotImplemented', array($method));
throw new NotImplementedException($msg);
}
@@ -1231,8 +1034,8 @@ function send_api_call(array $keys, $url, array $call, $method = 'GET', $post_da
$nonce = uniqid('');
// URL encode all the parameters
- foreach ($call as $k => $v){
- $encoded_params[] = urlencode($k).'='.urlencode($v);
+ foreach ($call as $k => $v) {
+ $encoded_params[] = urlencode($k) . '=' . urlencode($v);
}
$params = implode('&', $encoded_params);
@@ -1292,9 +1095,10 @@ function send_api_call(array $keys, $url, array $call, $method = 'GET', $post_da
/**
* Send a GET call
*
- * @param string $url URL of the endpoint.
- * @param array $call Associated array of "variable" => "value"
- * @param array $keys The keys dependant on chosen authentication method
+ * @param string $url URL of the endpoint.
+ * @param array $call Associated array of "variable" => "value"
+ * @param array $keys The keys dependant on chosen authentication method
+ *
* @return string
*/
function send_api_get_call($url, array $call, array $keys) {
@@ -1304,33 +1108,40 @@ function send_api_get_call($url, array $call, array $keys) {
/**
* Send a GET call
*
- * @param string $url URL of the endpoint.
- * @param array $call Associated array of "variable" => "value"
- * @param array $keys The keys dependant on chosen authentication method
- * @param string $post_data The post data
+ * @param string $url URL of the endpoint.
+ * @param array $call Associated array of "variable" => "value"
+ * @param array $keys The keys dependant on chosen authentication method
+ * @param string $post_data The post data
* @param string $content_type The content type
+ *
* @return string
*/
-function send_api_post_call($url, array $call, array $keys, $post_data, $content_type = 'application/octet-stream') {
+function send_api_post_call($url, array $call, array $keys, $post_data,
+$content_type = 'application/octet-stream') {
+
return send_api_call($keys, $url, $call, 'POST', $post_data, $content_type);
}
/**
- * Return a key array suitable for the API client using the standard authentication method based on api-keys and secret keys.
+ * Return a key array suitable for the API client using the standard
+ * authentication method based on api-keys and secret keys.
*
* @param string $secret_key Your secret key
- * @param string $api_key Your api key
+ * @param string $api_key Your api key
+ *
* @return array
*/
function get_standard_api_key_array($secret_key, $api_key) {
return array('public' => $api_key, 'private' => $secret_key);
}
-// System functions ///////////////////////////////////////////////////////////////////////
+// System functions
/**
* Simple api to return a list of all api's installed on the system.
+ *
* @return array
+ * @access private
*/
function list_all_apis() {
global $API_METHODS;
@@ -1349,11 +1160,24 @@ function list_all_apis() {
*
* @param string $username Username
* @param string $password Clear text password
+ *
* @return string Token string or exception
* @throws SecurityException
+ * @access private
*/
function auth_gettoken($username, $password) {
- if (authenticate($username, $password)) {
+ // check if username is an email address
+ if (is_email_address($username)) {
+ $users = get_user_by_email($username);
+
+ // check if we have a unique user
+ if (is_array($users) && (count($users) == 1)) {
+ $username = $users[0]->username;
+ }
+ }
+
+ // validate username and password
+ if (true === elgg_authenticate($username, $password)) {
$token = create_user_token($username);
if ($token) {
return $token;
@@ -1363,7 +1187,7 @@ function auth_gettoken($username, $password) {
throw new SecurityException(elgg_echo('SecurityException:authenticationfailed'));
}
-// Error handler functions ////////////////////////////////////////////////////////////////
+// Error handler functions
/** Define a global array of errors */
$ERRORS = array();
@@ -1373,22 +1197,28 @@ $ERRORS = array();
* This function acts as a wrapper to catch and report PHP error messages.
*
* @see http://uk3.php.net/set-error-handler
- * @param int $errno
- * @param string $errmsg
- * @param string $filename
- * @param int $linenum
- * @param array $vars
- * @return none
+ *
+ * @param int $errno Error number
+ * @param string $errmsg Human readable message
+ * @param string $filename Filename
+ * @param int $linenum Line number
+ * @param array $vars Vars
+ *
+ * @return void
+ * @access private
+ *
+ * @throws Exception
*/
-function __php_api_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
+function _php_api_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
global $ERRORS;
- $error = date("Y-m-d H:i:s (T)") . ": \"" . $errmsg . "\" in file " . $filename . " (line " . $linenum . ")";
+ $error = date("Y-m-d H:i:s (T)") . ": \"" . $errmsg . "\" in file "
+ . $filename . " (line " . $linenum . ")";
switch ($errno) {
case E_USER_ERROR:
error_log("ERROR: " . $error);
- $ERRORS[] = "ERROR: " .$error;
+ $ERRORS[] = "ERROR: " . $error;
// Since this is a fatal error, we want to stop any further execution but do so gracefully.
throw new Exception("ERROR: " . $error);
@@ -1397,12 +1227,12 @@ function __php_api_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
case E_WARNING :
case E_USER_WARNING :
error_log("WARNING: " . $error);
- $ERRORS[] = "WARNING: " .$error;
+ $ERRORS[] = "WARNING: " . $error;
break;
default:
error_log("DEBUG: " . $error);
- $ERRORS[] = "DEBUG: " .$error;
+ $ERRORS[] = "DEBUG: " . $error;
}
}
@@ -1412,45 +1242,50 @@ function __php_api_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
* uncaught exception, end API execution and return the result to the requestor
* as an ErrorResult in the requested format.
*
- * @param Exception $exception
- * @return none
+ * @param Exception $exception Exception
+ *
+ * @return void
+ * @access private
*/
-function __php_api_exception_handler($exception) {
+function _php_api_exception_handler($exception) {
error_log("*** FATAL EXCEPTION (API) *** : " . $exception);
$code = $exception->getCode() == 0 ? ErrorResult::$RESULT_FAIL : $exception->getCode();
$result = new ErrorResult($exception->getMessage(), $code, NULL);
- page_draw($exception->getMessage(), elgg_view("api/output", array("result" => $result)));
+ echo elgg_view_page($exception->getMessage(), elgg_view("api/output", array("result" => $result)));
}
-// Services handler ///////////////////////////////////////////
+// Services handler
/**
* Services handler - turns request over to the registered handler
* If no handler is found, this returns a 404 error
*
- * @param string $handler
- * @param array $request
+ * @param string $handler Handler name
+ * @param array $request Request string
+ *
+ * @return void
+ * @access private
*/
function service_handler($handler, $request) {
global $CONFIG;
- set_context('api');
+ elgg_set_context('api');
- $request = explode('/',$request);
+ $request = explode('/', $request);
// after the handler, the first identifier is response format
- // ex) http://example.org/services/api/rest/xml/?method=test
- $reponse_format = array_shift($request);
+ // ex) http://example.org/services/api/rest/json/?method=test
+ $response_format = array_shift($request);
// Which view - xml, json, ...
- if ($reponse_format) {
- elgg_set_viewtype($reponse_format);
+ if ($response_format && elgg_is_valid_view_type($response_format)) {
+ elgg_set_viewtype($response_format);
} else {
- // default to xml
- elgg_set_viewtype("xml");
+ // default to json
+ elgg_set_viewtype("json");
}
if (!isset($CONFIG->servicehandler) || empty($handler)) {
@@ -1459,7 +1294,7 @@ function service_handler($handler, $request) {
exit;
} else if (isset($CONFIG->servicehandler[$handler]) && is_callable($CONFIG->servicehandler[$handler])) {
$function = $CONFIG->servicehandler[$handler];
- $function($request, $handler);
+ call_user_func($function, $request, $handler);
} else {
// no handler for this web service
header("HTTP/1.0 404 Not Found");
@@ -1470,16 +1305,19 @@ function service_handler($handler, $request) {
/**
* Registers a web services handler
*
- * @param string $handler web services type
+ * @param string $handler Web services type
* @param string $function Your function name
- * @return true|false Depending on success
+ *
+ * @return bool Depending on success
+ * @since 1.7.0
*/
function register_service_handler($handler, $function) {
global $CONFIG;
+
if (!isset($CONFIG->servicehandler)) {
$CONFIG->servicehandler = array();
}
- if (is_callable($function)) {
+ if (is_callable($function, true)) {
$CONFIG->servicehandler[$handler] = $function;
return true;
}
@@ -1493,32 +1331,90 @@ function register_service_handler($handler, $function) {
* with register_service_handler().
*
* @param string $handler web services type
+ *
+ * @return void
+ * @since 1.7.0
*/
function unregister_service_handler($handler) {
global $CONFIG;
- if (isset($CONFIG->servicehandler) && isset($CONFIG->servicehandler[$handler])) {
+
+ if (isset($CONFIG->servicehandler, $CONFIG->servicehandler[$handler])) {
unset($CONFIG->servicehandler[$handler]);
}
}
-// REST handler //////////////////////////////////////////////////////////////
-
/**
* REST API handler
+ *
+ * @return void
+ * @access private
+ *
+ * @throws SecurityException|APIException
*/
function rest_handler() {
global $CONFIG;
- require $CONFIG->path . "services/api/rest_api.php";
+ // Register the error handler
+ error_reporting(E_ALL);
+ set_error_handler('_php_api_error_handler');
+
+ // Register a default exception handler
+ set_exception_handler('_php_api_exception_handler');
+
+ // Check to see if the api is available
+ if ((isset($CONFIG->disable_api)) && ($CONFIG->disable_api == true)) {
+ throw new SecurityException(elgg_echo('SecurityException:APIAccessDenied'));
+ }
+
+ // plugins should return true to control what API and user authentication handlers are registered
+ if (elgg_trigger_plugin_hook('rest', 'init', null, false) == false) {
+ // for testing from a web browser, you can use the session PAM
+ // do not use for production sites!!
+ //register_pam_handler('pam_auth_session');
+
+ // user token can also be used for user authentication
+ register_pam_handler('pam_auth_usertoken');
+
+ // simple API key check
+ register_pam_handler('api_auth_key', "sufficient", "api");
+ // hmac
+ register_pam_handler('api_auth_hmac', "sufficient", "api");
+ }
+
+ // Get parameter variables
+ $method = get_input('method');
+ $result = null;
+
+ // this will throw an exception if authentication fails
+ authenticate_method($method);
+
+ $result = execute_method($method);
+
+
+ if (!($result instanceof GenericResult)) {
+ throw new APIException(elgg_echo('APIException:ApiResultUnknown'));
+ }
+
+ // Output the result
+ echo elgg_view_page($method, elgg_view("api/output", array("result" => $result)));
}
-// Initialisation /////////////////////////////////////////////////////////////
+// Initialization
/**
* Unit tests for API
+ *
+ * @param string $hook unit_test
+ * @param string $type system
+ * @param mixed $value Array of tests
+ * @param mixed $params Params
+ *
+ * @return array
+ * @access private
*/
function api_unit_test($hook, $type, $value, $params) {
global $CONFIG;
+
$value[] = $CONFIG->path . 'engine/tests/services/api.php';
return $value;
}
@@ -1526,27 +1422,33 @@ function api_unit_test($hook, $type, $value, $params) {
/**
* Initialise the API subsystem.
*
+ * @return void
+ * @access private
*/
function api_init() {
// Register a page handler, so we can have nice URLs
- register_service_handler('rest','rest_handler');
+ register_service_handler('rest', 'rest_handler');
- register_plugin_hook('unit_test', 'system', 'api_unit_test');
+ elgg_register_plugin_hook_handler('unit_test', 'system', 'api_unit_test');
// expose the list of api methods
- expose_function("system.api.list", "list_all_apis", NULL, elgg_echo("system.api.list"), "GET", false, false);
+ expose_function("system.api.list", "list_all_apis", NULL,
+ elgg_echo("system.api.list"), "GET", false, false);
// The authentication token api
- expose_function("auth.gettoken",
- "auth_gettoken", array(
- 'username' => array ('type' => 'string'),
- 'password' => array ('type' => 'string'),
- ),
- elgg_echo('auth.gettoken'),
- 'POST',
- false,
- false);
+ expose_function(
+ "auth.gettoken",
+ "auth_gettoken",
+ array(
+ 'username' => array ('type' => 'string'),
+ 'password' => array ('type' => 'string'),
+ ),
+ elgg_echo('auth.gettoken'),
+ 'POST',
+ false,
+ false
+ );
}
-register_elgg_event_handler('init','system','api_init');
+elgg_register_event_handler('init', 'system', 'api_init');
diff --git a/engine/lib/widgets.php b/engine/lib/widgets.php
index 7884f263a..699462a1b 100644
--- a/engine/lib/widgets.php
+++ b/engine/lib/widgets.php
@@ -3,290 +3,178 @@
* Elgg widgets library.
* Contains code for handling widgets.
*
- * @package Elgg
- * @subpackage Core
- * @link http://elgg.org/
+ * @package Elgg.Core
+ * @subpackage Widgets
*/
/**
- * Override ElggObject in order to store widget data in ultra-private stores.
+ * Get widgets for a particular context
+ *
+ * The widgets are ordered for display and grouped in columns.
+ * $widgets = elgg_get_widgets(elgg_get_logged_in_user_guid(), 'dashboard');
+ * $first_column_widgets = $widgets[1];
+ *
+ * @param int $user_guid The owner user GUID
+ * @param string $context The context (profile, dashboard, etc)
+ *
+ * @return array An 2D array of ElggWidget objects
+ * @since 1.8.0
*/
-class ElggWidget extends ElggObject {
- protected function initialise_attributes() {
- parent::initialise_attributes();
-
- $this->attributes['subtype'] = "widget";
- }
-
- public function __construct($guid = null) {
- parent::__construct($guid);
+function elgg_get_widgets($user_guid, $context) {
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'widget',
+ 'owner_guid' => $user_guid,
+ 'private_setting_name' => 'context',
+ 'private_setting_value' => $context,
+ 'limit' => 0
+ );
+ $widgets = elgg_get_entities_from_private_settings($options);
+ if (!$widgets) {
+ return array();
}
- /**
- * Override entity get and sets in order to save data to private data store.
- */
- 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 private data store.
- $meta = get_private_setting($this->guid, $name);
- if ($meta) {
- return $meta;
+ $sorted_widgets = array();
+ foreach ($widgets as $widget) {
+ if (!isset($sorted_widgets[(int)$widget->column])) {
+ $sorted_widgets[(int)$widget->column] = array();
}
-
- // Can't find it, so return null
- return null;
+ $sorted_widgets[(int)$widget->column][$widget->order] = $widget;
}
- /**
- * Override entity get and sets in order to save data to private data store.
- */
- 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;
- }
-
- $this->attributes[$name] = $value;
- } else {
- return set_private_setting($this->guid, $name, $value);
- }
-
- return true;
+ foreach ($sorted_widgets as $col => $widgets) {
+ ksort($sorted_widgets[$col]);
}
+
+ return $sorted_widgets;
}
/**
- * Register a particular context for use with widgets.
+ * Create a new widget instance
*
- * @param string $context The context we wish to enable context for
+ * @param int $owner_guid GUID of entity that owns this widget
+ * @param string $handler The handler for this widget
+ * @param string $context The context for this widget
+ * @param int $access_id If not specified, it is set to the default access level
+ *
+ * @return int|false Widget GUID or false on failure
+ * @since 1.8.0
*/
-function use_widgets($context) {
- global $CONFIG;
-
- if (!isset($CONFIG->widgets)) {
- $CONFIG->widgets = new stdClass;
+function elgg_create_widget($owner_guid, $handler, $context, $access_id = null) {
+ if (empty($owner_guid) || empty($handler) || !elgg_is_widget_type($handler)) {
+ return false;
}
- if (!isset($CONFIG->widgets->contexts)) {
- $CONFIG->widgets->contexts = array();
+ $owner = get_entity($owner_guid);
+ if (!$owner) {
+ return false;
}
- if (!empty($context)) {
- $CONFIG->widgets->contexts[] = $context;
+ $widget = new ElggWidget;
+ $widget->owner_guid = $owner_guid;
+ $widget->container_guid = $owner_guid; // @todo - will this work for group widgets
+ if (isset($access_id)) {
+ $widget->access_id = $access_id;
+ } else {
+ $widget->access_id = get_default_access();
}
-}
-/**
- * Determines whether or not the current context is using widgets
- *
- * @return true|false Depending on widget status
- */
-function using_widgets() {
- global $CONFIG;
-
- $context = get_context();
- if (isset($CONFIG->widgets->contexts) && is_array($CONFIG->widgets->contexts)) {
- if (in_array($context, $CONFIG->widgets->contexts)) return true;
+ if (!$widget->save()) {
+ return false;
}
- return false;
+ // private settings cannot be set until ElggWidget saved
+ $widget->handler = $handler;
+ $widget->context = $context;
+
+ return $widget->getGUID();
}
/**
- * When given a widget entity and a new requested location, saves the new location
- * and also provides a sensible ordering for all widgets in that column
+ * Can the user edit the widget layout
*
- * @param ElggObject $widget The widget entity
- * @param int $order The order within the column
- * @param int $column The column (1, 2 or 3)
- * @return true|false Depending on success
+ * Triggers a 'permissions_check', 'widget_layout' plugin hook
+ *
+ * @param string $context The widget context
+ * @param int $user_guid The GUID of the user (0 for logged in user)
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function save_widget_location(ElggObject $widget, $order, $column) {
- if ($widget instanceof ElggObject) {
- if ($widget->subtype == "widget") {
- // If you can't move the widget, don't save a new location
- if (!$widget->draggable) {
- return false;
- }
-
- // Sanitise the column value
- if ($column != 1 || $column != 2 || $column != 3) {
- $column = 1;
- }
-
- $widget->column = (int) $column;
-
- $ordertmp = array();
- $params = array(
- 'context' => $widget->context,
- 'column' => $column,
- );
-
- if ($entities = get_entities_from_metadata_multi($params,'object','widget')) {
- foreach($entities as $entity) {
- $entityorder = $entity->order;
- if ($entityorder < $order) {
- $ordertmp[$entityorder] = $entity;
- }
- if ($entityorder >= $order) {
- $ordertmp[$entityorder + 10000] = $entity;
- }
- }
- }
-
- $ordertmp[$order] = $widget;
- ksort($ordertmp);
-
- $orderticker = 10;
- foreach($ordertmp as $orderval => $entity) {
- $entity->order = $orderticker;
- $orderticker += 10;
- }
-
- return true;
- } else {
- register_error($widget->subtype);
- }
+function elgg_can_edit_widget_layout($context, $user_guid = 0) {
+ $user = get_entity((int)$user_guid);
+ if (!$user) {
+ $user = elgg_get_logged_in_user_entity();
}
- return false;
-}
+ $return = false;
+ if (elgg_is_admin_logged_in()) {
+ $return = true;
+ }
+ if (elgg_get_page_owner_guid() == $user->guid) {
+ $return = true;
+ }
-/**
- * Get widgets for a particular context and column, in order of display
- *
- * @param int $user_guid The owner user GUID
- * @param string $context The context (profile, dashboard etc)
- * @param int $column The column (1 or 2)
- * @return array|false An array of widget ElggObjects, or false
- */
-function get_widgets($user_guid, $context, $column) {
$params = array(
- 'column' => $column,
- 'context' => $context
+ 'user' => $user,
+ 'context' => $context,
+ 'page_owner' => elgg_get_page_owner_entity()
);
- $widgets = get_entities_from_private_setting_multi($params, "object", "widget", $user_guid, "", 10000);
- if ($widgets) {
- $widgetorder = array();
- foreach($widgets as $widget) {
- $order = $widget->order;
- while(isset($widgetorder[$order])) {
- $order++;
- }
- $widgetorder[$order] = $widget;
- }
-
- ksort($widgetorder);
-
- return $widgetorder;
- }
-
- return false;
+ return elgg_trigger_plugin_hook('permissions_check', 'widget_layout', $params, $return);
}
/**
- * Displays a particular widget
+ * Regsiter a widget type
*
- * @param ElggObject $widget The widget to display
- * @return string The HTML for the widget, including JavaScript wrapper
- */
-function display_widget(ElggObject $widget) {
- return elgg_view_entity($widget);
-}
-
-/**
- * Add a new widget
+ * This should be called by plugins in their init function.
*
- * @param int $user_guid User GUID to associate this widget with
- * @param string $handler The handler for this widget
- * @param string $context The page context for this widget
- * @param int $order The order to display this widget in
- * @param int $column The column to display this widget in (1, 2 or 3)
- * @param int $access_id If not specified, it is set to the default access level
- * @return true|false Depending on success
+ * @param string $handler The identifier for the widget handler
+ * @param string $name The name of the widget type
+ * @param string $description A description for the widget type
+ * @param string $context A comma-separated list of contexts where this
+ * widget is allowed (default: 'all')
+ * @param bool $multiple Whether or not multiple instances of this widget
+ * are allowed in a single layout (default: false)
+ *
+ * @return bool
+ * @since 1.8.0
*/
-function add_widget($user_guid, $handler, $context, $order = 0, $column = 1, $access_id = null) {
- if (empty($user_guid) || empty($context) || empty($handler) || !widget_type_exists($handler)) {
+function elgg_register_widget_type($handler, $name, $description, $context = "all", $multiple = false) {
+
+ if (!$handler || !$name) {
return false;
}
- if ($user = get_user($user_guid)) {
- $widget = new ElggWidget;
- $widget->owner_guid = $user_guid;
- $widget->container_guid = $user_guid;
- if (isset($access_id)) {
- $widget->access_id = $access_id;
- } else {
- $widget->access_id = get_default_access();
- }
-
- if (!$widget->save()) {
- return false;
- }
-
- $widget->handler = $handler;
- $widget->context = $context;
- $widget->column = $column;
- $widget->order = $order;
-
- // save_widget_location($widget, $order, $column);
- return true;
+ global $CONFIG;
+ if (!isset($CONFIG->widgets)) {
+ $CONFIG->widgets = new stdClass;
+ }
+ if (!isset($CONFIG->widgets->handlers)) {
+ $CONFIG->widgets->handlers = array();
}
- return false;
-}
-
-/**
- * Define a new widget type
- *
- * @param string $handler The identifier for the widget handler
- * @param string $name The name of the widget type
- * @param string $description A description for the widget type
- * @param string $context A comma-separated list of contexts where this widget is allowed (default: 'all')
- * @param true|false $multiple Whether or not multiple instances of this widget are allowed on a single dashboard (default: false)
- * @param string $position A comma-separated list of positions on the page (side or main) where this widget is allowed (default: "side,main")
- * @return true|false Depending on success
- */
-function add_widget_type($handler, $name, $description, $context = "all", $multiple = false, $positions = "side,main") {
- if (!empty($handler) && !empty($name)) {
- global $CONFIG;
-
- if (!isset($CONFIG->widgets)) {
- $CONFIG->widgets = new stdClass;
- }
-
- if (!isset($CONFIG->widgets->handlers)) {
- $CONFIG->widgets->handlers = array();
- }
-
- $handlerobj = new stdClass;
- $handlerobj->name = $name;
- $handlerobj->description = $description;
- $handlerobj->context = explode(",",$context);
- $handlerobj->multiple = $multiple;
- $handlerobj->positions = explode(",",$positions);
-
- $CONFIG->widgets->handlers[$handler] = $handlerobj;
+ $handlerobj = new stdClass;
+ $handlerobj->name = $name;
+ $handlerobj->description = $description;
+ $handlerobj->context = explode(",", $context);
+ $handlerobj->multiple = $multiple;
- return true;
- }
+ $CONFIG->widgets->handlers[$handler] = $handlerobj;
- return false;
+ return true;
}
/**
* Remove a widget type
*
- * @param string $handler The identifier for the widget handler
+ * @param string $handler The identifier for the widget
+ *
+ * @return void
+ * @since 1.8.0
*/
-function remove_widget_type($handler) {
+function elgg_unregister_widget_type($handler) {
global $CONFIG;
if (!isset($CONFIG->widgets)) {
@@ -303,224 +191,230 @@ function remove_widget_type($handler) {
}
/**
- * Determines whether or not widgets with the specified handler have been defined
+ * Has a widget type with the specified handler been registered
*
* @param string $handler The widget handler identifying string
- * @return true|false Whether or not those widgets exist
+ *
+ * @return bool Whether or not that widget type exists
+ * @since 1.8.0
*/
-function widget_type_exists($handler) {
+function elgg_is_widget_type($handler) {
global $CONFIG;
- if (!empty($CONFIG->widgets)
- && !empty($CONFIG->widgets->handlers)
- && is_array($CONFIG->widgets->handlers)
- && array_key_exists($handler, $CONFIG->widgets->handlers)) {
- return true;
+ if (!empty($CONFIG->widgets) &&
+ !empty($CONFIG->widgets->handlers) &&
+ is_array($CONFIG->widgets->handlers) &&
+ array_key_exists($handler, $CONFIG->widgets->handlers)) {
+
+ return true;
}
return false;
}
/**
- * Returns an array of stdClass objects representing the defined widget types
+ * Get the widget types for a context
*
- * @return array A list of types defined (if any)
+ * The widget types are stdClass objects.
+ *
+ * @param string $context The widget context or empty string for current context
+ * @param bool $exact Only return widgets registered for this context (false)
+ *
+ * @return array
+ * @since 1.8.0
*/
-function get_widget_types() {
+function elgg_get_widget_types($context = "", $exact = false) {
global $CONFIG;
- if (!empty($CONFIG->widgets)
- && !empty($CONFIG->widgets->handlers)
- && is_array($CONFIG->widgets->handlers)) {
+ if (empty($CONFIG->widgets) ||
+ empty($CONFIG->widgets->handlers) ||
+ !is_array($CONFIG->widgets->handlers)) {
+ // no widgets
+ return array();
+ }
- $context = get_context();
+ if (!$context) {
+ $context = elgg_get_context();
+ }
- foreach($CONFIG->widgets->handlers as $key => $handler) {
- if (!in_array('all',$handler->context) &&
- !in_array($context,$handler->context)) {
- unset($CONFIG->widgets->handlers[$key]);
- }
+ $widgets = array();
+ foreach ($CONFIG->widgets->handlers as $key => $handler) {
+ if ($exact) {
+ if (in_array($context, $handler->context)) {
+ $widgets[$key] = $handler;
+ }
+ } else {
+ if (in_array('all', $handler->context) || in_array($context, $handler->context)) {
+ $widgets[$key] = $handler;
}
-
- return $CONFIG->widgets->handlers;
}
+ }
- return array();
+ return $widgets;
}
/**
- * Saves a widget's settings (by passing an array of (name => value) pairs to save_{$handler}_widget)
+ * Regsiter entity of object, widget as ElggWidget objects
*
- * @param int $widget_guid The GUID of the widget we're saving to
- * @param array $params An array of name => value parameters
+ * @return void
+ * @access private
*/
-function save_widget_info($widget_guid, $params) {
- if ($widget = get_entity($widget_guid)) {
-
- $subtype = $widget->getSubtype();
-
- if ($subtype != "widget") {
- return false;
- }
- $handler = $widget->handler;
- if (empty($handler) || !widget_type_exists($handler)) {
- return false;
- }
-
- if (!$widget->canEdit()) {
- return false;
- }
-
- // Save the params to the widget
- if (is_array($params) && sizeof($params) > 0) {
- foreach($params as $name => $value) {
-
- if (!empty($name) && !in_array($name, array(
- 'guid','owner_guid','site_guid'
- ))) {
- if (is_array($value)) {
- // TODO: Handle arrays securely
- $widget->setMetaData($name, $value, "", true);
- } else {
- $widget->$name = $value;
- }
- }
- }
- $widget->save();
- }
-
- $function = "save_{$handler}_widget";
- if (is_callable($function)) {
- return $function($params);
- }
-
- return true;
- }
-
- return false;
+function elgg_widget_run_once() {
+ add_subtype("object", "widget", "ElggWidget");
}
-function reorder_widgets_from_panel($panelstring1, $panelstring2, $panelstring3, $context, $owner) {
- $return = true;
+/**
+ * Function to initialize widgets functionality
+ *
+ * @return void
+ * @access private
+ */
+function elgg_widgets_init() {
+ elgg_register_action('widgets/save');
+ elgg_register_action('widgets/add');
+ elgg_register_action('widgets/move');
+ elgg_register_action('widgets/delete');
+ elgg_register_action('widgets/upgrade', '', 'admin');
+
+ run_function_once("elgg_widget_run_once");
+}
- $mainwidgets = explode('::',$panelstring1);
- $sidewidgets = explode('::',$panelstring2);
- $rightwidgets = explode('::',$panelstring3);
+/**
+ * Gets a list of events to create default widgets for and
+ * register menu items for default widgets with the admin section.
+ *
+ * A plugin that wants to register a new context for default widgets should
+ * register for the plugin hook 'get_list', 'default_widgets'. The handler
+ * can register the new type of default widgets by adding an associate array to
+ * the return value array like this:
+ * array(
+ * 'name' => elgg_echo('profile'),
+ * 'widget_context' => 'profile',
+ * 'widget_columns' => 3,
+ *
+ * 'event' => 'create',
+ * 'entity_type' => 'user',
+ * 'entity_subtype' => ELGG_ENTITIES_ANY_VALUE,
+ * );
+ *
+ * The first set of keys define information about the new type of default
+ * widgets and the second set determine what event triggers the creation of the
+ * new widgets.
+ *
+ * @return void
+ * @access private
+ */
+function elgg_default_widgets_init() {
+ global $CONFIG;
+ $default_widgets = elgg_trigger_plugin_hook('get_list', 'default_widgets', null, array());
- $handlers = array();
- $guids = array();
+ $CONFIG->default_widget_info = $default_widgets;
- if (is_array($mainwidgets) && sizeof($mainwidgets) > 0) {
- foreach($mainwidgets as $widget) {
+ if ($default_widgets) {
+ elgg_register_admin_menu_item('configure', 'default_widgets', 'appearance');
- $guid = (int) $widget;
+ // override permissions for creating widget on logged out / just created entities
+ elgg_register_plugin_hook_handler('container_permissions_check', 'object', 'elgg_default_widgets_permissions_override');
- if ("{$guid}" == "{$widget}") {
- $guids[1][] = $widget;
- } else {
- $handlers[1][] = $widget;
- }
+ // only register the callback once per event
+ $events = array();
+ foreach ($default_widgets as $info) {
+ $events[$info['event'] . ',' . $info['entity_type']] = $info;
}
- }
- if (is_array($sidewidgets) && sizeof($sidewidgets) > 0) {
- foreach($sidewidgets as $widget) {
-
- $guid = (int) $widget;
-
- if ("{$guid}" == "{$widget}") {
- $guids[2][] = $widget;
- } else {
- $handlers[2][] = $widget;
- }
-
+ foreach ($events as $info) {
+ elgg_register_event_handler($info['event'], $info['entity_type'], 'elgg_create_default_widgets');
}
}
- if (is_array($rightwidgets) && sizeof($rightwidgets) > 0) {
- foreach($rightwidgets as $widget) {
-
- $guid = (int) $widget;
+}
- if ("{$guid}" == "{$widget}") {
- $guids[3][] = $widget;
- } else {
- $handlers[3][] = $widget;
- }
+/**
+ * Creates default widgets
+ *
+ * This plugin hook handler is registered for events based on what kinds of
+ * default widgets have been registered. See elgg_default_widgets_init() for
+ * information on registering new default widget contexts.
+ *
+ * @param string $event The event
+ * @param string $type The type of object
+ * @param ElggEntity $entity The entity being created
+ * @return void
+ * @access private
+ */
+function elgg_create_default_widgets($event, $type, $entity) {
+ $default_widget_info = elgg_get_config('default_widget_info');
- }
+ if (!$default_widget_info || !$entity) {
+ return;
}
- // Reorder existing widgets or delete ones that have vanished
- foreach (array(1,2,3) as $column) {
- if ($dbwidgets = get_widgets($owner,$context,$column)) {
-
- foreach($dbwidgets as $dbwidget) {
- if (in_array($dbwidget->getGUID(),$guids[1]) || in_array($dbwidget->getGUID(),$guids[2]) || in_array($dbwidget->getGUID(),$guids[3])) {
- if (in_array($dbwidget->getGUID(),$guids[1])) {
- $pos = array_search($dbwidget->getGUID(),$guids[1]);
- $col = 1;
- } else if (in_array($dbwidget->getGUID(),$guids[2])) {
- $pos = array_search($dbwidget->getGUID(),$guids[2]);
- $col = 2;
- } else {
- $pos = array_search($dbwidget->getGUID(),$guids[3]);
- $col = 3;
+ $type = $entity->getType();
+ $subtype = $entity->getSubtype();
+
+ // event is already guaranteed by the hook registration.
+ // need to check subtype and type.
+ foreach ($default_widget_info as $info) {
+ if ($info['entity_type'] == $type) {
+ if ($info['entity_subtype'] == ELGG_ENTITIES_ANY_VALUE || $info['entity_subtype'] == $subtype) {
+
+ // need to be able to access everything
+ $old_ia = elgg_set_ignore_access(true);
+ elgg_push_context('create_default_widgets');
+
+ // pull in by widget context with widget owners as the site
+ // not using elgg_get_widgets() because it sorts by columns and we don't care right now.
+ $options = array(
+ 'type' => 'object',
+ 'subtype' => 'widget',
+ 'owner_guid' => elgg_get_site_entity()->guid,
+ 'private_setting_name' => 'context',
+ 'private_setting_value' => $info['widget_context'],
+ 'limit' => 0
+ );
+
+ $widgets = elgg_get_entities_from_private_settings($options);
+ /* @var ElggWidget[] $widgets */
+
+ foreach ($widgets as $widget) {
+ // change the container and owner
+ $new_widget = clone $widget;
+ $new_widget->container_guid = $entity->guid;
+ $new_widget->owner_guid = $entity->guid;
+
+ // pull in settings
+ $settings = get_all_private_settings($widget->guid);
+
+ foreach ($settings as $name => $value) {
+ $new_widget->$name = $value;
}
- $pos = ($pos + 1) * 10;
- $dbwidget->column = $col;
- $dbwidget->order = $pos;
- } else {
- $dbguid = $dbwidget->getGUID();
- if (!$dbwidget->delete()) {
- $return = false;
- } else {
- // Remove state cookie
- setcookie('widget' + $dbguid, null);
- }
- }
- }
- }
- // Add new ones
- if (sizeof($guids[$column]) > 0) {
- foreach($guids[$column] as $key => $guid) {
- if ($guid == 0) {
- $pos = ($key + 1) * 10;
- $handler = $handlers[$column][$key];
- if (!add_widget($owner,$handler,$context,$pos,$column)) {
- $return = false;
- }
+ $new_widget->save();
}
+
+ elgg_set_ignore_access($old_ia);
+ elgg_pop_context();
}
}
}
-
- return $return;
-}
-
-/**
- * Run some things once.
- *
- */
-function widget_run_once() {
- // Register a class
- add_subtype("object", "widget", "ElggWidget");
}
/**
- * Function to initialise widgets functionality on Elgg init
+ * Overrides permissions checks when creating widgets for logged out users.
*
+ * @param string $hook The permissions hook.
+ * @param string $type The type of entity being created.
+ * @param string $return Value
+ * @param mixed $params Params
+ * @return true|null
+ * @access private
*/
-function widgets_init() {
- register_action('widgets/reorder');
- register_action('widgets/save');
- register_action('widgets/add');
+function elgg_default_widgets_permissions_override($hook, $type, $return, $params) {
+ if ($type == 'object' && $params['subtype'] == 'widget') {
+ return elgg_in_context('create_default_widgets') ? true : null;
+ }
- // Now run this stuff, but only once
- run_function_once("widget_run_once");
+ return null;
}
-// Register event
-register_elgg_event_handler('init','system','widgets_init');
-
-// Use widgets on the dashboard
-use_widgets('dashboard'); \ No newline at end of file
+elgg_register_event_handler('init', 'system', 'elgg_widgets_init');
+// register default widget hooks from plugins
+elgg_register_event_handler('ready', 'system', 'elgg_default_widgets_init');
diff --git a/engine/lib/xml-rpc.php b/engine/lib/xml-rpc.php
index 7c369edc1..bfe1a8645 100644
--- a/engine/lib/xml-rpc.php
+++ b/engine/lib/xml-rpc.php
@@ -1,557 +1,203 @@
<?php
- /**
- * Elgg XML-RPC library.
- * Contains functions and classes to handle XML-RPC services, currently only server only.
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
- */
-
- // XMLRPC Call ////////////////////////////////////////////////////////////////////////////
-
- /**
- * @class XMLRPCCall
- * This class represents
- * @author Curverider Ltd
- */
- class XMLRPCCall
- {
- /** Method name */
- private $methodname;
- /** Parameters */
- private $params;
-
- /**
- * Construct a new XML RPC Call
- *
- * @param string $xml
- */
- function __construct($xml)
- {
- $this->parse($xml);
- }
-
- /**
- * Return the method name associated with the call.
- *
- * @return string
- */
- public function getMethodName() { return $this->methodname; }
-
- /**
- * Return the parameters.
- * Returns a nested array of XmlElement.
- *
- * @see XmlElement
- * @return array
- */
- public function getParameters() { return $this->params; }
-
- /**
- * Parse the xml into its components according to spec.
- * This first version is a little primitive.
- *
- * @param string $xml
- */
- private function parse($xml)
- {
- $xml = xml_to_object($xml);
-
- // sanity check
- if ((isset($xml->name)) && (strcasecmp($xml->name, "methodCall")!=0))
- throw new CallException(elgg_echo('CallException:NotRPCCall'));
-
- // method name
- $this->methodname = $xml->children[0]->content;
-
- // parameters
- $this->params = $xml->children[1]->children;
- }
- }
-
- // Response classes ///////////////////////////////////////////////////////////////////////
-
- /**
- * @class XMLRPCParameter Superclass for all RPC parameters.
- * @author Curverider Ltd
- */
- abstract class XMLRPCParameter
- {
- protected $value;
-
- function __construct() { }
-
- }
-
- /**
- * @class XMLRPCIntParameter An Integer.
- * @author Curverider Ltd
- */
- class XMLRPCIntParameter extends XMLRPCParameter
- {
- function __construct($value)
- {
- parent::__construct();
-
- $this->value = (int)$value;
- }
-
- function __toString()
- {
- return "<value><i4>{$this->value}</i4></value>";
- }
- }
-
- /**
- * @class XMLRPCBoolParameter A boolean.
- * @author Curverider Ltd
- */
- class XMLRPCBoolParameter extends XMLRPCParameter
- {
- function __construct($value)
- {
- parent::__construct();
-
- $this->value = (bool)$value;
- }
-
- function __toString()
- {
- $code = ($this->value) ? "1" : "0";
- return "<value><boolean>{$code}</boolean></value>";
- }
- }
-
- /**
- * @class XMLRPCStringParameter A string.
- * @author Curverider Ltd
- */
- class XMLRPCStringParameter extends XMLRPCParameter
- {
- function __construct($value)
- {
- parent::__construct();
-
- $this->value = $value;
- }
-
- function __toString()
- {
- $value = htmlentities($this->value);
- return "<value><string>{$value}</string></value>";
- }
- }
-
- /**
- * @class XMLRPCDoubleParameter A double precision signed floating point number.
- * @author Curverider Ltd
- */
- class XMLRPCDoubleParameter extends XMLRPCParameter
- {
- function __construct($value)
- {
- parent::__construct();
-
- $this->value = (float)$value;
- }
-
- function __toString()
- {
- return "<value><double>{$this->value}</double></value>";
- }
- }
-
- /**
- * @class XMLRPCDateParameter An ISO8601 data and time.
- * @author Curverider Ltd
- */
- class XMLRPCDateParameter extends XMLRPCParameter
- {
- /**
- * Construct a date
- *
- * @param int $timestamp The unix timestamp, or blank for "now".
- */
- function __construct($timestamp = 0)
- {
- parent::__construct();
-
- $this->value = $timestamp;
- if (!$timestamp)
- $this->value = time();
- }
-
- function __toString()
- {
- $value = date('c', $this->value);
- return "<value><dateTime.iso8601>{$value}</dateTime.iso8601></value>";
- }
- }
-
- /**
- * @class XMLRPCBase64Parameter A base 64 encoded blob of binary.
- * @author Curverider Ltd
- */
- class XMLRPCBase64Parameter extends XMLRPCParameter
- {
- /**
- * Construct a base64 encoded block
- *
- * @param string $blob Unencoded binary blob
- */
- function __construct($blob)
- {
- parent::__construct();
-
- $this->value = base64_encode($blob);
- }
-
- function __toString()
- {
- return "<value><base64>{$value}</base64></value>";
- }
+/**
+ * Elgg XML-RPC library.
+ * Contains functions and classes to handle XML-RPC services, currently only server only.
+ *
+ * @package Elgg.Core
+ * @subpackage XMLRPC
+ */
+
+/**
+ * parse XMLRPCCall parameters
+ *
+ * Convert an XMLRPCCall result array into native data types
+ *
+ * @param array $parameters An array of params
+ *
+ * @return array
+ * @access private
+ */
+function xmlrpc_parse_params($parameters) {
+ $result = array();
+
+ foreach ($parameters as $parameter) {
+ $result[] = xmlrpc_scalar_value($parameter);
}
-
- /**
- * @class XMLRPCStructParameter A structure containing other XMLRPCParameter objects.
- * @author Curverider Ltd
- */
- class XMLRPCStructParameter extends XMLRPCParameter
- {
- /**
- * Construct a struct.
- *
- * @param array $parameters Optional associated array of parameters, if not provided then addField must be used.
- */
- function __construct($parameters = NULL)
- {
- parent::__construct();
-
- if (is_array($parameters))
- {
- foreach ($parameters as $k => $v)
- $this->addField($k, $v);
- }
- }
-
- /**
- * Add a field to the container.
- *
- * @param string $name The name of the field.
- * @param XMLRPCParameter $value The value.
- */
- public function addField($name, XMLRPCParameter $value)
- {
- if (!is_array($this->value))
- $this->value = array();
-
- $this->value[$name] = $value;
- }
-
- function __toString()
- {
- $params = "";
- foreach ($this->value as $k => $v)
- {
- $params .= "<member><name>$k</name>$v</member>";
- }
-
- return "<value><struct>$params</struct></value>";
- }
+
+ return $result;
+}
+
+/**
+ * Extract the scalar value of an XMLObject type result array
+ *
+ * @param XMLObject $object And object
+ *
+ * @return mixed
+ * @access private
+ */
+function xmlrpc_scalar_value($object) {
+ if ($object->name == 'param') {
+ $object = $object->children[0]->children[0];
}
-
- /**
- * @class XMLRPCArrayParameter An array containing other XMLRPCParameter objects.
- * @author Curverider Ltd
- */
- class XMLRPCArrayParameter extends XMLRPCParameter
- {
- /**
- * Construct an array.
- *
- * @param array $parameters Optional array of parameters, if not provided then addField must be used.
- */
- function __construct($parameters = NULL)
- {
- parent::__construct();
-
- if (is_array($parameters))
- {
- foreach ($parameters as $v)
- $this->addField($v);
+
+ switch ($object->name) {
+ case 'string':
+ return $object->content;
+
+ case 'array':
+ foreach ($object->children[0]->children as $child) {
+ $value[] = xmlrpc_scalar_value($child);
}
- }
-
- /**
- * Add a field to the container.
- *
- * @param XMLRPCParameter $value The value.
- */
- public function addField(XMLRPCParameter $value)
- {
- if (!is_array($this->value))
- $this->value = array();
-
- $this->value[] = $value;
- }
-
- function __toString()
- {
- $params = "";
- foreach ($this->value as $value)
- {
- $params .= "$value";
+ return $value;
+
+ case 'struct':
+ foreach ($object->children as $child) {
+ if (isset($child->children[1]->children[0])) {
+ $value[$child->children[0]->content] = xmlrpc_scalar_value($child->children[1]->children[0]);
+ } else {
+ $value[$child->children[0]->content] = $child->children[1]->content;
+ }
}
-
- return "<array><data>$params</data></array>";
- }
- }
-
- /**
- * @class XMLRPCResponse XML-RPC Response.
- * @author Curverider Ltd
- */
- abstract class XMLRPCResponse
- {
- /** An array of parameters */
- protected $parameters = array();
-
- /**
- * Add a parameter here.
- *
- * @param XMLRPCParameter $param The parameter.
- */
- public function addParameter(XMLRPCParameter $param)
- {
- if (!is_array($this->parameters))
- $this->parameters = array();
-
- $this->parameters[] = $param;
- }
+ return $value;
- public function addInt($value) { $this->addParameter(new XMLRPCIntParameter($value)); }
- public function addString($value) { $this->addParameter(new XMLRPCStringParameter($value)); }
- public function addDouble($value) { $this->addParameter(new XMLRPCDoubleParameter($value)); }
- public function addBoolean($value) { $this->addParameter(new XMLRPCBoolParameter($value)); }
- }
+ case 'boolean':
+ return (boolean) $object->content;
- /**
- * @class XMLRPCSuccessResponse
- * @author Curverider Ltd
- */
- class XMLRPCSuccessResponse extends XMLRPCResponse
- {
- /**
- * Output to XML.
- */
- public function __toString()
- {
- $params = "";
- foreach ($this->parameters as $param)
- $params .= "<param>$param</param>\n";
-
- return "<methodResponse><params>$params</params></methodResponse>";
- }
- }
+ case 'i4':
+ case 'int':
+ return (int) $object->content;
- /**
- * @class XMLRPCErrorResponse
- * @author Curverider Ltd
- */
- class XMLRPCErrorResponse extends XMLRPCResponse
- {
- /**
- * Set the error response and error code.
- *
- * @param string $message The message
- * @param int $code Error code (default = system error as defined by http://xmlrpc-epi.sourceforge.net/specs/rfc.fault_codes.php)
- */
- function __construct($message, $code = -32400)
- {
- $this->addParameter(
- new XMLRPCStructParameter(
- array (
- 'faultCode' => new XMLRPCIntParameter($code),
- 'faultString' => new XMLRPCStringParameter($message)
- )
- )
- );
- }
-
- /**
- * Output to XML.
- */
- public function __toString()
- {
- return "<methodResponse><fault><value>{$this->parameters[0]}</value></fault></methodResponse>";
- }
- }
-
-
- // Helper functions ///////////////////////////////////////////////////////////////////////
-
- /**
- * parse XMLRPCCall parameters
- *
- * Convert an XMLRPCCall result array into native data types
- *
- * @param array $parameters
- * @return array
- */
- function xmlrpc_parse_params($parameters)
- {
- $result = array();
-
- foreach ($parameters as $parameter)
- {
- $result[] = xmlrpc_scalar_value($parameter);
- }
-
- return $result;
- }
+ case 'double':
+ return (double) $object->content;
- /**
- * Extract the scalar value of an XMLObject type result array
- *
- * @param XMLObject $object
- * @return mixed
- */
- function xmlrpc_scalar_value($object)
- {
- if ($object->name == 'param')
- {
- $object = $object->children[0]->children[0];
- }
-
- switch ($object->name)
- {
- case 'string':
- return $object->content;
- case 'array':
- foreach ($object->children[0]->children as $child)
- {
- $value[] = xmlrpc_scalar_value($child);
- }
- return $value;
- case 'struct':
- foreach ($object->children as $child)
- {
- if (isset($child->children[1]->children[0]))
- $value[$child->children[0]->content] = xmlrpc_scalar_value($child->children[1]->children[0]);
- else
- $value[$child->children[0]->content] = $child->children[1]->content;
- }
- return $value;
- case 'boolean':
- return (boolean) $object->content;
- case 'i4':
- case 'int':
- return (int) $object->content;
- case 'double':
- return (double) $object->content;
- case 'dateTime.iso8601':
- return (int) strtotime($object->content);
- case 'base64':
- return base64_decode($object->content);
- case 'value':
- return xmlrpc_scalar_value($object->children[0]);
- default:
- // TODO unsupported, throw an error
- return false;
- }
- }
-
- // Functions for adding handlers //////////////////////////////////////////////////////////
-
- /** XML-RPC Handlers */
- $XML_RPC_HANDLERS = array();
-
- /**
- * Register a method handler for a given XML-RPC method.
- *
- * @param string $method Method parameter.
- * @param string $handler The handler function. This function accepts once XMLRPCCall object and must return a XMLRPCResponse object.
- * @return bool
- */
- function register_xmlrpc_handler($method, $handler)
- {
- global $XML_RPC_HANDLERS;
-
- $XML_RPC_HANDLERS[$method] = $handler;
+ case 'dateTime.iso8601':
+ return (int) strtotime($object->content);
+
+ case 'base64':
+ return base64_decode($object->content);
+
+ case 'value':
+ return xmlrpc_scalar_value($object->children[0]);
+
+ default:
+ // @todo unsupported, throw an error
+ return false;
}
-
- /**
- * Trigger a method call and pass the relevant parameters to the funciton.
- *
- * @param XMLRPCCall $parameters The call and parameters.
- * @return XMLRPCCall
- */
- function trigger_xmlrpc_handler(XMLRPCCall $parameters)
- {
- global $XML_RPC_HANDLERS;
-
- // Go through and see if we have a handler
- if (isset($XML_RPC_HANDLERS[$parameters->getMethodName()]))
- {
- $handler = $XML_RPC_HANDLERS[$parameters->getMethodName()];
- $result = $handler($parameters);
-
- if (!($result instanceof XMLRPCResponse))
- throw new InvalidParameterException(sprintf(elgg_echo('InvalidParameterException:UnexpectedReturnFormat'), $parameters->getMethodName()));
-
- // Result in right format, return it.
- return $result;
+}
+
+// Functions for adding handlers //////////////////////////////////////////////////////////
+
+/** XML-RPC Handlers */
+global $XML_RPC_HANDLERS;
+$XML_RPC_HANDLERS = array();
+
+/**
+ * Register a method handler for a given XML-RPC method.
+ *
+ * @param string $method Method parameter.
+ * @param string $handler The handler function. This function accepts
+ * one XMLRPCCall object and must return a XMLRPCResponse object.
+ *
+ * @return bool
+ */
+function register_xmlrpc_handler($method, $handler) {
+ global $XML_RPC_HANDLERS;
+
+ $XML_RPC_HANDLERS[$method] = $handler;
+}
+
+/**
+ * Trigger a method call and pass the relevant parameters to the funciton.
+ *
+ * @param XMLRPCCall $parameters The call and parameters.
+ *
+ * @return XMLRPCCall
+ * @access private
+ */
+function trigger_xmlrpc_handler(XMLRPCCall $parameters) {
+ global $XML_RPC_HANDLERS;
+
+ // Go through and see if we have a handler
+ if (isset($XML_RPC_HANDLERS[$parameters->getMethodName()])) {
+ $handler = $XML_RPC_HANDLERS[$parameters->getMethodName()];
+ $result = $handler($parameters);
+
+ if (!($result instanceof XMLRPCResponse)) {
+ $msg = elgg_echo('InvalidParameterException:UnexpectedReturnFormat',
+ array($parameters->getMethodName()));
+ throw new InvalidParameterException($msg);
}
-
- // if no handler then throw exception
- throw new NotImplementedException(sprintf(elgg_echo('NotImplementedException:XMLRPCMethodNotImplemented'), $parameters->getMethodName()));
+
+ // Result in right format, return it.
+ return $result;
}
-
- // Error handler functions ////////////////////////////////////////////////////////////////
-
- /**
- * PHP Error handler function.
- * This function acts as a wrapper to catch and report PHP error messages.
- *
- * @see http://uk3.php.net/set-error-handler
- * @param unknown_type $errno
- * @param unknown_type $errmsg
- * @param unknown_type $filename
- * @param unknown_type $linenum
- * @param unknown_type $vars
- */
- function __php_xmlrpc_error_handler($errno, $errmsg, $filename, $linenum, $vars)
- {
- $error = date("Y-m-d H:i:s (T)") . ": \"" . $errmsg . "\" in file " . $filename . " (line " . $linenum . ")";
-
- switch ($errno) {
- case E_USER_ERROR:
- error_log("ERROR: " . $error);
-
- // Since this is a fatal error, we want to stop any further execution but do so gracefully.
- throw new Exception("ERROR: " . $error);
- break;
-
- case E_WARNING :
- case E_USER_WARNING :
- error_log("WARNING: " . $error);
- break;
-
- default:
- error_log("DEBUG: " . $error);
- }
+
+ // if no handler then throw exception
+ $msg = elgg_echo('NotImplementedException:XMLRPCMethodNotImplemented',
+ array($parameters->getMethodName()));
+ throw new NotImplementedException($msg);
+}
+
+/**
+ * PHP Error handler function.
+ * This function acts as a wrapper to catch and report PHP error messages.
+ *
+ * @see http://uk3.php.net/set-error-handler
+ *
+ * @param int $errno Error number
+ * @param string $errmsg Human readable message
+ * @param string $filename Filename
+ * @param int $linenum Line number
+ * @param array $vars Vars
+ *
+ * @return void
+ * @access private
+ */
+function _php_xmlrpc_error_handler($errno, $errmsg, $filename, $linenum, $vars) {
+ $error = date("Y-m-d H:i:s (T)") . ": \"" . $errmsg . "\" in file "
+ . $filename . " (line " . $linenum . ")";
+
+ switch ($errno) {
+ case E_USER_ERROR:
+ error_log("ERROR: " . $error);
+
+ // Since this is a fatal error, we want to stop any further execution but do so gracefully.
+ throw new Exception("ERROR: " . $error);
+ break;
+
+ case E_WARNING :
+ case E_USER_WARNING :
+ error_log("WARNING: " . $error);
+ break;
+
+ default:
+ error_log("DEBUG: " . $error);
}
-
- /**
- * PHP Exception handler for XMLRPC.
- * @param Exception $exception
- */
- function __php_xmlrpc_exception_handler($exception) {
-
- error_log("*** FATAL EXCEPTION (XML-RPC) *** : " . $exception);
-
- page_draw($exception->getMessage(), elgg_view("xml-rpc/output", array('result' => new XMLRPCErrorResponse($exception->getMessage(), $exception->getCode()==0 ? -32400 : $exception->getCode()))));
+}
+
+/**
+ * PHP Exception handler for XMLRPC.
+ *
+ * @param Exception $exception The exception
+ *
+ * @return void
+ * @access private
+ */
+function _php_xmlrpc_exception_handler($exception) {
+
+ error_log("*** FATAL EXCEPTION (XML-RPC) *** : " . $exception);
+
+ $code = $exception->getCode();
+
+ if ($code == 0) {
+ $code = -32400;
}
-?>
+
+ $result = new XMLRPCErrorResponse($exception->getMessage(), $code);
+
+ $vars = array('result' => $result);
+
+ $content = elgg_view("xml-rpc/output", $vars);
+
+ echo elgg_view_page($exception->getMessage(), $content);
+}
diff --git a/engine/lib/xml.php b/engine/lib/xml.php
index b21fdd92b..497459d83 100644
--- a/engine/lib/xml.php
+++ b/engine/lib/xml.php
@@ -1,163 +1,111 @@
<?php
- /**
- * Elgg XML library.
- * Contains functions for generating and parsing XML.
- *
- * @package Elgg
- * @subpackage Core
- * @author Curverider Ltd
- * @link http://elgg.org/
- */
-
- /**
- * @class XmlElement
- * A class representing an XML element for import.
- */
- class XmlElement
- {
- /** The name of the element */
- public $name;
-
- /** The attributes */
- public $attributes;
-
- /** CData */
- public $content;
-
- /** Child elements */
- public $children;
- };
-
- /**
- * This function serialises an object recursively into an XML representation.
- * The function attempts to call $data->export() which expects a stdClass in return, otherwise it will attempt to
- * get the object variables using get_object_vars (which will only return public variables!)
- * @param $data object The object to serialise.
- * @param $n int Level, only used for recursion.
- * @return string The serialised XML output.
- */
- function serialise_object_to_xml($data, $name = "", $n = 0)
- {
- $classname = ($name=="" ? get_class($data) : $name);
-
- $vars = method_exists($data, "export") ? get_object_vars($data->export()) : get_object_vars($data);
-
- $output = "";
-
- if (($n==0) || ( is_object($data) && !($data instanceof stdClass))) {
- $output = "<$classname>";
- }
-
- foreach ($vars as $key => $value) {
- $output .= "<$key type=\"".gettype($value)."\">";
-
- if (is_object($value)) {
- $output .= serialise_object_to_xml($value, $key, $n+1);
- } else if (is_array($value)) {
- $output .= serialise_array_to_xml($value, $n+1);
- } else if (gettype($value) == "boolean") {
- $output .= $value ? "true" : "false";
- } else {
- $output .= htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
- }
-
- $output .= "</$key>\n";
- }
-
- if (($n==0) || ( is_object($data) && !($data instanceof stdClass))) {
- $output .= "</$classname>\n";
- }
-
- return $output;
+/**
+ * Elgg XML library.
+ * Contains functions for generating and parsing XML.
+ *
+ * @package Elgg.Core
+ * @subpackage XML
+ */
+
+/**
+ * This function serialises an object recursively into an XML representation.
+ *
+ * The function attempts to call $data->export() which expects a stdClass in return,
+ * otherwise it will attempt to get the object variables using get_object_vars (which
+ * will only return public variables!)
+ *
+ * @param mixed $data The object to serialise.
+ * @param string $name The name?
+ * @param int $n Level, only used for recursion.
+ *
+ * @return string The serialised XML output.
+ */
+function serialise_object_to_xml($data, $name = "", $n = 0) {
+ $classname = ($name == "" ? get_class($data) : $name);
+
+ $vars = method_exists($data, "export") ? get_object_vars($data->export()) : get_object_vars($data);
+
+ $output = "";
+
+ if (($n == 0) || ( is_object($data) && !($data instanceof stdClass))) {
+ $output = "<$classname>";
}
- /**
- * Serialise an array.
- *
- * @param array $data
- * @param int $n Used for recursion
- * @return string
- */
- function serialise_array_to_xml(array $data, $n = 0)
- {
- $output = "";
-
- if ($n==0) {
- $output = "<array>\n";
+ foreach ($vars as $key => $value) {
+ $output .= "<$key type=\"" . gettype($value) . "\">";
+
+ if (is_object($value)) {
+ $output .= serialise_object_to_xml($value, $key, $n + 1);
+ } else if (is_array($value)) {
+ $output .= serialise_array_to_xml($value, $n + 1);
+ } else if (gettype($value) == "boolean") {
+ $output .= $value ? "true" : "false";
+ } else {
+ $output .= htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
}
-
- foreach ($data as $key => $value) {
- $item = "array_item";
-
- if (is_numeric($key)) {
- $output .= "<$item name=\"$key\" type=\"".gettype($value)."\">";
- } else {
- $item = $key;
- $output .= "<$item type=\"".gettype($value)."\">";
- }
-
- if (is_object($value)) {
- $output .= serialise_object_to_xml($value, "", $n+1);
- } else if (is_array($value)) {
- $output .= serialise_array_to_xml($value, $n+1);
- } else if (gettype($value) == "boolean") {
- $output .= $value ? "true" : "false";
- } else {
- $output .= htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
- }
-
- $output .= "</$item>\n";
+
+ $output .= "</$key>\n";
+ }
+
+ if (($n == 0) || (is_object($data) && !($data instanceof stdClass))) {
+ $output .= "</$classname>\n";
+ }
+
+ return $output;
+}
+
+/**
+ * Serialise an array.
+ *
+ * @param array $data The data to serialize
+ * @param int $n Used for recursion
+ *
+ * @return string
+ */
+function serialise_array_to_xml(array $data, $n = 0) {
+ $output = "";
+
+ if ($n == 0) {
+ $output = "<array>\n";
+ }
+
+ foreach ($data as $key => $value) {
+ $item = "array_item";
+
+ if (is_numeric($key)) {
+ $output .= "<$item name=\"$key\" type=\"" . gettype($value) . "\">";
+ } else {
+ $item = $key;
+ $output .= "<$item type=\"" . gettype($value) . "\">";
}
-
- if ($n==0) {
- $output .= "</array>\n";
+
+ if (is_object($value)) {
+ $output .= serialise_object_to_xml($value, "", $n + 1);
+ } else if (is_array($value)) {
+ $output .= serialise_array_to_xml($value, $n + 1);
+ } else if (gettype($value) == "boolean") {
+ $output .= $value ? "true" : "false";
+ } else {
+ $output .= htmlspecialchars($value, ENT_NOQUOTES, 'UTF-8');
}
-
- return $output;
+
+ $output .= "</$item>\n";
}
-
- /**
- * Parse an XML file into an object.
- * Based on code from http://de.php.net/manual/en/function.xml-parse-into-struct.php by
- * efredricksen at gmail dot com
- *
- * @param string $xml The XML.
- */
- function xml_to_object($xml)
- {
- $parser = xml_parser_create();
-
- // Parse $xml into a structure
- xml_parser_set_option($parser, XML_OPTION_SKIP_WHITE, 1);
- xml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, 0);
- xml_parse_into_struct($parser, $xml, $tags);
-
- xml_parser_free($parser);
-
- $elements = array();
- $stack = array();
-
- foreach ($tags as $tag) {
- $index = count($elements);
-
- if ($tag['type'] == "complete" || $tag['type'] == "open") {
- $elements[$index] = new XmlElement;
- $elements[$index]->name = $tag['tag'];
- $elements[$index]->attributes = $tag['attributes'];
- $elements[$index]->content = $tag['value'];
-
- if ($tag['type'] == "open") {
- $elements[$index]->children = array();
- $stack[count($stack)] = &$elements;
- $elements = &$elements[$index]->children;
- }
- }
-
- if ($tag['type'] == "close") {
- $elements = &$stack[count($stack) - 1];
- unset($stack[count($stack) - 1]);
- }
- }
-
- return $elements[0];
+
+ if ($n == 0) {
+ $output .= "</array>\n";
}
+
+ return $output;
+}
+
+/**
+ * Parse an XML file into an object.
+ *
+ * @param string $xml The XML
+ *
+ * @return ElggXMLElement
+ */
+function xml_to_object($xml) {
+ return new ElggXMLElement($xml);
+}