diff options
Diffstat (limited to 'engine')
78 files changed, 1429 insertions, 806 deletions
diff --git a/engine/classes/ElggBatch.php b/engine/classes/ElggBatch.php index 62128e34f..0cb13eb32 100644 --- a/engine/classes/ElggBatch.php +++ b/engine/classes/ElggBatch.php @@ -3,47 +3,51 @@ * Efficiently run operations on batches of results for any function * that supports an options array. * - * This is usually used with elgg_get_entities() and friends, elgg_get_annotations() - * and elgg_get_metadata(). + * This is usually used with elgg_get_entities() and friends, + * elgg_get_annotations(), and elgg_get_metadata(). * - * If you pass a valid PHP callback, all results will be run through that callback. - * You can still foreach() through the result set after. Valid PHP callbacks - * can be a string, an array, or a closure. + * If you pass a valid PHP callback, all results will be run through that + * callback. You can still foreach() through the result set after. Valid + * PHP callbacks can be a string, an array, or a closure. * {@link http://php.net/manual/en/language.pseudo-types.php} * - * The callback function must accept 3 arguments: an entity, the getter used, and the options used. + * The callback function must accept 3 arguments: an entity, the getter + * used, and the options used. * - * Results from the callback are stored in callbackResult. - * If the callback returns only booleans, callbackResults will be the combined - * result of all calls. + * Results from the callback are stored in callbackResult. If the callback + * returns only booleans, callbackResults will be the combined result of + * all calls. * - * If the callback returns anything else, callbackresult will be an indexed array - * of whatever the callback returns. If returning error handling information, - * you should include enough information to determine which result you're referring - * to. + * If the callback returns anything else, callbackresult will be an indexed + * array of whatever the callback returns. If returning error handling + * information, you should include enough information to determine which + * result you're referring to. * * Don't combine returning bools and returning something else. * * Note that returning false will not stop the foreach. * + * @warning If your callback or foreach loop deletes or disable entities + * you MUST call setIncrementOffset(false) or set that when instantiating. + * This forces the offset to stay what it was in the $options array. + * * @example * <code> + * // using foreach * $batch = new ElggBatch('elgg_get_entities', array()); + * $batch->setIncrementOffset(false); * * foreach ($batch as $entity) { * $entity->disable(); * } * + * // using both a callback * $callback = function($result, $getter, $options) { - * var_dump("Going to delete annotation id: $result->id"); + * var_dump("Looking at annotation id: $result->id"); * return true; * } * * $batch = new ElggBatch('elgg_get_annotations', array('guid' => 2), $callback); - * - * foreach ($batch as $annotation) { - * $annotation->delete(); - * } * </code> * * @package Elgg.Core @@ -92,7 +96,7 @@ class ElggBatch /** * Stop after this many results. * - * @var unknown_type + * @var int */ private $limit = 0; @@ -139,6 +143,13 @@ class ElggBatch public $callbackResult = null; /** + * If false, offset will not be incremented. This is used for callbacks/loops that delete. + * + * @var bool + */ + private $incrementOffset = true; + + /** * Batches operations on any elgg_get_*() or compatible function that supports * an options array. * @@ -147,19 +158,27 @@ class ElggBatch * * @param string $getter The function used to get objects. Usually * an elgg_get_*() function, but can be any valid PHP callback. - * @param array $options The options array to pass to the getter function + * @param array $options The options array to pass to the getter function. If limit is + * not set, 10 is used as the default. In most cases that is not + * what you want. * @param mixed $callback An optional callback function that all results will be passed * to upon load. The callback needs to accept $result, $getter, * $options. * @param int $chunk_size The number of entities to pull in before requesting more. * You have to balance this between running out of memory in PHP * and hitting the db server too often. + * @param bool $inc_offset Increment the offset on each fetch. This must be false for + * callbacks that delete rows. You can set this after the + * object is created with {@see ElggBatch::setIncrementOffset()}. */ - public function __construct($getter, $options, $callback = null, $chunk_size = 25) { + public function __construct($getter, $options, $callback = null, $chunk_size = 25, + $inc_offset = true) { + $this->getter = $getter; $this->options = $options; $this->callback = $callback; $this->chunkSize = $chunk_size; + $this->setIncrementOffset($inc_offset); if ($this->chunkSize <= 0) { $this->chunkSize = 25; @@ -172,7 +191,7 @@ class ElggBatch // if passed a callback, create a new ElggBatch with the same options // and pass each to the callback. if ($callback && is_callable($callback)) { - $batch = new ElggBatch($getter, $options, null, $chunk_size); + $batch = new ElggBatch($getter, $options, null, $chunk_size, $inc_offset); $all_results = null; @@ -234,20 +253,24 @@ class ElggBatch } // if original limit < chunk size, set limit to original limit + // else if the number of results we'll fetch if greater than the original limit if ($this->limit < $this->chunkSize) { $limit = $this->limit; - } - - // if the number of results we'll fetch is greater than the original limit, - // set the limit to the number of results remaining in the original limit - elseif ($this->retrievedResults + $this->chunkSize > $this->limit) { + } elseif ($this->retrievedResults + $this->chunkSize > $this->limit) { + // set the limit to the number of results remaining in the original limit $limit = $this->limit - $this->retrievedResults; } } + if ($this->incrementOffset) { + $offset = $this->offset + $this->retrievedResults; + } else { + $offset = $this->offset; + } + $current_options = array( 'limit' => $limit, - 'offset' => $this->offset + $this->retrievedResults + 'offset' => $offset ); $options = array_merge($this->options, $current_options); @@ -270,6 +293,16 @@ class ElggBatch } /** + * Increment the offset from the original options array? Setting to + * false is required for callbacks that delete rows. + * + * @param bool $increment + */ + public function setIncrementOffset($increment = true) { + $this->incrementOffset = (bool) $increment; + } + + /** * Implements Iterator */ @@ -319,13 +352,13 @@ class ElggBatch */ public function next() { // if we'll be at the end. - if ($this->processedResults + 1 >= $this->limit && $this->limit > 0) { + if (($this->processedResults + 1) >= $this->limit && $this->limit > 0) { $this->results = array(); return false; } // if we'll need new results. - if ($this->resultIndex + 1 >= $this->chunkSize) { + if (($this->resultIndex + 1) >= $this->chunkSize) { if (!$this->getNextResultsChunk()) { $this->results = array(); return false; @@ -356,4 +389,4 @@ class ElggBatch $key = key($this->results); return ($key !== NULL && $key !== FALSE); } -}
\ No newline at end of file +} diff --git a/engine/classes/ElggCache.php b/engine/classes/ElggCache.php index 5c2cafcb7..4317f4be9 100644 --- a/engine/classes/ElggCache.php +++ b/engine/classes/ElggCache.php @@ -29,7 +29,7 @@ abstract class ElggCache implements ArrayAccess { * * @return void * - * @deprecated 1.8 Use ElggAccess:setVariable() + * @deprecated 1.8 Use ElggCache:setVariable() */ public function set_variable($variable, $value) { elgg_deprecated_notice('ElggCache::set_variable() is deprecated by ElggCache::setVariable()', 1.8); @@ -191,8 +191,8 @@ abstract class ElggCache implements ArrayAccess { * * @see ArrayAccess::offsetSet() * - * @param mixed $key The key (offset) to assign the value to. - * @param mixed $value The value to set. + * @param mixed $key The key (offset) to assign the value to. + * @param mixed $value The value to set. * * @return void */ @@ -205,7 +205,7 @@ abstract class ElggCache implements ArrayAccess { * * @see ArrayAccess::offsetGet() * - * @param mixed $offset The key (offset) to retrieve. + * @param mixed $key The key (offset) to retrieve. * * @return mixed */ diff --git a/engine/classes/ElggDiskFilestore.php b/engine/classes/ElggDiskFilestore.php index 11b2bd947..f00376481 100644 --- a/engine/classes/ElggDiskFilestore.php +++ b/engine/classes/ElggDiskFilestore.php @@ -205,7 +205,7 @@ class ElggDiskFilestore extends ElggFilestore { $owner = elgg_get_logged_in_user_entity(); } - if ((!$owner) || (!$owner->username)) { + if (!$owner) { $msg = elgg_echo('InvalidParameterException:MissingOwner', array($file->getFilename(), $file->guid)); throw new InvalidParameterException($msg); diff --git a/engine/classes/ElggEntity.php b/engine/classes/ElggEntity.php index df87082fe..dc38dafbe 100644 --- a/engine/classes/ElggEntity.php +++ b/engine/classes/ElggEntity.php @@ -1311,12 +1311,16 @@ abstract class ElggEntity extends ElggData implements /** * Loads attributes from the entities table into the object. * - * @param int $guid GUID of Entity + * @param mixed $guid GUID of entity or stdClass object from entities table * * @return bool */ protected function load($guid) { - $row = get_entity_as_row($guid); + if ($guid instanceof stdClass) { + $row = $guid; + } else { + $row = get_entity_as_row($guid); + } if ($row) { // Create the array if necessary - all subclasses should test before creating @@ -1583,36 +1587,36 @@ abstract class ElggEntity extends ElggData implements foreach ($this->attributes as $k => $v) { $meta = NULL; - if (in_array( $k, $exportable_values)) { + 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 'guid': // Dont use guid in OpenDD + case 'type': // Type and subtype already taken care of + case 'subtype': + break; - case 'time_created' : // Created = published + case 'time_created': // Created = published $odd->setAttribute('published', date("r", $v)); - break; + break; - case 'site_guid' : // Container + case 'site_guid': // Container $k = 'site_uuid'; $v = guid_to_uuid($v); $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); - break; + break; - case 'container_guid' : // Container + case 'container_guid': // Container $k = 'container_uuid'; $v = guid_to_uuid($v); $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); - break; + break; - case 'owner_guid' : // Convert owner guid to uuid, this will be stored in metadata + 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; + break; - default : + default: $meta = new ODDMetaData($uuid . "attr/$k/", $uuid, $k, $v); } diff --git a/engine/classes/ElggExtender.php b/engine/classes/ElggExtender.php index d6f79d18d..d94bad837 100644 --- a/engine/classes/ElggExtender.php +++ b/engine/classes/ElggExtender.php @@ -3,8 +3,7 @@ * The base class for ElggEntity extenders. * * Extenders allow you to attach extended information to an - * ElggEntity. Core supports two: ElggAnnotation, ElggMetadata, - * and ElggRelationship + * ElggEntity. Core supports two: ElggAnnotation and ElggMetadata. * * Saving the extender data to database is handled by the child class. * @@ -16,9 +15,24 @@ * @link http://docs.elgg.org/DataModel/Extenders * @see ElggAnnotation * @see ElggMetadata + * + * @property string $type annotation or metadata (read-only after save) + * @property int $id The unique identifier (read-only) + * @property int $entity_guid The GUID of the entity that this extender describes + * @property int $access_id Specifies the visibility level of this extender + * @property string $name The name of this extender + * @property mixed $value The value of the extender (int or string) + * @property int $time_created A UNIX timestamp of when the extender was created (read-only, set on first save) */ -abstract class ElggExtender extends ElggData -{ +abstract class ElggExtender extends ElggData { + + /** + * (non-PHPdoc) + * + * @see ElggData::initializeAttributes() + * + * @return void + */ protected function initializeAttributes() { parent::initializeAttributes(); diff --git a/engine/classes/ElggFileCache.php b/engine/classes/ElggFileCache.php index 8304372dc..34178d452 100644 --- a/engine/classes/ElggFileCache.php +++ b/engine/classes/ElggFileCache.php @@ -161,12 +161,25 @@ class ElggFileCache extends ElggCache { } /** - * This was probably meant to delete everything? + * Delete all files in the directory of this file cache * * @return void */ public function clear() { - // @todo writeme + $dir = $this->getVariable("cache_path"); + + $exclude = array(".", ".."); + + $files = scandir($dir); + if (!$files) { + return; + } + + foreach ($files as $f) { + if (!in_array($f, $exclude)) { + unlink($dir . $f); + } + } } /** @@ -184,7 +197,7 @@ class ElggFileCache extends ElggCache { return; } - $exclude = array(".",".."); + $exclude = array(".", ".."); $files = scandir($dir); if (!$files) { diff --git a/engine/classes/ElggGroup.php b/engine/classes/ElggGroup.php index 0190e5eac..f7f67bf41 100644 --- a/engine/classes/ElggGroup.php +++ b/engine/classes/ElggGroup.php @@ -5,6 +5,9 @@ * * @package Elgg.Core * @subpackage Groups + * + * @property string $name A short name that captures the purpose of the group + * @property string $description A longer body of content that gives more details about the group */ class ElggGroup extends ElggEntity implements Friendable { @@ -26,12 +29,12 @@ class ElggGroup extends ElggEntity } /** - * Construct a new user entity, optionally from a given id value. + * Construct a new group entity, optionally from a given guid value. * * @param mixed $guid If an int, load that GUID. - * If a db row then will attempt to load the rest of the data. + * If an entity table db row, then will load the rest of the data. * - * @throws Exception if there was a problem creating the user. + * @throws Exception if there was a problem creating the group. */ function __construct($guid = null) { $this->initializeAttributes(); @@ -40,15 +43,15 @@ class ElggGroup extends ElggEntity $this->initialise_attributes(false); if (!empty($guid)) { - // Is $guid is a DB row - either a entity row, or a user table row. + // Is $guid is a entity table DB row if ($guid instanceof stdClass) { // Load the rest - if (!$this->load($guid->guid)) { + if (!$this->load($guid)) { $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - // Is $guid is an ElggGroup? Use a copy constructor + // 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); @@ -56,11 +59,11 @@ class ElggGroup extends ElggEntity $this->attributes[$key] = $value; } - // Is this is an ElggEntity but not an ElggGroup = ERROR! + // 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 + // Is it a GUID } else if (is_numeric($guid)) { if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); @@ -316,11 +319,9 @@ class ElggGroup extends ElggEntity } /** - * 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. + * Load the ElggGroup data from the database * - * @param int $guid GUID of an ElggGroup entity + * @param mixed $guid GUID of an ElggGroup entity or database row from entity table * * @return bool */ @@ -330,6 +331,11 @@ class ElggGroup extends ElggEntity return false; } + // Only work with GUID from here + if ($guid instanceof stdClass) { + $guid = $guid->guid; + } + // Check the type if ($this->attributes['type'] != 'group') { $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class())); diff --git a/engine/classes/ElggMemcache.php b/engine/classes/ElggMemcache.php index a54c29723..f27b017d0 100644 --- a/engine/classes/ElggMemcache.php +++ b/engine/classes/ElggMemcache.php @@ -114,27 +114,11 @@ class ElggMemcache extends ElggSharedMemoryCache { * Combine a key with the namespace. * Memcache can only accept <250 char key. If the given key is too long it is shortened. * - * @deprecated 1.8 Use ElggMemcache::_makeMemcacheKey() - * - * @param string $key The key - * - * @return string The new key. - */ - private function make_memcache_key($key) { - elgg_deprecated_notice('ElggMemcache::make_memcache_key() is deprecated by ::_makeMemcacheKey()', 1.8); - - return $this->_makeMemcacheKey($key); - } - - /** - * 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 _makeMemcacheKey($key) { + private function makeMemcacheKey($key) { $prefix = $this->getNamespace() . ":"; if (strlen($prefix . $key) > 250) { @@ -154,7 +138,7 @@ class ElggMemcache extends ElggSharedMemoryCache { * @return bool */ public function save($key, $data, $expires = null) { - $key = $this->_makeMemcacheKey($key); + $key = $this->makeMemcacheKey($key); if ($expires === null) { $expires = $this->expires; @@ -178,7 +162,7 @@ class ElggMemcache extends ElggSharedMemoryCache { * @return mixed */ public function load($key, $offset = 0, $limit = null) { - $key = $this->_makeMemcacheKey($key); + $key = $this->makeMemcacheKey($key); $result = $this->memcache->get($key); if ($result === false) { @@ -196,7 +180,7 @@ class ElggMemcache extends ElggSharedMemoryCache { * @return bool */ public function delete($key) { - $key = $this->_makeMemcacheKey($key); + $key = $this->makeMemcacheKey($key); return $this->memcache->delete($key, 0); } diff --git a/engine/classes/ElggMenuBuilder.php b/engine/classes/ElggMenuBuilder.php index cadfee7f5..de0017599 100644 --- a/engine/classes/ElggMenuBuilder.php +++ b/engine/classes/ElggMenuBuilder.php @@ -4,8 +4,7 @@ * * @package Elgg.Core * @subpackage Navigation - * - * @since 1.8.0 + * @since 1.8.0 */ class ElggMenuBuilder { @@ -16,16 +15,16 @@ class ElggMenuBuilder { /** * ElggMenuBuilder constructor * - * @param string $name Identifier of the menu + * @param array $menu Array of ElggMenuItem objects */ - public function __construct($menu) { + public function __construct(array $menu) { $this->menu = $menu; } /** * Get a prepared menu array * - * @param mixed $sort_by + * @param mixed $sort_by Method to sort the menu by. @see ElggMenuBuilder::sort() * @return array */ public function getMenu($sort_by = 'text') { @@ -80,6 +79,7 @@ class ElggMenuBuilder { /** * Group the menu items into sections + * * @return void */ protected function setupSections() { diff --git a/engine/classes/ElggMenuItem.php b/engine/classes/ElggMenuItem.php index 62547134a..4bc9144d4 100644 --- a/engine/classes/ElggMenuItem.php +++ b/engine/classes/ElggMenuItem.php @@ -2,12 +2,11 @@ /** * Elgg Menu Item * - * @package Elgg.Core - * @subpackage Navigation - * * To create a menu item that is not a link, pass false for $href. * - * @since 1.8.0 + * @package Elgg.Core + * @subpackage Navigation + * @since 1.8.0 */ class ElggMenuItem { @@ -70,9 +69,9 @@ class ElggMenuItem { /** * ElggMenuItem constructor * - * @param string $name Identifier of the menu item - * @param string $text Display text of the menu item - * @param string $href URL of the menu item (false if not a link) + * @param string $name Identifier of the menu item + * @param string $text Display text of the menu item + * @param string $href URL of the menu item (false if not a link) */ public function __construct($name, $text, $href) { //$this->name = $name; @@ -182,7 +181,7 @@ class ElggMenuItem { /** * Set the identifier of the menu item * - * @param string Unique identifier + * @param string $name Unique identifier * @return void */ public function setName($name) { @@ -491,7 +490,7 @@ class ElggMenuItem { /** * Set the parent menu item * - * @param ElggMenuItem $parent + * @param ElggMenuItem $parent The parent of this menu item * @return void */ public function setParent($parent) { @@ -510,7 +509,7 @@ class ElggMenuItem { /** * Add a child menu item * - * @param ElggMenuItem $item + * @param ElggMenuItem $item A child menu item * @return void */ public function addChild($item) { @@ -549,9 +548,8 @@ class ElggMenuItem { /** * Get the menu item content (usually a link) * - * @params array $vars Options to pass to output/url if a link + * @param array $vars Options to pass to output/url if a link * @return string - * * @todo View code in a model. How do we feel about that? */ public function getContent(array $vars = array()) { diff --git a/engine/classes/ElggMetadata.php b/engine/classes/ElggMetadata.php index 32e7b32f1..634a122e5 100644 --- a/engine/classes/ElggMetadata.php +++ b/engine/classes/ElggMetadata.php @@ -9,6 +9,13 @@ */ class ElggMetadata extends ElggExtender { + /** + * (non-PHPdoc) + * + * @see ElggData::initializeAttributes() + * + * @return void + */ protected function initializeAttributes() { parent::initializeAttributes(); diff --git a/engine/classes/ElggObject.php b/engine/classes/ElggObject.php index 0b8340697..b4bae6825 100644 --- a/engine/classes/ElggObject.php +++ b/engine/classes/ElggObject.php @@ -14,6 +14,10 @@ * * @package Elgg.Core * @subpackage DataModel.Object + * + * @property string $title The title, name, or summary of this object + * @property string $description The body, description, or content of the object + * @property array $tags Array of tags that describe the object */ class ElggObject extends ElggEntity { @@ -37,12 +41,12 @@ class ElggObject extends ElggEntity { * * If no arguments are passed, create a new entity. * - * If an argument is passed attempt to load a full Object entity. Arguments - * can be: + * If an argument is passed, attempt to load a full ElggObject entity. + * Arguments can be: * - The GUID of an object entity. - * - A DB result object with a guid property + * - A DB result object from the entities table with a guid property * - * @param mixed $guid If an int, load that GUID. If a db row then will attempt to + * @param mixed $guid If an int, load that GUID. If a db row, then will attempt to * load the rest of the data. * * @throws IOException If passed an incorrect guid @@ -55,15 +59,15 @@ class ElggObject extends ElggEntity { $this->initialise_attributes(false); if (!empty($guid)) { - // Is $guid is a DB row - either a entity row, or a object table row. + // Is $guid is a DB row from the entity table if ($guid instanceof stdClass) { // Load the rest - if (!$this->load($guid->guid)) { + if (!$this->load($guid)) { $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - // Is $guid is an ElggObject? Use a copy constructor + // 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); @@ -71,11 +75,11 @@ class ElggObject extends ElggEntity { $this->attributes[$key] = $value; } - // Is this is an ElggEntity but not an ElggObject = ERROR! + // 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 + // Is it a GUID } else if (is_numeric($guid)) { if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); @@ -89,17 +93,22 @@ class ElggObject extends ElggEntity { /** * Loads the full ElggObject when given a guid. * - * @param int $guid Guid of an ElggObject + * @param mixed $guid GUID of an ElggObject or the stdClass object from entities table * * @return bool * @throws InvalidClassException */ protected function load($guid) { - // Test to see if we have the generic stuff + // Load data from entity table if needed if (!parent::load($guid)) { return false; } + // Only work with GUID from here + if ($guid instanceof stdClass) { + $guid = $guid->guid; + } + // Check the type if ($this->attributes['type'] != 'object') { $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class())); diff --git a/engine/classes/ElggPlugin.php b/engine/classes/ElggPlugin.php index c4d6ec034..33f14ae37 100644 --- a/engine/classes/ElggPlugin.php +++ b/engine/classes/ElggPlugin.php @@ -707,9 +707,9 @@ class ElggPlugin extends ElggObject { * @throws PluginException */ public function start($flags) { -// if (!$this->canActivate()) { -// return false; -// } + //if (!$this->canActivate()) { + // return false; + //} // include classes if ($flags & ELGG_PLUGIN_REGISTER_CLASSES) { diff --git a/engine/classes/ElggPluginPackage.php b/engine/classes/ElggPluginPackage.php index d240af477..2dc4bdb3d 100644 --- a/engine/classes/ElggPluginPackage.php +++ b/engine/classes/ElggPluginPackage.php @@ -303,6 +303,8 @@ class ElggPluginPackage { /** * Returns an array of present and readable text files + * + * @return array */ public function getTextFilenames() { return $this->textFiles; diff --git a/engine/classes/ElggRelationship.php b/engine/classes/ElggRelationship.php index 2d9a32cbd..efc0f7eff 100644 --- a/engine/classes/ElggRelationship.php +++ b/engine/classes/ElggRelationship.php @@ -4,6 +4,12 @@ * * @package Elgg.Core * @subpackage Core + * + * @property int $id The unique identifier (read-only) + * @property int $guid_one The GUID of the subject of the relationship + * @property string $relationship The name of the relationship + * @property int $guid_two The GUID of the object of the relationship + * @property int $time_created A UNIX timestamp of when the relationship was created (read-only, set on first save) */ class ElggRelationship extends ElggData implements Importable diff --git a/engine/classes/ElggRiverItem.php b/engine/classes/ElggRiverItem.php index fcc8f9c85..d3d09cd91 100644 --- a/engine/classes/ElggRiverItem.php +++ b/engine/classes/ElggRiverItem.php @@ -4,9 +4,19 @@ * * @package Elgg.Core * @subpackage Core + * + * @property int $id The unique identifier (read-only) + * @property int $subject_guid The GUID of the actor + * @property int $object_guid The GUID of the object + * @property int $annotation_id The ID of the annotation involved in the action + * @property string $type The type of one of the entities involved in the action + * @property string $subtype The subtype of one of the entities involved in the action + * @property string $action_type The name of the action + * @property string $view The view for displaying this river item + * @property int $access_id The visibility of the river item + * @property int $posted UNIX timestamp when the action occurred */ -class ElggRiverItem -{ +class ElggRiverItem { public $id; public $subject_guid; public $object_guid; diff --git a/engine/classes/ElggSite.php b/engine/classes/ElggSite.php index 3ccb146fb..49616f1be 100644 --- a/engine/classes/ElggSite.php +++ b/engine/classes/ElggSite.php @@ -21,6 +21,10 @@ * @package Elgg.Core * @subpackage DataMode.Site * @link http://docs.elgg.org/DataModel/Sites + * + * @property string $name The name or title of the website + * @property string $description A motto, mission statement, or description of the website + * @property string $url The root web address for the site, including trailing slash */ class ElggSite extends ElggEntity { @@ -53,8 +57,8 @@ class ElggSite extends ElggEntity { * - A URL as stored in ElggSite->url * - A DB result object with a guid property * - * @param mixed $guid If an int, load that GUID. If a db row then will attempt - * to load the rest of the data. + * @param mixed $guid If an int, load that GUID. If a db row then will + * load the rest of the data. * * @throws IOException If passed an incorrect guid * @throws InvalidParameterException If passed an Elgg* Entity that isn't an ElggSite @@ -66,15 +70,15 @@ class ElggSite extends ElggEntity { $this->initialise_attributes(false); if (!empty($guid)) { - // Is $guid is a DB row - either a entity row, or a site table row. + // Is $guid is a DB entity table row if ($guid instanceof stdClass) { // Load the rest - if (!$this->load($guid->guid)) { + if (!$this->load($guid)) { $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - // Is $guid is an ElggSite? Use a copy constructor + // 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); @@ -82,18 +86,18 @@ class ElggSite extends ElggEntity { $this->attributes[$key] = $value; } - // Is this is an ElggEntity but not an ElggSite = ERROR! + // 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 + // 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 + // Is it a GUID } else if (is_numeric($guid)) { if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); @@ -107,7 +111,7 @@ class ElggSite extends ElggEntity { /** * Loads the full ElggSite when given a guid. * - * @param int $guid Guid of ElggSite entity + * @param mixed $guid GUID of ElggSite entity or database row object * * @return bool * @throws InvalidClassException @@ -118,6 +122,11 @@ class ElggSite extends ElggEntity { return false; } + // Only work with GUID from here + if ($guid instanceof stdClass) { + $guid = $guid->guid; + } + // Check the type if ($this->attributes['type'] != 'site') { $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class())); @@ -192,7 +201,7 @@ class ElggSite extends ElggEntity { * * @note You cannot disable the current site. * - * @param string $reason Optional reason for disabling + * @param string $reason Optional reason for disabling * @param bool $recursive Recursively disable all contained entities? * * @return bool @@ -215,7 +224,7 @@ class ElggSite extends ElggEntity { * accepted by elgg_get_entities(). Common parameters * include 'limit', and 'offset'. * Note: this was $limit before version 1.8 - * @param int $offset Offset @deprecated parameter + * @param int $offset Offset @deprecated parameter * * @todo remove $offset in 2.0 * @@ -231,6 +240,7 @@ class ElggSite extends ElggEntity { } $defaults = array( + 'site_guids' => ELGG_ENTITIES_ANY_VALUE, 'relationship' => 'member_of_site', 'relationship_guid' => $this->getGUID(), 'inverse_relationship' => TRUE, @@ -254,6 +264,7 @@ class ElggSite extends ElggEntity { */ public function listMembers($options = array()) { $defaults = array( + 'site_guids' => ELGG_ENTITIES_ANY_VALUE, 'relationship' => 'member_of_site', 'relationship_guid' => $this->getGUID(), 'inverse_relationship' => TRUE, diff --git a/engine/classes/ElggUser.php b/engine/classes/ElggUser.php index a1c7147a5..d7bb89265 100644 --- a/engine/classes/ElggUser.php +++ b/engine/classes/ElggUser.php @@ -6,6 +6,15 @@ * * @package Elgg.Core * @subpackage DataModel.User + * + * @property string $name The display name that the user will be known by in the network + * @property string $username The short, reference name for the user in the network + * @property string $email The email address to which Elgg will send email notifications + * @property string $language The language preference of the user (ISO 639-1 formatted) + * @property string $banned 'yes' if the user is banned from the network, 'no' otherwise + * @property string $admin 'yes' if the user is an administrator of the network, 'no' otherwise + * @property string $password The hashed password of the user + * @property string $salt The salt used to secure the password before hashing */ class ElggUser extends ElggEntity implements Friendable { @@ -38,7 +47,7 @@ class ElggUser extends ElggEntity * 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. + * If an entity table db row then will load the rest of the data. * * @throws Exception if there was a problem creating the user. */ @@ -49,15 +58,15 @@ class ElggUser extends ElggEntity $this->initialise_attributes(false); if (!empty($guid)) { - // Is $guid is a DB row - either a entity row, or a user table row. + // Is $guid is a DB entity row if ($guid instanceof stdClass) { // Load the rest - if (!$this->load($guid->guid)) { + if (!$this->load($guid)) { $msg = elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid->guid)); throw new IOException($msg); } - // See if this is a username + // See if this is a username } else if (is_string($guid)) { $user = get_user_by_username($guid); if ($user) { @@ -66,7 +75,7 @@ class ElggUser extends ElggEntity } } - // Is $guid is an ElggUser? Use a copy constructor + // 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); @@ -74,11 +83,11 @@ class ElggUser extends ElggEntity $this->attributes[$key] = $value; } - // Is this is an ElggEntity but not an ElggUser = ERROR! + // 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 + // Is it a GUID } else if (is_numeric($guid)) { if (!$this->load($guid)) { throw new IOException(elgg_echo('IOException:FailedToLoadGUID', array(get_class(), $guid))); @@ -90,13 +99,11 @@ class ElggUser extends ElggEntity } /** - * 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. + * Load the ElggUser data from the database * - * @param int $guid ElggUser GUID + * @param mixed $guid ElggUser GUID or stdClass database row from entity table * - * @return true|false + * @return bool */ protected function load($guid) { // Test to see if we have the generic stuff @@ -104,6 +111,11 @@ class ElggUser extends ElggEntity return false; } + // Only work with GUID from here + if ($guid instanceof stdClass) { + $guid = $guid->guid; + } + // Check the type if ($this->attributes['type'] != 'user') { $msg = elgg_echo('InvalidClassException:NotValidElggStar', array($guid, get_class())); @@ -132,7 +144,7 @@ class ElggUser extends ElggEntity /** * Saves this user to the database. * - * @return true|false + * @return bool */ public function save() { // Save generic stuff @@ -252,7 +264,7 @@ class ElggUser extends ElggEntity * @param int $limit The number of results to return * @param int $offset Any indexing offset * - * @return bool + * @return array */ function getSites($subtype = "", $limit = 10, $offset = 0) { return get_user_sites($this->getGUID(), $subtype, $limit, $offset); @@ -263,7 +275,7 @@ class ElggUser extends ElggEntity * * @param int $site_guid The guid of the site to add it to * - * @return true|false + * @return bool */ function addToSite($site_guid) { return add_site_user($site_guid, $this->getGUID()); @@ -274,7 +286,7 @@ class ElggUser extends ElggEntity * * @param int $site_guid The guid of the site to remove it from * - * @return true|false + * @return bool */ function removeFromSite($site_guid) { return remove_site_user($site_guid, $this->getGUID()); @@ -285,7 +297,7 @@ class ElggUser extends ElggEntity * * @param int $friend_guid The GUID of the user to add * - * @return true|false Depending on success + * @return bool */ function addFriend($friend_guid) { return user_add_friend($this->getGUID(), $friend_guid); @@ -296,7 +308,7 @@ class ElggUser extends ElggEntity * * @param int $friend_guid The GUID of the user to remove * - * @return true|false Depending on success + * @return bool */ function removeFriend($friend_guid) { return user_remove_friend($this->getGUID(), $friend_guid); @@ -305,8 +317,7 @@ class ElggUser extends ElggEntity /** * Determines whether or not this user is a friend of the currently logged in user * - * - * @return true|false + * @return bool */ function isFriend() { return $this->isFriendOf(elgg_get_logged_in_user_guid()); @@ -317,7 +328,7 @@ class ElggUser extends ElggEntity * * @param int $user_guid The GUID of the user to check against * - * @return true|false + * @return bool */ function isFriendsWith($user_guid) { return user_is_friend($this->getGUID(), $user_guid); @@ -328,7 +339,7 @@ class ElggUser extends ElggEntity * * @param int $user_guid The GUID of the user to check against * - * @return true|false + * @return bool */ function isFriendOf($user_guid) { return user_is_friend($user_guid, $this->getGUID()); @@ -376,7 +387,6 @@ class ElggUser extends ElggEntity 'relationship' => 'friend', 'relationship_guid' => $this->guid, 'limit' => $limit, - 'offset' => get_input('offset', 0), 'full_view' => false, ); @@ -450,7 +460,14 @@ class ElggUser extends ElggEntity * @return array|false */ public function getObjects($subtype = "", $limit = 10, $offset = 0) { - return get_user_objects($this->getGUID(), $subtype, $limit, $offset); + $params = array( + 'type' => 'object', + 'subtype' => $subtype, + 'owner_guid' => $this->getGUID(), + 'limit' => $limit, + 'offset' => $offset + ); + return elgg_get_entities($params); } /** diff --git a/engine/classes/ElggWidget.php b/engine/classes/ElggWidget.php index 0eb83913b..99708f66a 100644 --- a/engine/classes/ElggWidget.php +++ b/engine/classes/ElggWidget.php @@ -115,6 +115,8 @@ class ElggWidget extends ElggObject { $options = array( 'type' => 'object', 'subtype' => 'widget', + 'container_guid' => $this->container_guid, + 'limit' => false, 'private_setting_name_value_pairs' => array( array('name' => 'context', 'value' => $this->getContext()), array('name' => 'column', 'value' => $column) @@ -129,21 +131,60 @@ class ElggWidget extends ElggObject { usort($widgets, create_function('$a,$b','return (int)$a->order > (int)$b->order;')); + // remove widgets from inactive plugins + $widget_types = elgg_get_widget_types($this->context); + $inactive_widgets = array(); + foreach ($widgets as $index => $widget) { + if (!array_key_exists($widget->handler, $widget_types)) { + $inactive_widgets[] = $widget; + unset($widgets[$index]); + } + } + if ($rank == 0) { // top of the column - $this->order = $widgets[0]->order - 10; - } elseif ($rank == count($widgets)) { - // bottom of the column + $this->order = reset($widgets)->order - 10; + } elseif ($rank == (count($widgets) - 1)) { + // bottom of the column of active widgets $this->order = end($widgets)->order + 10; } else { - // reorder widgets that are below - $this->order = $widgets[$rank]->order; - for ($index = $rank; $index < count($widgets); $index++) { - if ($widgets[$index]->guid != $this->guid) { - $widgets[$index]-> order += 10; + // reorder widgets + + // remove the widget that's being moved from the array + foreach ($widgets as $index => $widget) { + if ($widget->guid == $this->guid) { + unset($widgets[$index]); + } + } + + // split the array in two and recombine with the moved widget in middle + $before = array_slice($widgets, 0, $rank); + array_push($before, $this); + $after = array_slice($widgets, $rank); + $widgets = array_merge($before, $after); + ksort($widgets); + $order = 0; + foreach ($widgets as $widget) { + $widget->order = $order; + $order += 10; + } + } + + // put inactive widgets at the bottom + if ($inactive_widgets) { + $bottom = 0; + foreach ($widgets as $widget) { + if ($widget->order > $bottom) { + $bottom = $widget->order; } } + $bottom += 10; + foreach ($inactive_widgets as $widget) { + $widget->order = $bottom; + $bottom += 10; + } } + $this->column = $column; } diff --git a/engine/classes/ODDDocument.php b/engine/classes/ODDDocument.php index 4d185aba5..540c35a3b 100644 --- a/engine/classes/ODDDocument.php +++ b/engine/classes/ODDDocument.php @@ -70,8 +70,8 @@ class ODDDocument implements Iterator { public function addElement(ODD $element) { if (!is_array($this->elements)) { $this->elements = array(); - $this->elements[] = $element; } + $this->elements[] = $element; } /** diff --git a/engine/classes/ODDEntity.php b/engine/classes/ODDEntity.php index ab3a49168..e9bb5da6a 100644 --- a/engine/classes/ODDEntity.php +++ b/engine/classes/ODDEntity.php @@ -32,75 +32,3 @@ class ODDEntity extends ODD { return "entity"; } } - -/** - * ODD Metadata class. - * - * @package Elgg.Core - * @subpackage ODD - */ -class ODDMetaData extends ODD { - - /** - * New ODD metadata - * - * @param unknown_type $uuid Unique ID - * @param unknown_type $entity_uuid Another unique ID - * @param unknown_type $name Name - * @param unknown_type $value Value - * @param unknown_type $type Type - * @param unknown_type $owner_uuid Owner ID - */ - 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); - } - - /** - * Returns 'metadata' - * - * @return 'metadata' - */ - protected function getTagName() { - return "metadata"; - } -} - -/** - * ODD Relationship class. - * - * @package Elgg - * @subpackage Core - */ -class ODDRelationship extends ODD { - - /** - * New ODD Relationship - * - * @param unknown_type $uuid1 First UUID - * @param unknown_type $type Type of telationship - * @param unknown_type $uuid2 Second UUId - */ - function __construct($uuid1, $type, $uuid2) { - parent::__construct(); - - $this->setAttribute('uuid1', $uuid1); - $this->setAttribute('type', $type); - $this->setAttribute('uuid2', $uuid2); - } - - /** - * Returns 'relationship' - * - * @return 'relationship' - */ - protected function getTagName() { - return "relationship"; - } -} diff --git a/engine/classes/ODDMetaData.php b/engine/classes/ODDMetaData.php new file mode 100644 index 000000000..58862e0fb --- /dev/null +++ b/engine/classes/ODDMetaData.php @@ -0,0 +1,39 @@ +<?php +/** + * ODD Metadata class. + * + * @package Elgg.Core + * @subpackage ODD + */ +class ODDMetaData extends ODD { + + /** + * New ODD metadata + * + * @param unknown_type $uuid Unique ID + * @param unknown_type $entity_uuid Another unique ID + * @param unknown_type $name Name + * @param unknown_type $value Value + * @param unknown_type $type Type + * @param unknown_type $owner_uuid Owner ID + */ + 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); + } + + /** + * Returns 'metadata' + * + * @return 'metadata' + */ + protected function getTagName() { + return "metadata"; + } +} diff --git a/engine/classes/ODDRelationship.php b/engine/classes/ODDRelationship.php new file mode 100644 index 000000000..2906b1c73 --- /dev/null +++ b/engine/classes/ODDRelationship.php @@ -0,0 +1,33 @@ +<?php +/** + * ODD Relationship class. + * + * @package Elgg + * @subpackage Core + */ +class ODDRelationship extends ODD { + + /** + * New ODD Relationship + * + * @param unknown_type $uuid1 First UUID + * @param unknown_type $type Type of telationship + * @param unknown_type $uuid2 Second UUId + */ + function __construct($uuid1, $type, $uuid2) { + parent::__construct(); + + $this->setAttribute('uuid1', $uuid1); + $this->setAttribute('type', $type); + $this->setAttribute('uuid2', $uuid2); + } + + /** + * Returns 'relationship' + * + * @return 'relationship' + */ + protected function getTagName() { + return "relationship"; + } +} diff --git a/engine/classes/SuccessResult.php b/engine/classes/SuccessResult.php index c8578a2cf..ab5468ad8 100644 --- a/engine/classes/SuccessResult.php +++ b/engine/classes/SuccessResult.php @@ -15,7 +15,7 @@ class SuccessResult extends GenericResult { * * @param string $result The result */ - public function SuccessResult($result) { + public function __construct($result) { $this->setResult($result); $this->setStatusCode(SuccessResult::$RESULT_SUCCESS); } diff --git a/engine/classes/XMLRPCCall.php b/engine/classes/XMLRPCCall.php index 8eeba0c29..fd28f1e3e 100644 --- a/engine/classes/XMLRPCCall.php +++ b/engine/classes/XMLRPCCall.php @@ -18,7 +18,7 @@ class XMLRPCCall { * @param string $xml XML */ function __construct($xml) { - $this->_parse($xml); + $this->parse($xml); } /** @@ -45,7 +45,7 @@ class XMLRPCCall { * * @return void */ - private function _parse($xml) { + private function parse($xml) { $xml = xml_to_object($xml); // sanity check diff --git a/engine/handlers/cache_handler.php b/engine/handlers/cache_handler.php index 94a0e64e9..b332ec379 100644 --- a/engine/handlers/cache_handler.php +++ b/engine/handlers/cache_handler.php @@ -60,26 +60,31 @@ preg_match($regex, $request, $matches); $type = $matches[1]; $viewtype = $matches[2]; $view = $matches[3]; +$ts = $matches[4]; + +// If is the same ETag, content didn't changed. +$etag = $ts; +if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag) { + header("HTTP/1.1 304 Not Modified"); + exit; +} switch ($type) { case 'css': header("Content-type: text/css", true); - header('Expires: ' . date('r', strtotime("+6 months")), true); - header("Pragma: public", true); - header("Cache-Control: public", true); - $view = "css/$view"; break; case 'js': header('Content-type: text/javascript', true); - header('Expires: ' . date('r', strtotime("+6 months")), true); - header("Pragma: public", true); - header("Cache-Control: public", true); - $view = "js/$view"; break; } +header('Expires: ' . date('r', strtotime("+6 months")), true); +header("Pragma: public", true); +header("Cache-Control: public", true); +header("ETag: $etag"); + $filename = $dataroot . 'views_simplecache/' . md5($viewtype . $view); if (file_exists($filename)) { diff --git a/engine/handlers/export_handler.php b/engine/handlers/export_handler.php index b91a037e8..aa5214c23 100644 --- a/engine/handlers/export_handler.php +++ b/engine/handlers/export_handler.php @@ -72,8 +72,10 @@ if (($guid != "") && ($type == "") && ($id_or_name == "")) { $r = get_relationship($id_or_name); break; case 'volatile' : - $m = elgg_trigger_plugin_hook('volatile', 'metadata', - array('guid' => $guid, 'varname' => $id_or_name)); + $m = elgg_trigger_plugin_hook('volatile', 'metadata', array( + 'guid' => $guid, + 'varname' => $id_or_name, + )); break; default : diff --git a/engine/lib/access.php b/engine/lib/access.php index 08b9283cd..6be252c6a 100644 --- a/engine/lib/access.php +++ b/engine/lib/access.php @@ -671,8 +671,10 @@ function add_user_to_access_collection($user_guid, $collection_id) { 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}"; + 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; @@ -838,7 +840,7 @@ function elgg_list_entities_from_access_id(array $options = array()) { * * @param int $entity_access_id The entity's access id * - * @return string 'Public', 'Private', etc. or false if error. + * @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. @@ -849,15 +851,12 @@ function get_readable_access_level($entity_access_id) { //get the access level for object in readable string $options = get_write_access_array(); - //@todo Really? Use array_key_exists() - 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'); } /** @@ -987,9 +986,9 @@ function elgg_override_permissions($hook, $type, $value, $params) { } // don't do this so ignore access still works with no one logged in -// if (!$user instanceof ElggUser) { -// return false; -// } + //if (!$user instanceof ElggUser) { + // return false; + //} // check for admin if ($user_guid && elgg_is_admin_user($user_guid)) { diff --git a/engine/lib/actions.php b/engine/lib/actions.php index f415842ab..c6613e6d6 100644 --- a/engine/lib/actions.php +++ b/engine/lib/actions.php @@ -459,8 +459,7 @@ function ajax_forward_hook($hook, $type, $reason, $params) { // however some browsers will not accept the JSON MIME type. if (stripos($_SERVER['HTTP_ACCEPT'], 'application/json') === FALSE) { header("Content-type: text/plain"); - } - else { + } else { header("Content-type: application/json"); } diff --git a/engine/lib/admin.php b/engine/lib/admin.php index a191d740b..928101fc5 100644 --- a/engine/lib/admin.php +++ b/engine/lib/admin.php @@ -79,6 +79,10 @@ function elgg_add_admin_notice($id, $message) { if (elgg_admin_notice_exists($id)) { return false; } + + // need to handle when no one is logged in + $old_ia = elgg_set_ignore_access(true); + $admin_notice = new ElggObject(); $admin_notice->subtype = 'admin_notice'; // admins can see ACCESS_PRIVATE but no one else can. @@ -86,13 +90,16 @@ function elgg_add_admin_notice($id, $message) { $admin_notice->admin_notice_id = $id; $admin_notice->description = $message; - return $admin_notice->save(); + $result = $admin_notice->save(); + + elgg_set_ignore_access($old_ia); + + return (bool)$result; } - return FALSE; + return false; } - /** * Remove an admin notice by ID. * @@ -172,10 +179,10 @@ function elgg_admin_notice_exists($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 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 * * @return bool * @since 1.8.0 @@ -255,6 +262,7 @@ function admin_init() { // 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'); // users elgg_register_admin_menu_item('administer', 'users', null, 20); diff --git a/engine/lib/annotations.php b/engine/lib/annotations.php index bfd40d1e8..f32dee0f0 100644 --- a/engine/lib/annotations.php +++ b/engine/lib/annotations.php @@ -163,13 +163,9 @@ function update_annotation($annotation_id, $name, $value, $value_type, $owner_gu 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); - if (elgg_trigger_event('update', 'annotation', $obj)) { - return true; - } else { - // @todo add plugin hook that sends old and new annotation information before db access - elgg_delete_annotation_by_id($annotation_id); - } + elgg_trigger_event('update', 'annotation', $obj); } return $result; @@ -183,21 +179,23 @@ function update_annotation($annotation_id, $name, $value, $value_type, $owner_gu * * @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_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. * - * 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. * * @return mixed * @since 1.8.0 @@ -211,9 +209,11 @@ function elgg_get_annotations(array $options = array()) { * 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 mixed + * @return mixed Null if the metadata name is invalid. Bool on success or fail. * @since 1.8.0 */ function elgg_delete_annotations(array $options) { @@ -239,7 +239,7 @@ function elgg_disable_annotations(array $options) { return false; } - $options['metastrings_type'] = 'annotations'; + $options['metastring_type'] = 'annotations'; return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback'); } @@ -388,8 +388,14 @@ function elgg_list_entities_from_annotations($options = array()) { * Get entities ordered by a mathematical calculation on annotation values * * @param array $options An options array: - * 'annotation_calculation' => The calculation to use. Must be a valid MySQL function. + * '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. @@ -545,8 +551,8 @@ function elgg_comment_url_handler(ElggAnnotation $comment) { /** * 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 */ diff --git a/engine/lib/cache.php b/engine/lib/cache.php index a6ebe2a30..c117b9ec9 100644 --- a/engine/lib/cache.php +++ b/engine/lib/cache.php @@ -10,15 +10,14 @@ /* Filepath Cache */ /** - * Returns an ElggCache object suitable for caching view - * file load paths to disk under $CONFIG->dataroot. + * Returns an ElggCache object suitable for caching system information * * @todo Can this be done in a cleaner way? * @todo Swap to memcache etc? * - * @return ElggFileCache A cache object suitable for caching file load paths. + * @return ElggFileCache */ -function elgg_get_filepath_cache() { +function elgg_get_system_cache() { global $CONFIG; /** @@ -27,35 +26,34 @@ function elgg_get_filepath_cache() { static $FILE_PATH_CACHE; if (!$FILE_PATH_CACHE) { - $FILE_PATH_CACHE = new ElggFileCache($CONFIG->dataroot); + $FILE_PATH_CACHE = new ElggFileCache($CONFIG->dataroot . 'system_cache/'); } return $FILE_PATH_CACHE; } /** - * Function which resets the file path cache. + * Reset the system cache by deleting the caches * + * @return void */ -function elgg_filepath_cache_reset() { - $cache = elgg_get_filepath_cache(); - $view_types_result = $cache->delete('view_types'); - $views_result = $cache->delete('views'); - return $view_types_result && $views_result; +function elgg_reset_system_cache() { + $cache = elgg_get_system_cache(); + $cache->clear(); } /** - * Saves a filepath cache. + * Saves a system cache. * - * @param string $type - * @param string $data + * @param string $type The type or identifier of the cache + * @param string $data The data to be saved * @return bool */ -function elgg_filepath_cache_save($type, $data) { +function elgg_save_system_cache($type, $data) { global $CONFIG; - if ($CONFIG->viewpath_cache_enabled) { - $cache = elgg_get_filepath_cache(); + if ($CONFIG->system_cache_enabled) { + $cache = elgg_get_system_cache(); return $cache->save($type, $data); } @@ -63,16 +61,16 @@ function elgg_filepath_cache_save($type, $data) { } /** - * Retrieve the contents of the filepath cache. + * Retrieve the contents of a system cache. * * @param string $type The type of cache to load * @return string */ -function elgg_filepath_cache_load($type) { +function elgg_load_system_cache($type) { global $CONFIG; - if ($CONFIG->viewpath_cache_enabled) { - $cache = elgg_get_filepath_cache(); + if ($CONFIG->system_cache_enabled) { + $cache = elgg_get_system_cache(); $cached_data = $cache->load($type); if ($cached_data) { @@ -84,35 +82,74 @@ function elgg_filepath_cache_load($type) { } /** - * Enables the views file paths disk cache. + * Enables the system disk cache. * - * Uses the 'viewpath_cache_enabled' datalist with a boolean value. - * Resets the views paths cache. + * Uses the 'system_cache_enabled' datalist with a boolean value. + * Resets the system cache. * * @return void */ -function elgg_enable_filepath_cache() { +function elgg_enable_system_cache() { global $CONFIG; - datalist_set('viewpath_cache_enabled', 1); - $CONFIG->viewpath_cache_enabled = 1; - elgg_filepath_cache_reset(); + datalist_set('system_cache_enabled', 1); + $CONFIG->system_cache_enabled = 1; + elgg_reset_system_cache(); } /** - * Disables the views file paths disk cache. + * Disables the system disk cache. * - * Uses the 'viewpath_cache_enabled' datalist with a boolean value. - * Resets the views paths cache. + * Uses the 'system_cache_enabled' datalist with a boolean value. + * Resets the system cache. * * @return void */ -function elgg_disable_filepath_cache() { +function elgg_disable_system_cache() { global $CONFIG; - datalist_set('viewpath_cache_enabled', 0); - $CONFIG->viewpath_cache_enabled = 0; - elgg_filepath_cache_reset(); + datalist_set('system_cache_enabled', 0); + $CONFIG->system_cache_enabled = 0; + elgg_reset_system_cache(); +} + +/** @todo deprecate in Elgg 1.9 **/ + +/** + * @access private + */ +function elgg_get_filepath_cache() { + return elgg_get_system_cache(); +} +/** + * @access private + */ +function elgg_filepath_cache_reset() { + return 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() { + return elgg_enable_system_cache(); +} +/** + * @access private + */ +function elgg_disable_filepath_cache() { + return elgg_disable_system_cache(); } /* Simplecache */ @@ -332,7 +369,7 @@ function elgg_invalidate_simplecache() { $return = true; while (false !== ($file = readdir($handle))) { if ($file != "." && $file != "..") { - $return = $return && unlink($CONFIG->dataroot . 'views_simplecache/' . $file); + $return &= unlink($CONFIG->dataroot . 'views_simplecache/' . $file); } } closedir($handle); @@ -345,9 +382,70 @@ function elgg_invalidate_simplecache() { } foreach ($viewtypes as $viewtype) { - $return = $return && datalist_set("simplecache_lastupdate_$viewtype", 0); - $return = $return && datalist_set("simplecache_lastcached_$viewtype", 0); + $return &= datalist_set("simplecache_lastupdate_$viewtype", 0); + $return &= datalist_set("simplecache_lastcached_$viewtype", 0); } return $return; } + +/** + * @see elgg_reset_system_cache() + * @access private + */ +function _elgg_load_cache() { + global $CONFIG; + + $CONFIG->system_cache_loaded = false; + + $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); + + $CONFIG->system_cache_loaded = true; +} + +/** + * @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; + } + + // 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)); + } + + if ($CONFIG->system_cache_enabled && !$CONFIG->i18n_loaded_from_cache) { + foreach ($CONFIG->translations as $lang => $map) { + elgg_save_system_cache("$lang.php", serialize($map)); + } + } +} + +elgg_register_event_handler('ready', 'system', '_elgg_cache_init'); diff --git a/engine/lib/configuration.php b/engine/lib/configuration.php index 615063f3d..9bf1529d6 100644 --- a/engine/lib/configuration.php +++ b/engine/lib/configuration.php @@ -3,8 +3,9 @@ * Elgg configuration procedural code. * * Includes functions for manipulating the configuration values stored in the database - * Plugin authors should use the {@link get_config()}, {@link set_config()}, - * and {@unset_config()} functions to access or update config values. + * 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 @@ -302,7 +303,7 @@ function datalist_set($name, $value) { . " set name = '{$sanitised_name}', value = '{$sanitised_value}'" . " ON DUPLICATE KEY UPDATE value='{$sanitised_value}'"); - if ($success) { + if ($success !== FALSE) { $DATALIST_CACHE[$name] = $value; return true; } else { @@ -517,10 +518,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; @@ -533,37 +534,49 @@ function get_all_config($site_guid = 0) { } /** - * Sets defaults for or attempts to autodetect some common config values and - * loads them into $CONFIG. + * Loads configuration related to this site * - * @return true + * This loads from the config database table and the site entity * @access private */ -function set_default_config() { +function _elgg_load_site_config() { global $CONFIG; - $install_root = str_replace("\\", "/", dirname(dirname(dirname(__FILE__)))); - - // @todo this seldom works right. - $pathpart = str_replace("//", "/", str_replace($_SERVER['DOCUMENT_ROOT'], "", $install_root)); - if (substr($pathpart, 0, 1) != "/") { - $pathpart = "/" . $pathpart; + $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')); } - $www_root = "http://" . $_SERVER['HTTP_HOST'] . $pathpart; + $CONFIG->wwwroot = $CONFIG->site->url; + $CONFIG->sitename = $CONFIG->site->name; + $CONFIG->sitedescription = $CONFIG->site->description; + $CONFIG->siteemail = $CONFIG->site->email; + $CONFIG->url = $CONFIG->wwwroot; + + get_all_config(); +} + +/** + * Loads configuration related to Elgg as an application + * + * This loads from the datalists database table + * @access private + */ +function _elgg_load_application_config() { + global $CONFIG; + + $install_root = str_replace("\\", "/", dirname(dirname(dirname(__FILE__)))); $defaults = array( 'path' => "$install_root/", 'view_path' => "$install_root/views/", 'plugins_path' => "$install_root/mod/", - 'wwwroot' => $www_root, - 'url' => $www_root, - 'site_name' => 'New Elgg site', 'language' => 'en', - // compatibility with old names for ppl not using get_config() + // compatibility with old names for plugins not using elgg_get_config() 'viewpath' => "$install_root/views/", 'pluginspath' => "$install_root/mod/", - 'sitename' => 'New Elgg site', ); foreach ($defaults as $name => $value) { @@ -572,25 +585,6 @@ function set_default_config() { } } - $CONFIG->context = array(); - - return true; -} - -/** - * Loads values into $CONFIG. - * - * If Elgg is installed, this function pulls all rows from dbprefix_config - * and cherry picks some values from dbprefix_datalists. This also extracts - * some commonly used values from the default site object. - * - * @elgg_event boot system - * @return true|null - * @access private - */ -function configuration_boot() { - global $CONFIG; - $path = datalist_get('path'); if (!empty($path)) { $CONFIG->path = $path; @@ -605,22 +599,23 @@ function configuration_boot() { } 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; + $system_cache_enabled = datalist_get('system_cache_enabled'); + if ($system_cache_enabled !== false) { + $CONFIG->system_cache_enabled = $system_cache_enabled; } else { - $CONFIG->viewpath_cache_enabled = 1; + $CONFIG->system_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; - // Load default settings from database - get_all_config(); -} + // initialize context here so it is set before the get_input call + $CONFIG->context = array(); + + // 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; -elgg_register_event_handler('boot', 'system', 'configuration_boot', 10); + $CONFIG->i18n_loaded_from_cache = false; + + // this must be synced with the enum for the entities table + $CONFIG->entity_types = array('group', 'object', 'site', 'user'); +} diff --git a/engine/lib/database.php b/engine/lib/database.php index c44fdf1fd..cc2b99f6a 100644 --- a/engine/lib/database.php +++ b/engine/lib/database.php @@ -189,22 +189,6 @@ function db_delayedexecution_shutdown_hook() { } /** - * Registers shutdown functions for database profiling and delayed queries. - * - * @note Database connections are established upon first call to database. - * - * @return true - * @elgg_event_handler boot system - * @access private - */ -function init_db() { - register_shutdown_function('db_delayedexecution_shutdown_hook'); - register_shutdown_function('db_profiling_shutdown_hook'); - - return true; -} - -/** * Returns (if required, also creates) a database link resource. * * Database link resources are stored in the {@link $dblink} global. These @@ -728,9 +712,9 @@ function sanitize_string($string) { /** * Sanitises an integer for database use. * - * @param int $int Integer - * @param bool[optional] $signed Whether negative values should be allowed (true) - * @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, $signed = true) { $int = (int) $int; @@ -745,18 +729,25 @@ function sanitise_int($int, $signed = true) { } /** - * Sanitises an integer for database use. + * Sanitizes an integer for database use. * Wrapper function for alternate English spelling (@see sanitise_int) * - * @param int $int Integer - * @param bool[optional] $signed Whether negative values should be allowed (true) - * @return int Sanitised integer + * @param int $int Value to be sanitized + * @param bool $signed Whether negative values should be allowed (true) + * @return int */ function sanitize_int($int, $signed = true) { return sanitise_int($int, $signed); } /** - * @elgg_register_event boot system init_db + * Registers shutdown functions for database profiling and delayed queries. + * + * @access private */ -elgg_register_event_handler('boot', 'system', 'init_db', 0); +function init_db() { + register_shutdown_function('db_delayedexecution_shutdown_hook'); + register_shutdown_function('db_profiling_shutdown_hook'); +} + +elgg_register_event_handler('init', 'system', 'init_db'); diff --git a/engine/lib/deprecated-1.8.php b/engine/lib/deprecated-1.8.php index e1866498b..4b9d41543 100644 --- a/engine/lib/deprecated-1.8.php +++ b/engine/lib/deprecated-1.8.php @@ -1674,7 +1674,7 @@ function get_plugin_list() { * otherwise you may experience view display artifacts. Do this with the following code: * * elgg_regenerate_simplecache(); - * elgg_filepath_cache_reset(); + * elgg_reset_system_cache(); * * @deprecated 1.8 Use elgg_generate_plugin_entities() and elgg_set_plugin_priorities() * @@ -1841,7 +1841,7 @@ function get_installed_plugins($status = 'all') { * otherwise you may experience view display artifacts. Do this with the following code: * * elgg_regenerate_simplecache(); - * elgg_filepath_cache_reset(); + * elgg_reset_system_cache(); * * @deprecated 1.8 Use ElggPlugin->activate() * @@ -1882,7 +1882,7 @@ function enable_plugin($plugin, $site_guid = null) { * otherwise you may experience view display artifacts. Do this with the following code: * * elgg_regenerate_simplecache(); - * elgg_filepath_cache_reset(); + * elgg_reset_system_cache(); * * @deprecated 1.8 Use ElggPlugin->deactivate() * diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index 57d602450..11bdc7285 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -995,7 +995,8 @@ function elgg_trigger_plugin_hook($hook, $type, $params = null, $returnvalue = n * @access private */ function _elgg_php_exception_handler($exception) { - error_log("*** FATAL EXCEPTION *** : " . $exception); + $timestamp = time(); + error_log("Exception #$timestamp: $exception"); // Wipe any existing output buffer ob_end_clean(); @@ -1011,7 +1012,17 @@ function _elgg_php_exception_handler($exception) { $CONFIG->pagesetupdone = true; elgg_set_viewtype('failsafe'); - $body = elgg_view("messages/exceptions/exception", array('object' => $exception)); + 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(); @@ -1144,9 +1155,11 @@ 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); + $params = array( + 'level' => $level, + 'msg' => $value, + 'to_screen' => $to_screen, + ); if (!elgg_trigger_plugin_hook('debug', 'log', $params, true)) { return; } @@ -1172,7 +1185,9 @@ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') { * * 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'. + * 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(). * * 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 @@ -1183,11 +1198,12 @@ function elgg_dump($value, $to_screen = TRUE, $level = 'NOTICE') { * * @see CODING.txt * - * @param str $msg Message to log / display. - * @param str $dep_version Human-readable *release* version: 1.7, 1.7.3 - * @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. + * @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 @@ -1196,13 +1212,13 @@ function elgg_deprecated_notice($msg, $dep_version, $backtrace_level = 1) { // if it's a major release behind, visual and logged // if it's a 1 minor release behind, visual and logged // if it's for current minor release, logged. - // bugfixes don't matter because you're not deprecating between them, RIGHT? + // 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 = (int)$elgg_version_arr[0]; $elgg_minor_version = (int)$elgg_version_arr[1]; @@ -1210,16 +1226,16 @@ function elgg_deprecated_notice($msg, $dep_version, $backtrace_level = 1) { $dep_major_version = (int)$dep_version; $dep_minor_version = 10 * ($dep_version - $dep_major_version); - $visual = FALSE; + $visual = false; if (($dep_major_version < $elgg_major_version) || ($dep_minor_version < $elgg_minor_version)) { - $visual = TRUE; + $visual = true; } $msg = "Deprecated in $dep_major_version.$dep_minor_version: $msg"; - if ($visual) { + if ($visual && elgg_is_admin_logged_in()) { register_error($msg); } @@ -1247,9 +1263,9 @@ function elgg_deprecated_notice($msg, $dep_version, $backtrace_level = 1) { $msg .= implode("<br /> -> ", $stack); - elgg_log($msg, 'WARNING'); + elgg_dump($msg, elgg_is_admin_logged_in(), 'WARNING'); - return TRUE; + return true; } /** @@ -1772,6 +1788,12 @@ function elgg_ajax_page_handler($page) { unset($page[0]); $view = implode('/', $page); + $allowed_views = elgg_get_config('allowed_ajax_views'); + if (!array_key_exists($view, $allowed_views)) { + header('HTTP/1.1 403 Forbidden'); + exit; + } + // pull out GET parameters through filter $vars = array(); foreach ($_GET as $name => $value) { @@ -1948,7 +1970,7 @@ function elgg_is_valid_options_for_batch_operation($options, $type) { // at least one of these is required. $required = array( // generic restraints - 'guid', 'guids', 'limit' + 'guid', 'guids' ); switch ($type) { @@ -1996,9 +2018,7 @@ function elgg_is_valid_options_for_batch_operation($options, $type) { * @access private */ function elgg_walled_garden_index() { - elgg_register_css('elgg.walled_garden', '/css/walled_garden.css'); elgg_load_css('elgg.walled_garden'); - elgg_register_js('elgg.walled_garden', '/js/walled_garden.js'); elgg_load_js('elgg.walled_garden'); $body = elgg_view('core/walled_garden/body'); @@ -2026,6 +2046,9 @@ function elgg_walled_garden_index() { 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'); + // check for external page view if (isset($CONFIG->site) && $CONFIG->site instanceof ElggSite) { $CONFIG->site->checkWalledGarden(); @@ -2033,6 +2056,36 @@ function elgg_walled_garden() { } /** + * Boots the engine + * + * 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_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(); + + register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/"); + + _elgg_load_site_config(); + + _elgg_load_cache(); +} + +/** * Elgg's main init. * * Handles core actions for comments, the JS pagehandler, and the shutdown function. @@ -2155,6 +2208,7 @@ define('REFERRER', -1); define('REFERER', -1); 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'); elgg_register_event_handler('init', 'system', 'add_custom_menu_items', 1000); diff --git a/engine/lib/entities.php b/engine/lib/entities.php index daced6740..4875b2c2f 100644 --- a/engine/lib/entities.php +++ b/engine/lib/entities.php @@ -738,6 +738,7 @@ function elgg_entity_exists($guid) { * 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 @@ -923,7 +924,7 @@ function elgg_get_entities(array $options = array()) { } if ($options['limit']) { - $limit = sanitise_int($options['limit']); + $limit = sanitise_int($options['limit'], false); $offset = sanitise_int($options['offset'], false); $query .= " LIMIT $offset, $limit"; } @@ -960,8 +961,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(); @@ -1378,34 +1379,33 @@ function disable_entity($guid, $reason = "", $recursive = true) { } 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(elgg_get_logged_in_user_guid()); - - $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(); - // relationships can't be disabled. hope they join to the entities table. - //$entity->disableRelationships(); $res = update_data("UPDATE {$CONFIG->dbprefix}entities - set enabled='no' - where guid={$guid}"); + SET enabled = 'no' + WHERE guid = $guid"); return $res; } @@ -1420,40 +1420,51 @@ function disable_entity($guid, $reason = "", $recursive = true) { * @warning In order to enable an entity using ElggEntity::enable(), * you must first use {@link access_show_hidden_entities()}. * - * @param int $guid GUID of entity to enable + * @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 (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}"); + 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, + )); + + 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; } /** @@ -1510,18 +1521,23 @@ function delete_entity($guid, $recursive = true) { $entity_disable_override = 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", 'entity_row_to_elggstar'); - if ($sub_entities) { - foreach ($sub_entities as $e) { - // check for equality so that an entity that is its own - // owner or container does not cause infinite loop - if ($e->guid != $guid) { - $e->delete(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); @@ -1955,7 +1971,7 @@ function elgg_register_entity_type($type, $subtype = null) { global $CONFIG; $type = strtolower($type); - if (!in_array($type, array('object', 'site', 'group', 'user'))) { + if (!in_array($type, $CONFIG->entity_types)) { return FALSE; } @@ -1990,7 +2006,7 @@ function unregister_entity_type($type, $subtype) { global $CONFIG; $type = strtolower($type); - if (!in_array($type, array('object', 'site', 'group', 'user'))) { + if (!in_array($type, $CONFIG->entity_types)) { return FALSE; } @@ -2158,31 +2174,8 @@ function elgg_list_registered_entities(array $options = array()) { $entities = array(); } - return elgg_view_entity_list($entities, $count, $options['offset'], - $options['limit'], $options['full_view'], $options['list_type_toggle'], $options['pagination']); -} - -/** - * Check the recursive delete permissions token. - * - * If an entity is deleted recursively, a permissions override is required to allow - * contained or owned entities to be removed. - * - * @return bool - * @elgg_plugin_hook_handler permissions_check all - * @elgg_plugin_hook_handler permissions_check:metadata all - * @access private - */ -function recursive_delete_permissions_check() { - static $__RECURSIVE_DELETE_TOKEN; - - if ((elgg_is_logged_in()) && ($__RECURSIVE_DELETE_TOKEN) - && (strcmp($__RECURSIVE_DELETE_TOKEN, md5(elgg_get_logged_in_user_guid())))) { - return true; - } - - // consult next function - return NULL; + $options['count'] = $count; + return elgg_view_entity_list($entities, $options); } /** @@ -2299,11 +2292,6 @@ function entities_init() { elgg_register_plugin_hook_handler('unit_test', 'system', 'entities_test'); - // Allow a permission override for recursive entity deletion - // @todo Can this be done better? - elgg_register_plugin_hook_handler('permissions_check', 'all', 'recursive_delete_permissions_check'); - elgg_register_plugin_hook_handler('permissions_check:metadata', 'all', 'recursive_delete_permissions_check'); - elgg_register_plugin_hook_handler('gc', 'system', 'entities_gc'); } @@ -2318,3 +2306,4 @@ elgg_register_plugin_hook_handler('volatile', 'metadata', 'volatile_data_export_ /** Register init system event **/ elgg_register_event_handler('init', 'system', 'entities_init'); + diff --git a/engine/lib/extender.php b/engine/lib/extender.php index 51fc62c30..ffd3c1357 100644 --- a/engine/lib/extender.php +++ b/engine/lib/extender.php @@ -164,9 +164,9 @@ function can_edit_extender($extender_id, $type, $user_guid = 0) { * 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 ('annotation', 'metadata') * @param string $extender_name The name of the extender + * @param string $function_name The function to register * * @return bool */ diff --git a/engine/lib/filestore.php b/engine/lib/filestore.php index a13d8aa27..86f6d9baa 100644 --- a/engine/lib/filestore.php +++ b/engine/lib/filestore.php @@ -18,7 +18,7 @@ */ function get_dir_size($dir, $totalsize = 0) { $handle = @opendir($dir); - while ($file = @readdir ($handle)) { + while ($file = @readdir($handle)) { if (eregi("^\.{1,2}$", $file)) { continue; } diff --git a/engine/lib/group.php b/engine/lib/group.php index 29330eeca..feb1f1e7f 100644 --- a/engine/lib/group.php +++ b/engine/lib/group.php @@ -261,16 +261,24 @@ function group_gatekeeper($forward = true) { if ($group = elgg_get_page_owner_entity()) { if ($group instanceof ElggGroup) { $url = $group->getURL(); - if ( - ((!elgg_is_logged_in()) && (!$group->isPublicMembership())) || - ((!$group->isMember(elgg_get_logged_in_user_entity()) && (!$group->isPublicMembership()))) - ) { - $allowed = false; - } + if (!$group->isPublicMembership()) { + // closed group so must be member or an admin + + if (!elgg_is_logged_in()) { + $allowed = false; + if ($forward == true) { + $_SESSION['last_forward_from'] = current_page_url(); + register_error(elgg_echo('loggedinrequired')); + forward('', 'login'); + } + } else if (!$group->isMember(elgg_get_logged_in_user_entity())) { + $allowed = false; + } - // Admin override - if (elgg_is_admin_logged_in()) { - $allowed = true; + // Admin override + if (elgg_is_admin_logged_in()) { + $allowed = true; + } } } } diff --git a/engine/lib/input.php b/engine/lib/input.php index 57e35786f..dda8211b6 100644 --- a/engine/lib/input.php +++ b/engine/lib/input.php @@ -188,8 +188,8 @@ function elgg_get_sticky_value($form_name, $variable = '', $default = NULL, $fil /** * Get all the values in a sticky form in an array * - * @param string $form_name The name of the form - * @param bool $filter_result Filter for bad input if true + * @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 diff --git a/engine/lib/languages.php b/engine/lib/languages.php index 0400843af..bf6829a39 100644 --- a/engine/lib/languages.php +++ b/engine/lib/languages.php @@ -145,9 +145,16 @@ function elgg_echo($message_key, $args = array(), $language = "") { function register_translations($path, $load_all = false) { global $CONFIG; + static $load_from_cache; + static $cache_loaded_langs; + if (!isset($load_from_cache)) { + $load_from_cache = $CONFIG->system_cache_enabled; + $cache_loaded_langs = array(); + } + $path = sanitise_filepath($path); - // Make a note of this path just incase we need to register this language later + // Make a note of this path just in case we need to register this language later if (!isset($CONFIG->language_paths)) { $CONFIG->language_paths = array(); } @@ -155,7 +162,6 @@ function register_translations($path, $load_all = false) { // Get the current language based on site defaults and user preference $current_language = get_current_language(); - elgg_log("Translations loaded from: $path"); // only load these files unless $load_all is true. $load_language_files = array( @@ -165,6 +171,32 @@ function register_translations($path, $load_all = false) { $load_language_files = array_unique($load_language_files); + if ($load_from_cache && !$load_all) { + // load language files from cache + $data = array(); + foreach ($load_language_files as $lang_file) { + $lang = substr($lang_file, 0, strpos($lang_file, '.')); + if (!isset($cache_loaded_langs[$lang])) { + $data[$lang] = elgg_load_system_cache($lang_file); + if ($data[$lang]) { + $cache_loaded_langs[$lang] = true; + } else { + // this language file not cached yet + $load_from_cache = false; + } + } + } + + // are we still suppose to load from cache + if ($load_from_cache) { + foreach ($data as $lang => $map) { + add_translation($lang, unserialize($map)); + } + $CONFIG->i18n_loaded_from_cache = true; + return true; + } + } + $handle = opendir($path); if (!$handle) { elgg_log("Could not open language path: $path", 'ERROR'); @@ -186,6 +218,11 @@ function register_translations($path, $load_all = false) { } } + elgg_log("Translations loaded from: $path"); + + // make sure caching code saves language data if system cache is on + $CONFIG->i18n_loaded_from_cache = false; + return $return; } @@ -311,5 +348,3 @@ function elgg_languages_init() { } elgg_register_event_handler('init', 'system', 'elgg_languages_init'); - -register_translations(dirname(dirname(dirname(__FILE__))) . "/languages/"); diff --git a/engine/lib/metadata.php b/engine/lib/metadata.php index 050e69526..34a36d86e 100644 --- a/engine/lib/metadata.php +++ b/engine/lib/metadata.php @@ -216,12 +216,11 @@ function update_metadata($id, $name, $value, $value_type, $owner_guid, $access_i $result = update_data($query); if ($result !== false) { + // @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); - if (elgg_trigger_event('update', 'metadata', $obj)) { - return true; - } else { - elgg_delete_metadata_by_id($id); - } + elgg_trigger_event('update', 'metadata', $obj); } return $result; @@ -270,21 +269,18 @@ $access_id = ACCESS_PRIVATE, $allow_multiple = false) { * * @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. + * 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 mixed * @since 1.8.0 @@ -298,11 +294,11 @@ function elgg_get_metadata(array $options = array()) { * Deletes metadata based on $options. * * @warning Unlike elgg_get_metadata() this will not accept an empty options array! - * This requires some constraints: metadata_owner_guid(s), - * metadata_name(s), metadata_value(s), or limit must be set. + * 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 mixed + * @param array $options An options array. {@see elgg_get_metadata()} + * @return mixed Null if the metadata name is invalid. Bool on success or fail. * @since 1.8.0 */ function elgg_delete_metadata(array $options) { @@ -311,7 +307,8 @@ function elgg_delete_metadata(array $options) { } $options['metastring_type'] = 'metadata'; - return elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback'); + $result = elgg_batch_metastring_based_objects($options, 'elgg_batch_delete_callback'); + return $result; } /** @@ -328,7 +325,7 @@ function elgg_disable_metadata(array $options) { return false; } - $options['metastrings_type'] = 'metadata'; + $options['metastring_type'] = 'metadata'; return elgg_batch_metastring_based_objects($options, 'elgg_batch_disable_callback'); } @@ -403,15 +400,15 @@ function elgg_enable_metadata(array $options) { */ 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); @@ -634,7 +631,7 @@ $owner_guids = NULL) { $i++; } - if ($where = implode (" $pair_operator ", $pair_wheres)) { + if ($where = implode(" $pair_operator ", $pair_wheres)) { $wheres[] = "($where)"; } } @@ -749,7 +746,7 @@ 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 + * which have been trimmed * * @param string $string Comma-separated tag string * @@ -758,12 +755,7 @@ function export_metadata_plugin_hook($hook, $entity_type, $returnvalue, $params) function string_to_tag_array($string) { if (is_string($string)) { $ar = explode(",", $string); - // trim blank spaces $ar = array_map('trim', $ar); - // make lower case : [Marcus Povey 20090605 - Using mb wrapper function - // using UTF8 safe function where available] - $ar = array_map('elgg_strtolower', $ar); - // Remove null values $ar = array_filter($ar, 'is_not_null'); return $ar; } @@ -872,8 +864,8 @@ 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 */ diff --git a/engine/lib/metastrings.php b/engine/lib/metastrings.php index 9fe9b4bff..d7cc4e0bc 100644 --- a/engine/lib/metastrings.php +++ b/engine/lib/metastrings.php @@ -609,8 +609,7 @@ function elgg_get_metastring_sql($table, $names = null, $values = null, } /** - * Normalizes metadata / annotation option names to their - * corresponding metastrings name. + * Normalizes metadata / annotation option names to their corresponding metastrings name. * * @param array $options An options array * @since 1.8.0 @@ -631,10 +630,10 @@ function elgg_normalize_metastrings_options(array $options = array()) { // 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', + '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', @@ -728,7 +727,8 @@ function elgg_batch_metastring_based_objects(array $options, $callback) { return false; } - $batch = new ElggBatch('elgg_get_metastring_based_objects', $options, $callback); + // @todo restore once ElggBatch supports callbacks that delete rows. + $batch = new ElggBatch('elgg_get_metastring_based_objects', $options, $callback, 50, false); $r = $batch->callbackResult; return $r; diff --git a/engine/lib/navigation.php b/engine/lib/navigation.php index 956ca220a..a7984ce5a 100644 --- a/engine/lib/navigation.php +++ b/engine/lib/navigation.php @@ -78,7 +78,11 @@ * link_class => STR A class or classes for the <a> tag * item_class => STR A class or classes for the <li> tag * - * Custom options can be added as key value pairs. + * 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 @@ -301,7 +305,7 @@ function elgg_site_menu_setup($hook, $type, $return, $params) { // 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); + $return['more'] = array_splice($return['default'], $max_display_items); } } diff --git a/engine/lib/notification.php b/engine/lib/notification.php index eb7e594c6..5a2f5f8ac 100644 --- a/engine/lib/notification.php +++ b/engine/lib/notification.php @@ -487,6 +487,7 @@ function object_notifications($event, $object_type, $object) { // (Person defined by container_guid so we can also subscribe to groups if we want) 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, 'inverse_relationship' => TRUE, diff --git a/engine/lib/objects.php b/engine/lib/objects.php index 63d0f5cef..f186c66cb 100644 --- a/engine/lib/objects.php +++ b/engine/lib/objects.php @@ -52,11 +52,8 @@ function create_object_entity($guid, $title, $description) { if ($result != false) { // Update succeeded, continue $entity = get_entity($guid); - if (elgg_trigger_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. diff --git a/engine/lib/output.php b/engine/lib/output.php index 6554481f5..b96cf354c 100644 --- a/engine/lib/output.php +++ b/engine/lib/output.php @@ -67,7 +67,7 @@ function autop($pee, $br = 1) { $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>|', "$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); @@ -81,11 +81,11 @@ function autop($pee, $br = 1) { } $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 ); + //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; } diff --git a/engine/lib/pagehandler.php b/engine/lib/pagehandler.php index ffcfc5b6a..a675d976a 100644 --- a/engine/lib/pagehandler.php +++ b/engine/lib/pagehandler.php @@ -120,6 +120,7 @@ function elgg_unregister_page_handler($handler) { * @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 elgg_error_page_handler($hook, $type, $result, $params) { if (elgg_view_exists("errors/$type")) { diff --git a/engine/lib/pageowner.php b/engine/lib/pageowner.php index 9d41d74c1..0cf0e0625 100644 --- a/engine/lib/pageowner.php +++ b/engine/lib/pageowner.php @@ -54,7 +54,7 @@ function elgg_get_page_owner_entity() { * 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) { @@ -173,7 +173,7 @@ function default_page_owner_handler($hook, $entity_type, $returnvalue, $params) * @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 + * @param string $context The context of the page * @return bool * @since 1.8.0 */ @@ -216,6 +216,7 @@ function elgg_get_context() { * Push a context onto the top of the stack * * @param string $context The context string to add to the context stack + * @return void * @since 1.8.0 */ function elgg_push_context($context) { @@ -244,7 +245,7 @@ function elgg_pop_context() { * 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 + * @param string $context The context string to check for * @return bool * @since 1.8.0 */ diff --git a/engine/lib/plugins.php b/engine/lib/plugins.php index be871d025..123fb18d8 100644 --- a/engine/lib/plugins.php +++ b/engine/lib/plugins.php @@ -62,7 +62,7 @@ function elgg_get_plugin_ids_in_dir($dir = null) { $dir = elgg_get_plugins_path(); } - $plugin_idss = array(); + $plugin_ids = array(); $handle = opendir($dir); if ($handle) { @@ -298,19 +298,13 @@ function elgg_load_plugins() { // 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; } - // Load view caches if available - $cached_view_paths = elgg_filepath_cache_load('views'); - $cached_view_types = elgg_filepath_cache_load('view_types'); - $cached_view_info = is_string($cached_view_paths) && is_string($cached_view_types); - - if ($cached_view_info) { - $CONFIG->views = unserialize($cached_view_paths); - $CONFIG->view_types = unserialize($cached_view_types); - - // don't need to register views + if (elgg_get_config('system_cache_loaded')) { $start_flags = $start_flags & ~ELGG_PLUGIN_REGISTER_VIEWS; } @@ -332,12 +326,6 @@ function elgg_load_plugins() { } } - // Cache results - if (!$cached_view_info) { - elgg_filepath_cache_save('views', serialize($CONFIG->views)); - elgg_filepath_cache_save('view_types', serialize($CONFIG->view_types)); - } - return $return; } @@ -439,9 +427,9 @@ function elgg_set_plugin_priorities(array $order) { } } - // set the missing plugins priorities + // set the missing plugins' priorities if ($return && $missing_plugins) { - if (!$priority) { + if (!isset($priority)) { $priority = 0; } foreach ($missing_plugins as $plugin) { @@ -480,9 +468,10 @@ function elgg_reindex_plugin_priorities() { */ function elgg_namespace_plugin_private_setting($type, $name, $id = null) { switch ($type) { -// case 'setting': -// $name = ELGG_PLUGIN_SETTING_PREFIX . $name; -// break; + // commented out because it breaks $plugin->$name access to variables + //case 'setting': + // $name = ELGG_PLUGIN_SETTING_PREFIX . $name; + // break; case 'user_setting': if (!$id) { diff --git a/engine/lib/private_settings.php b/engine/lib/private_settings.php index 386af5279..1fa9bdb66 100644 --- a/engine/lib/private_settings.php +++ b/engine/lib/private_settings.php @@ -240,7 +240,7 @@ $pairs = NULL, $pair_operator = 'AND', $name_prefix = '') { $i++; } - $where = implode (" $pair_operator ", $pair_wheres); + $where = implode(" $pair_operator ", $pair_wheres); if ($where) { $wheres[] = "($where)"; } diff --git a/engine/lib/relationships.php b/engine/lib/relationships.php index 5b7080b56..fabe2d2d6 100644 --- a/engine/lib/relationships.php +++ b/engine/lib/relationships.php @@ -399,8 +399,8 @@ function elgg_list_entities_from_relationship_count($options) { /** * Sets the URL handler for a particular relationship type * - * @param string $function_name The function to register * @param string $relationship_type The relationship type. + * @param string $function_name The function to register * * @return bool Depending on success */ diff --git a/engine/lib/river.php b/engine/lib/river.php index 421813441..547d9495e 100644 --- a/engine/lib/river.php +++ b/engine/lib/river.php @@ -44,10 +44,16 @@ $posted = 0, $annotation_id = 0) { if ($access_id === "") { $access_id = $object->access_id; } - $annotation_id = (int)$annotation_id; $type = $object->getType(); $subtype = $object->getSubtype(); + + $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); $params = array( 'type' => $type, @@ -102,7 +108,7 @@ $posted = 0, $annotation_id = 0) { * * @warning not checking access (should we?) * - * @param array $options + * @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) @@ -209,7 +215,7 @@ function elgg_delete_river(array $options = array()) { * * @note If using types and subtypes in a query, they are joined with an AND. * - * @param array $options + * @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) @@ -542,7 +548,7 @@ function elgg_river_get_action_where_sql($types) { /** * Get the where clause based on river view strings * - * @param array $types Array of view strings + * @param array $views Array of view strings * * @return string * @since 1.8.0 diff --git a/engine/lib/sessions.php b/engine/lib/sessions.php index 97a05e2e8..9982d9fe8 100644 --- a/engine/lib/sessions.php +++ b/engine/lib/sessions.php @@ -355,7 +355,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; @@ -379,7 +379,7 @@ function logout() { * @return bool * @access private */ -function session_init($event, $object_type, $object) { +function _elgg_session_boot($event, $object_type, $object) { global $DB_PREFIX, $CONFIG; // Use database for sessions @@ -444,8 +444,8 @@ function session_init($event, $object_type, $object) { set_last_action($_SESSION['guid']); } - elgg_register_action("login", '', 'public'); - elgg_register_action("logout"); + elgg_register_action('login', '', 'public'); + elgg_register_action('logout'); // Register a default PAM handler register_pam_handler('pam_auth_userpass'); @@ -655,4 +655,4 @@ function _elgg_session_gc($maxlifetime) { return true; } -elgg_register_event_handler("boot", "system", "session_init", 20); +elgg_register_event_handler('boot', 'system', '_elgg_session_boot', 2); diff --git a/engine/lib/sites.php b/engine/lib/sites.php index 337b2d180..850092cad 100644 --- a/engine/lib/sites.php +++ b/engine/lib/sites.php @@ -231,43 +231,6 @@ function get_site_domain($guid) { } /** - * Initialise site handling - * - * 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. - * - * @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 - * @access private - */ -function sites_boot($event, $object_type, $object) { - global $CONFIG; - - $site = elgg_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; -} - -// Register event handlers -elgg_register_event_handler('boot', 'system', 'sites_boot', 2); - -// Register with unit test -elgg_register_plugin_hook_handler('unit_test', 'system', 'sites_test'); - -/** * Unit tests for sites * * @param sting $hook unit_test @@ -283,3 +246,6 @@ function sites_test($hook, $type, $value, $params) { $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/statistics.php b/engine/lib/statistics.php index 7c170f3bb..e1f95ed97 100644 --- a/engine/lib/statistics.php +++ b/engine/lib/statistics.php @@ -95,14 +95,12 @@ function get_number_users($show_deactivated = false) { * @return string */ function get_online_users() { - $offset = get_input('offset', 0); $count = find_active_users(600, 10, $offset, true); $objects = find_active_users(600, 10, $offset); if ($objects) { return elgg_view_entity_list($objects, array( 'count' => $count, - 'offset' => $offset, 'limit' => 10 )); } diff --git a/engine/lib/system_log.php b/engine/lib/system_log.php index fd5644135..28d90be56 100644 --- a/engine/lib/system_log.php +++ b/engine/lib/system_log.php @@ -11,6 +11,7 @@ * Retrieve the system log based on a number of parameters. * * @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 @@ -21,11 +22,12 @@ * @param int $timebefore Lower time limit * @param int $timeafter Upper time limit * @param int $object_id GUID of an object - * + * @param str $ip_address The IP address. * @return mixed */ function get_system_log($by_user = "", $event = "", $class = "", $type = "", $subtype = "", -$limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $object_id = 0) { +$limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $object_id = 0, +$ip_address = false) { global $CONFIG; @@ -37,16 +39,18 @@ $limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $obje } 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)) { @@ -75,6 +79,9 @@ $limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $obje if ($object_id) { $where[] = "object_id = " . ((int) $object_id); } + if ($ip_address) { + $where[] = "ip_address = '$ip_address'"; + } $select = "*"; if ($count) { @@ -91,7 +98,8 @@ $limit = 10, $offset = 0, $count = false, $timebefore = 0, $timeafter = 0, $obje } if ($count) { - if ($numrows = get_data_row($query)) { + $numrows = get_data_row($query); + if ($numrows) { return $numrows->count; } } else { @@ -171,6 +179,7 @@ function system_log($object, $event) { $object_subtype = $object->getSubtype(); $event = sanitise_string($event); $time = time(); + $ip_address = sanitise_string($_SERVER['REMOTE_ADDR']); $performed_by = elgg_get_logged_in_user_guid(); if (isset($object->access_id)) { @@ -194,10 +203,10 @@ function system_log($object, $event) { 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) + 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')"; + $performed_by, $owner_guid, $access_id, '$enabled', '$time', '$ip_address')"; insert_data($query); diff --git a/engine/lib/upgrades/2011010101.php b/engine/lib/upgrades/2011010101.php index b063c249b..a1ee92622 100644 --- a/engine/lib/upgrades/2011010101.php +++ b/engine/lib/upgrades/2011010101.php @@ -66,7 +66,7 @@ if ($old_enabled_plugins) { // invalidate caches elgg_invalidate_simplecache(); -elgg_filepath_cache_reset(); +elgg_reset_system_cache(); // clean up. remove_metadata($site->guid, 'pluginorder'); 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 index e4ab9c137..fe2af9928 100644 --- 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 @@ -9,7 +9,8 @@ $ia = elgg_set_ignore_access(true); $options = array( 'type' => 'object', - 'subtype' => 'blog' + 'subtype' => 'blog', + 'limit' => 0, ); $batch = new ElggBatch('elgg_get_entities', $options); 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 index 4fc59ac41..41ab29998 100644 --- 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 @@ -16,6 +16,7 @@ access_show_hidden_entities(true); $options = array( 'type' => 'site', 'site_guid' => 0, + 'limit' => 0, ); $batch = new ElggBatch('elgg_get_entities', $options); 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/users.php b/engine/lib/users.php index 1b3cca799..f1d42e25e 100644 --- a/engine/lib/users.php +++ b/engine/lib/users.php @@ -60,13 +60,12 @@ 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 - $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', last_action = " - . time() . " where guid = {$guid}"; + 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) { @@ -79,7 +78,7 @@ function create_user_entity($guid, $name, $username, $password, $salt, $email, $ } } } else { - // Update failed, attempt an insert. + // 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')"; @@ -90,7 +89,7 @@ function create_user_entity($guid, $name, $username, $password, $salt, $email, $ if (elgg_trigger_event('create', $entity->type, $entity)) { return $guid; } else { - $entity->delete(); //delete_entity($guid); + $entity->delete(); } } } @@ -299,13 +298,14 @@ 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', 'limit' => $limit, - 'offset' => $offset) - ); + 'offset' => $offset, + )); } /** @@ -497,20 +497,26 @@ $timelower = 0, $timeupper = 0) { * @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 string */ function list_user_friends_objects($user_guid, $subtype = "", $limit = 10, $full_view = true, $listtypetoggle = 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); + $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); - return elgg_view_entity_list($entities, $count, $offset, $limit, $full_view, - $listtypetoggle, $pagination); + return elgg_view_entity_list($entities, array( + 'count' => $count, + 'offset' => $offset, + 'limit' => $limit, + 'full_view' => $full_view, + 'list_type_toggle' => $listtypetoggle, + 'pagination' => $pagination, + )); } /** @@ -606,11 +612,11 @@ function get_user_by_code($code) { } /** - * Get an array of users from their email addresses + * 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; @@ -630,10 +636,10 @@ function get_user_by_email($email) { * A function that returns a maximum of $limit users who have done something within the last * $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, default 0. + * @param bool $count Count, default false. * * @return mixed */ @@ -952,6 +958,7 @@ $allow_multiple_emails = false, $friend_guid = 0, $invitecode = '') { $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 @@ -1485,7 +1492,7 @@ function users_pagesetup() { if ($viewer) { elgg_register_menu_item('topbar', array( 'name' => 'profile', - 'href' => $viewer->getURL(), + 'href' => $viewer->getURL(), 'text' => elgg_view('output/img', array( 'src' => $viewer->getIconURL('topbar'), 'alt' => $viewer->name, @@ -1549,6 +1556,7 @@ function users_init() { elgg_register_action('friends/remove'); elgg_register_action('avatar/upload'); elgg_register_action('avatar/crop'); + elgg_register_action('avatar/revert'); elgg_register_action('profile/edit'); elgg_register_action('friends/collections/add'); diff --git a/engine/lib/views.php b/engine/lib/views.php index b938dd60e..ca0ce7196 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -196,6 +196,37 @@ function elgg_does_viewtype_fallback($viewtype) { 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]); + } +} /** * Returns the file location for a view. @@ -415,7 +446,6 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie 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']; - $test=false; } elseif (isset($vars['name'])) { if (!isset($vars['internalname'])) { $vars['__ignoreInternalname'] = ''; @@ -530,7 +560,7 @@ function elgg_view($view, $vars = array(), $bypass = false, $debug = false, $vie * * @return void * @since 1.7.0 - * @link http://docs.elgg.org/Views/Ejxtend + * @link http://docs.elgg.org/Views/Extend * @example views/extend.php */ function elgg_extend_view($view, $view_extension, $priority = 501, $viewtype = '') { @@ -939,12 +969,7 @@ function elgg_view_annotation(ElggAnnotation $annotation, array $vars = array(), return elgg_view($view, $vars, $bypass, $debug); } - // @todo would be better to always make sure name is initialized properly $name = $annotation->name; - $intname = (int) $name; - if ("{$intname}" == "{$name}") { - $name = get_metastring($intname); - } if (empty($name)) { return false; } @@ -1300,21 +1325,18 @@ function elgg_view_form($action, $form_vars = array(), $body_vars = array()) { * @access private */ function elgg_view_list_item($item, array $vars = array()) { + global $CONFIG; - switch ($item->getType()) { - case 'user': - case 'object': - case 'group': - case 'site': - return elgg_view_entity($item, $vars); - case 'annotation': - return elgg_view_annotation($item, $vars); - case 'river': - return elgg_view_river_item($item, $vars); - default: - return false; - break; + $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); } + + return false; } /** @@ -1611,6 +1633,8 @@ function elgg_views_boot() { 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 @@ -1628,16 +1652,16 @@ function elgg_views_boot() { // set default icon sizes - can be overridden in settings.php or with plugin if (!elgg_get_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), + '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', 1000); +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/web_services.php b/engine/lib/web_services.php index 1c77b757e..07be76ec6 100644 --- a/engine/lib/web_services.php +++ b/engine/lib/web_services.php @@ -1165,7 +1165,7 @@ function list_all_apis() { * @access private */ function auth_gettoken($username, $password) { - if (authenticate($username, $password)) { + if (elgg_authenticate($username, $password)) { $token = create_user_token($username); if ($token) { return $token; diff --git a/engine/lib/widgets.php b/engine/lib/widgets.php index 46f34391a..d73dd6330 100644 --- a/engine/lib/widgets.php +++ b/engine/lib/widgets.php @@ -316,7 +316,12 @@ function elgg_default_widgets_init() { // 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'); + // only register the callback once per event + $events = array(); foreach ($default_widgets as $info) { + $events[$info['event'] . ',' . $info['entity_type']] = $info; + } + foreach ($events as $info) { elgg_register_event_handler($info['event'], $info['entity_type'], 'elgg_create_default_widgets'); } } diff --git a/engine/schema/mysql.sql b/engine/schema/mysql.sql index 74cf2ce74..6c6e9db89 100644 --- a/engine/schema/mysql.sql +++ b/engine/schema/mysql.sql @@ -361,6 +361,7 @@ CREATE TABLE `prefix_system_log` ( `access_id` int(11) NOT NULL, `enabled` enum('yes','no') NOT NULL DEFAULT 'yes', `time_created` int(11) NOT NULL, + `ip_address` varchar(15) NOT NULL, PRIMARY KEY (`id`), KEY `object_id` (`object_id`), KEY `object_class` (`object_class`), diff --git a/engine/settings.example.php b/engine/settings.example.php index 011770f89..3b139d710 100644 --- a/engine/settings.example.php +++ b/engine/settings.example.php @@ -107,7 +107,7 @@ $CONFIG->broken_mta = FALSE; * * Elgg stores each query and its results in a query cache. * On large sites or long-running scripts, this cache can grow to be - * large. To disable query caching, set this to FALSE. + * large. To disable query caching, set this to TRUE. * * @global bool $CONFIG->db_disable_query_cache */ diff --git a/engine/start.php b/engine/start.php index 00bdc3197..506e27380 100644 --- a/engine/start.php +++ b/engine/start.php @@ -1,12 +1,12 @@ <?php /** - * Bootstraps and starts the Elgg engine. + * Bootstraps the Elgg engine. * * This file loads the full Elgg engine, checks the installation - * state, then emits a series of events to finish booting Elgg: + * state, and triggers a series of events to finish booting Elgg: * - {@elgg_event boot system} - * - {@elgg_event plugins_boot system} * - {@elgg_event init system} + * - {@elgg_event ready system} * * If Elgg is fully uninstalled, the browser will be redirected to an * installation page. @@ -36,13 +36,12 @@ $START_MICROTIME = microtime(true); * Configuration values. * * The $CONFIG global contains configuration values required - * for running Elgg as defined in the settings.php file. The following - * array keys are defined by core Elgg: + * for running Elgg as defined in the settings.php file. * - * Plugin authors are encouraged to use get_config() instead of accessing the - * global directly. + * Plugin authors are encouraged to use elgg_get_config() instead of accessing + * the global directly. * - * @see get_config() + * @see elgg_get_config() * @see engine/settings.php * @global stdClass $CONFIG */ @@ -53,56 +52,35 @@ if (!isset($CONFIG)) { $lib_dir = dirname(__FILE__) . '/lib/'; -/** - * The minimum required libs to bootstrap an Elgg installation. - * - * @var array - */ -$required_files = array( - 'elgglib.php', 'views.php', 'access.php', 'system_log.php', 'export.php', - 'sessions.php', 'languages.php', 'pageowner.php', 'input.php', 'cache.php', - 'output.php' -); - -// include bootstraping libs -foreach ($required_files as $file) { - $path = $lib_dir . $file; - if (!include($path)) { - echo "Could not load file '$path'. " - . 'Please check your Elgg installation for all required files.'; - exit; - } +// Load the bootstrapping library +$path = $lib_dir . 'elgglib.php'; +if (!include_once($path)) { + echo "Could not load file '$path'. Please check your Elgg installation for all required files."; + exit; } -// Register the error handler -set_error_handler('_elgg_php_error_handler'); -set_exception_handler('_elgg_php_exception_handler'); - -/** - * Load the system settings - */ +// Load the system settings if (!include_once(dirname(__FILE__) . "/settings.php")) { - $msg = elgg_echo('InstallationException:CannotLoadSettings'); + $msg = 'Elgg could not load the settings file. It does not exist or there is a file permissions issue.'; throw new InstallationException($msg); } // load the rest of the library files from engine/lib/ $lib_files = array( - // these need to be loaded first. - 'database.php', 'actions.php', - - 'admin.php', 'annotations.php', 'calendar.php', - 'configuration.php', 'cron.php', 'entities.php', 'export.php', - 'extender.php', 'filestore.php', 'group.php', - 'location.php', 'mb_wrapper.php', 'memcache.php', 'metadata.php', - 'metastrings.php', 'navigation.php', 'notification.php', 'objects.php', - 'opendd.php', 'pagehandler.php', 'pam.php', 'plugins.php', - 'private_settings.php', 'relationships.php', 'river.php', 'sites.php', - 'statistics.php', 'tags.php', 'user_settings.php', 'users.php', - 'upgrade.php', 'web_services.php', 'widgets.php', 'xml.php', 'xml-rpc.php', + 'access.php', 'actions.php', 'admin.php', 'annotations.php', 'cache.php', + 'calendar.php', 'configuration.php', 'cron.php', 'database.php', + 'entities.php', 'export.php', 'extender.php', 'filestore.php', 'group.php', + 'input.php', 'languages.php', 'location.php', 'mb_wrapper.php', + 'memcache.php', 'metadata.php', 'metastrings.php', 'navigation.php', + 'notification.php', 'objects.php', 'opendd.php', 'output.php', + 'pagehandler.php', 'pageowner.php', 'pam.php', 'plugins.php', + 'private_settings.php', 'relationships.php', 'river.php', 'sessions.php', + 'sites.php', 'statistics.php', 'system_log.php', 'tags.php', + 'user_settings.php', 'users.php', 'upgrade.php', 'views.php', + 'web_services.php', 'widgets.php', 'xml.php', 'xml-rpc.php', - //backwards compatibility + // backward compatibility 'deprecated-1.7.php', 'deprecated-1.8.php', ); @@ -110,48 +88,22 @@ foreach ($lib_files as $file) { $file = $lib_dir . $file; elgg_log("Loading $file..."); if (!include_once($file)) { - $msg = sprintf(elgg_echo('InstallationException:MissingLibrary'), $file); + $msg = "Could not load $file"; throw new InstallationException($msg); } } -// connect to db -setup_db_connections(); - -// confirm that the installation completed successfully -verify_installation(); - -// Autodetect some default configuration settings -set_default_config(); - -// needs to be set for links in html head -$viewtype = get_input('view', 'default'); -$lastcached = datalist_get("simplecache_lastcached_$viewtype"); -$CONFIG->lastcache = $lastcached; - -// Trigger boot events for core. Plugins can't hook -// into this because they haven't been loaded yet. +// Connect to database, load language files, load configuration, init session +// Plugins can't use this event because they haven't been loaded yet. elgg_trigger_event('boot', 'system'); // Load the plugins that are active elgg_load_plugins(); +// @todo deprecate as plugins can use 'init', 'system' event elgg_trigger_event('plugins_boot', 'system'); -// Trigger system init event for plugins +// Complete the boot process for both engine and plugins elgg_trigger_event('init', 'system'); -// 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; -} - // System loaded and ready elgg_trigger_event('ready', 'system'); diff --git a/engine/tests/api/annotations.php b/engine/tests/api/annotations.php index d7551a0fa..947292970 100644 --- a/engine/tests/api/annotations.php +++ b/engine/tests/api/annotations.php @@ -43,4 +43,28 @@ class ElggCoreAnnotationAPITest extends ElggCoreUnitTest { $this->object->delete(); } + + public function testElggDeleteAnnotations() { + $e = new ElggObject(); + $e->save(); + + for ($i=0; $i<30; $i++) { + $e->annotate('test_annotation', rand(0,10000)); + } + + $options = array( + 'guid' => $e->getGUID(), + 'limit' => 0 + ); + + $annotations = elgg_get_annotations($options); + $this->assertIdentical(30, count($annotations)); + + $this->assertTrue(elgg_delete_annotations($options)); + + $annotations = elgg_get_annotations($options); + $this->assertTrue(empty($annotations)); + + $this->assertTrue($e->delete()); + } } diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php index 77205138d..62e4471e0 100644 --- a/engine/tests/api/helpers.php +++ b/engine/tests/api/helpers.php @@ -518,4 +518,87 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $this->assertIdentical($elements_sorted_string, $test_elements); } + + // see http://trac.elgg.org/ticket/4288 + public function testElggBatchIncOffset() { + // normal increment + $options = array( + 'offset' => 0, + 'limit' => 11 + ); + $batch = new ElggBatch(array('ElggCoreHelpersTest', 'elgg_batch_callback_test'), $options, + null, 5); + $j = 0; + foreach ($batch as $e) { + $offset = floor($j / 5) * 5; + $this->assertEqual($offset, $e['offset']); + $this->assertEqual($j + 1, $e['index']); + $j++; + } + + $this->assertEqual(11, $j); + + // no increment, 0 start + ElggCoreHelpersTest::elgg_batch_callback_test(array(), true); + $options = array( + 'offset' => 0, + 'limit' => 11 + ); + $batch = new ElggBatch(array('ElggCoreHelpersTest', 'elgg_batch_callback_test'), $options, + null, 5); + $batch->setIncrementOffset(false); + + $j = 0; + foreach ($batch as $e) { + $this->assertEqual(0, $e['offset']); + // should always be the same 5 + $this->assertEqual($e['index'], $j + 1 - (floor($j / 5) * 5)); + $j++; + } + $this->assertEqual(11, $j); + + // no increment, 3 start + ElggCoreHelpersTest::elgg_batch_callback_test(array(), true); + $options = array( + 'offset' => 3, + 'limit' => 11 + ); + $batch = new ElggBatch(array('ElggCoreHelpersTest', 'elgg_batch_callback_test'), $options, + null, 5); + $batch->setIncrementOffset(false); + + $j = 0; + foreach ($batch as $e) { + $this->assertEqual(3, $e['offset']); + // same 5 results + $this->assertEqual($e['index'], $j + 4 - (floor($j / 5) * 5)); + $j++; + } + + $this->assertEqual(11, $j); + } + + static function elgg_batch_callback_test($options, $reset = false) { + static $count = 1; + + if ($reset) { + $count = 1; + return true; + } + + if ($count > 20) { + return false; + } + + for ($j = 0; ($options['limit'] < 5) ? $j < $options['limit'] : $j < 5; $j++) { + $return[] = array( + 'offset' => $options['offset'], + 'limit' => $options['limit'], + 'count' => $count++, + 'index' => 1 + $options['offset'] + $j + ); + } + + return $return; + } }
\ No newline at end of file diff --git a/engine/tests/api/metadata.php b/engine/tests/api/metadata.php index f5b615ca8..be8ac269c 100644 --- a/engine/tests/api/metadata.php +++ b/engine/tests/api/metadata.php @@ -99,6 +99,31 @@ class ElggCoreMetadataAPITest extends ElggCoreUnitTest { $this->object->delete(); } + public function testElggDeleteMetadata() { + $e = new ElggObject(); + $e->save(); + + for ($i=0; $i<30; $i++) { + $name = "test_metadata" . rand(0, 10000); + $e->$name = rand(0, 10000); + } + + $options = array( + 'guid' => $e->getGUID(), + 'limit' => 0 + ); + + $md = elgg_get_metadata($options); + $this->assertIdentical(30, count($md)); + + $this->assertTrue(elgg_delete_metadata($options)); + + $md = elgg_get_metadata($options); + $this->assertTrue(empty($md)); + + $e->delete(); + } + protected function create_metastring($string) { global $CONFIG, $METASTRINGS_CACHE, $METASTRINGS_DEADNAME_CACHE; diff --git a/engine/tests/api/metastrings.php b/engine/tests/api/metastrings.php index a96388217..0a8945084 100644 --- a/engine/tests/api/metastrings.php +++ b/engine/tests/api/metastrings.php @@ -132,7 +132,7 @@ class ElggCoreMetastringsTest extends ElggCoreUnitTest { public function testKeepMeFromDeletingEverything() { foreach ($this->metastringTypes as $type) { $required = array( - 'guid', 'guids', 'limit' + 'guid', 'guids' ); switch ($type) { @@ -160,6 +160,10 @@ class ElggCoreMetastringsTest extends ElggCoreUnitTest { $options = array(); $this->assertFalse(elgg_is_valid_options_for_batch_operation($options, $type)); + // limit alone isn't valid: + $options = array('limit' => 10); + $this->assertFalse(elgg_is_valid_options_for_batch_operation($options, $type)); + foreach ($required as $key) { $options = array(); diff --git a/engine/tests/objects/entities.php b/engine/tests/objects/entities.php index 1772f7c1a..a4dc7946c 100644 --- a/engine/tests/objects/entities.php +++ b/engine/tests/objects/entities.php @@ -226,6 +226,39 @@ class ElggCoreEntityTest extends ElggCoreUnitTest { $this->assertTrue($this->entity->delete()); } + public function testElggEntityRecursiveDisableAndEnable() { + global $CONFIG; + + $this->save_entity(); + $obj1 = new ElggObject(); + $obj1->container_guid = $this->entity->getGUID(); + $obj1->save(); + $obj2 = new ElggObject(); + $obj2->container_guid = $this->entity->getGUID(); + $obj2->save(); + + // disable $obj2 before disabling the container + $this->assertTrue($obj2->disable()); + + // disable entities container by $this->entity + $this->assertTrue($this->entity->disable()); + $entity = get_data_row("SELECT * FROM {$CONFIG->dbprefix}entities WHERE guid = '{$obj1->guid}'"); + $this->assertIdentical($entity->enabled, 'no'); + + // enable entities that were disabled with the container (but not $obj2) + $this->assertTrue($this->entity->enable()); + $entity = get_data_row("SELECT * FROM {$CONFIG->dbprefix}entities WHERE guid = '{$obj1->guid}'"); + $this->assertIdentical($entity->enabled, 'yes'); + $entity = get_data_row("SELECT * FROM {$CONFIG->dbprefix}entities WHERE guid = '{$obj2->guid}'"); + $this->assertIdentical($entity->enabled, 'no'); + + // cleanup + $this->assertTrue($obj2->enable()); + $this->assertTrue($obj2->delete()); + $this->assertTrue($obj1->delete()); + $this->assertTrue($this->entity->delete()); + } + public function testElggEntityMetadata() { // let's delete a non-existent metadata $this->assertFalse($this->entity->deleteMetadata('important')); diff --git a/engine/tests/objects/objects.php b/engine/tests/objects/objects.php index 0d0df6b75..915594e0a 100644 --- a/engine/tests/objects/objects.php +++ b/engine/tests/objects/objects.php @@ -194,7 +194,99 @@ class ElggCoreObjectTest extends ElggCoreUnitTest { $old = elgg_set_ignore_access(true); } + // see http://trac.elgg.org/ticket/1196 + public function testElggEntityRecursiveDisableWhenLoggedOut() { + $e1 = new ElggObject(); + $e1->access_id = ACCESS_PUBLIC; + $e1->owner_guid = 0; + $e1->container_guid = 0; + $e1->save(); + $guid1 = $e1->getGUID(); + + $e2 = new ElggObject(); + $e2->container_guid = $guid1; + $e2->access_id = ACCESS_PUBLIC; + $e2->owner_guid = 0; + $e2->save(); + $guid2 = $e2->getGUID(); + + // fake being logged out + $user = $_SESSION['user']; + unset($_SESSION['user']); + $ia = elgg_set_ignore_access(true); + + $this->assertTrue(disable_entity($guid1, null, true)); + + // "log in" original user + $_SESSION['user'] = $user; + elgg_set_ignore_access($ia); + + $this->assertFalse(get_entity($guid1)); + $this->assertFalse(get_entity($guid2)); + + $db_prefix = get_config('dbprefix'); + $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $guid1"; + $r = get_data_row($q); + $this->assertEqual('no', $r->enabled); + + $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $guid2"; + $r = get_data_row($q); + $this->assertEqual('no', $r->enabled); + + access_show_hidden_entities(true); + delete_entity($guid1); + delete_entity($guid2); + access_show_hidden_entities(false); + } + + public function testElggRecursiveDelete() { + $types = array('ElggGroup', 'ElggObject', 'ElggUser', 'ElggSite'); + $db_prefix = elgg_get_config('dbprefix'); + + foreach ($types as $type) { + $parent = new $type(); + $this->assertTrue($parent->save()); + + $child = new ElggObject(); + $child->container_guid = $parent->guid; + $this->assertTrue($child->save()); + + $grandchild = new ElggObject(); + $grandchild->container_guid = $child->guid; + $this->assertTrue($grandchild->save()); + + $this->assertTrue($parent->delete(true)); + + $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $parent->guid"; + $r = get_data($q); + $this->assertFalse($r); + + $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $child->guid"; + $r = get_data($q); + $this->assertFalse($r); + $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $grandchild->guid"; + $r = get_data($q); + $this->assertFalse($r); + } + + // object that owns itself + // can't check container_guid because of infinite loops in can_edit_entity() + $obj = new ElggObject(); + $obj->save(); + $obj->owner_guid = $obj->guid; + $obj->save(); + + $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $obj->guid"; + $r = get_data_row($q); + $this->assertEqual($obj->guid, $r->owner_guid); + + $this->assertTrue($obj->delete(true)); + + $q = "SELECT * FROM {$db_prefix}entities WHERE guid = $obj->guid"; + $r = get_data_row($q); + $this->assertFalse($r); + } protected function get_object_row($guid) { global $CONFIG; |