From b3bad6fc928cae56bdc3a97fe8089b27f6f79f0b Mon Sep 17 00:00:00 2001 From: Brett Profitt Date: Sun, 3 Jul 2011 16:52:33 -0400 Subject: Merged d423aee393458d6827db from 1.7 to master. Fixes #3552. Addess ACL unit tests. These currently fail because of #3522. git-svn-id: http://code.elgg.org/elgg/branches/1.7@9202 36083f99-b078-4883-b0ff-0f9b5a30f544 Conflicts: engine/lib/access.php --- engine/tests/api/access_collections.php | 170 ++++++++++++++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 engine/tests/api/access_collections.php (limited to 'engine/tests') diff --git a/engine/tests/api/access_collections.php b/engine/tests/api/access_collections.php new file mode 100644 index 000000000..060587d78 --- /dev/null +++ b/engine/tests/api/access_collections.php @@ -0,0 +1,170 @@ +dbPrefix = get_config("dbprefix"); + + $user = new ElggUser(); + $user->username = 'test_user_' . rand(); + $user->email = 'fake_email@fake.com' . rand(); + $user->name = 'fake user'; + $user->access_id = ACCESS_PUBLIC; + $user->salt = generate_random_cleartext_password(); + $user->password = generate_user_password($user, rand()); + $user->owner_guid = 0; + $user->container_guid = 0; + $user->save(); + + $this->user = $user; + } + + /** + * Called before each test method. + */ + public function setUp() { + + } + + /** + * Called after each test method. + */ + public function tearDown() { + // do not allow SimpleTest to interpret Elgg notices as exceptions + $this->swallowErrors(); + } + + /** + * Called after each test object. + */ + public function __destruct() { + // all __destruct() code should go above here + $this->user->delete(); + parent::__destruct(); + } + + public function testCreateGetDeleteACL() { + global $DB_QUERY_CACHE; + + $acl_name = 'test access collection'; + $acl_id = create_access_collection($acl_name); + + $this->assertTrue(is_int($acl_id)); + + $q = "SELECT * FROM {$this->dbPrefix}access_collections WHERE id = $acl_id"; + $acl = get_data_row($q); + + $this->assertEqual($acl->id, $acl_id); + + if ($acl) { + $DB_QUERY_CACHE = array(); + + $this->assertEqual($acl->name, $acl_name); + + $result = delete_access_collection($acl_id); + $this->assertTrue($result); + + $q = "SELECT * FROM {$this->dbPrefix}access_collections WHERE id = $acl_id"; + $data = get_data($q); + $this->assertFalse($data); + } + } + + public function testAddRemoveUserToACL() { + $acl_id = create_access_collection('test acl'); + + $result = add_user_to_access_collection($this->user->guid, $acl_id); + $this->assertTrue($result); + + if ($result) { + $result = remove_user_from_access_collection($this->user->guid, $acl_id); + $this->assertTrue($result); + } + + delete_access_collection($acl_id); + } + + public function testUpdateACL() { + // another fake user to test with + $user = new ElggUser(); + $user->username = 'test_user_' . rand(); + $user->email = 'fake_email@fake.com' . rand(); + $user->name = 'fake user'; + $user->access_id = ACCESS_PUBLIC; + $user->salt = generate_random_cleartext_password(); + $user->password = generate_user_password($user, rand()); + $user->owner_guid = 0; + $user->container_guid = 0; + $user->save(); + + $acl_id = create_access_collection('test acl'); + + $member_lists = array( + // adding + array( + $this->user->guid, + $user->guid + ), + // removing one, keeping one. + array( + $user->guid + ), + // removing one, adding one + array( + $this->user->guid, + ), + // removing all. + array() + ); + + foreach ($member_lists as $members) { + $result = update_access_collection($acl_id, $members); + $this->assertTrue($result); + + if ($result) { + $q = "SELECT * FROM {$this->dbPrefix}access_collection_membership + WHERE access_collection_id = $acl_id"; + $data = get_data($q); + + if (count($members) == 0) { + $this->assertFalse($data); + } else { + $this->assertEqual(count($members), count($data)); + } + foreach ($data as $row) { + $this->assertTrue(in_array($row->user_guid, $members)); + } + } + } + + delete_access_collection($acl_id); + $user->delete(); + } + + // groups interface + public function testNewGroupCreateACL() { + + } + + public function testDeleteGroupDeleteACL() { + + } + + public function testJoinGroupJoinACL() { + + } + + public function testLeaveGroupLeaveACL() { + + } +} -- cgit v1.2.3 From de111da23258cd2b513c8f4ab84712ee50272b23 Mon Sep 17 00:00:00 2001 From: Brett Profitt Date: Sun, 3 Jul 2011 17:41:20 -0400 Subject: Merged ACL fixes from 1.7 branch. --- actions/friends/collections/add.php | 38 ++++--- actions/friends/collections/delete.php | 34 +++---- actions/friends/collections/edit.php | 20 ++-- engine/lib/access.php | 169 +++++++++++++++++--------------- engine/tests/api/access_collections.php | 100 ++++++++++++++++++- languages/en.php | 2 + 6 files changed, 231 insertions(+), 132 deletions(-) (limited to 'engine/tests') diff --git a/actions/friends/collections/add.php b/actions/friends/collections/add.php index 8ec6a085f..8383e4db2 100644 --- a/actions/friends/collections/add.php +++ b/actions/friends/collections/add.php @@ -2,35 +2,31 @@ /** * Elgg collection add page * - * @package Elgg.Core - * @subpackage Friends.Collections + * @package Elgg + * @subpackage Core */ $collection_name = get_input('collection_name'); $friends = get_input('friends_collection'); -//first check to make sure that a collection name has been set and create the new colection -if ($collection_name) { +if (!$collection_name) { + register_error(elgg_echo("friends:nocollectionname")); + forward(REFERER); +} - //create the collection - $create_collection = create_access_collection($collection_name, elgg_get_logged_in_user_guid()); +$id = create_access_collection($collection_name); - //if the collection was created and the user passed some friends from the form, add them - if ($create_collection && (!empty($friends))) { - //add friends to the collection - foreach ($friends as $friend) { - add_user_to_access_collection($friend, $create_collection); - } +if ($id) { + $result = update_access_collection($id, $friends); + if ($result) { + system_message(elgg_echo("friends:collectionadded")); + // go to the collections page + forward("pg/collections/" . get_loggedin_user()->username); + } else { + register_error(elgg_echo("friends:nocollectionname")); + forward(REFERER); } - - // Success message - system_message(elgg_echo("friends:collectionadded")); - // Forward to the collections page - forward("collections/" . elgg_get_logged_in_user_entity()->username); - } else { register_error(elgg_echo("friends:nocollectionname")); - - // Forward to the add collection page - forward("collections/add"); + forward(REFERER); } diff --git a/actions/friends/collections/delete.php b/actions/friends/collections/delete.php index fe719d74b..5b0aa8e10 100644 --- a/actions/friends/collections/delete.php +++ b/actions/friends/collections/delete.php @@ -1,36 +1,24 @@ owner_guid == elgg_get_logged_in_user_guid()) { - - $delete_collection = delete_access_collection($collection_id); +// check the ACL exists and we can edit +if (!can_edit_access_collection($collection_id)) { + register_error(elgg_echo("friends:collectiondeletefailed")); + forward(REFERER); +} - // Success message - if ($delete_collection) { - system_message(elgg_echo("friends:collectiondeleted")); - } else { - register_error(elgg_echo("friends:collectiondeletefailed")); - } - } else { - // Failure message - register_error(elgg_echo("friends:collectiondeletefailed")); - } +if (delete_access_collection($collection_id)) { + system_message(elgg_echo("friends:collectiondeleted")); } else { - // Failure message register_error(elgg_echo("friends:collectiondeletefailed")); } -// Forward to the collections page -forward("collections/" . elgg_get_logged_in_user_entity()->username); +forward(REFERER); diff --git a/actions/friends/collections/edit.php b/actions/friends/collections/edit.php index b7fb716f2..581b21353 100644 --- a/actions/friends/collections/edit.php +++ b/actions/friends/collections/edit.php @@ -1,15 +1,23 @@ getGUID(), null, true); + + // don't ignore access when checking users. + if ($user_guid) { + return array_key_exists($collection_id, $write_access); + } else { + return elgg_get_ignore_access() || array_key_exists($collection_id, $write_access); + } +} + +/** + * Creates a new access control collection owned by the specified user. * * Access colletions allow plugins and users to create granular access * for entities. @@ -448,6 +484,7 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) { SET name = '{$name}', owner_guid = {$owner_guid}, site_guid = {$site_guid}"; + if (!$id = insert_data($q)) { return false; } @@ -483,37 +520,31 @@ function create_access_collection($name, $owner_guid = 0, $site_guid = 0) { function update_access_collection($collection_id, $members) { global $CONFIG; - $collection_id = (int) $collection_id; - $members = (is_array($members)) ? $members : array(); + $acl = get_access_collection($collection_id); - $collections = get_write_access_array(); + if (!$acl) { + return false; + } - if (array_key_exists($collection_id, $collections)) { - $cur_members = get_members_of_access_collection($collection_id, true); - $cur_members = (is_array($cur_members)) ? $cur_members : array(); + $members = (is_array($members)) ? $members : array(); - $remove_members = array_diff($cur_members, $members); - $add_members = array_diff($members, $cur_members); + $cur_members = get_members_of_access_collection($collection_id, true); + $cur_members = (is_array($cur_members)) ? $cur_members : array(); - $params = array( - 'collection_id' => $collection_id, - 'members' => $members, - 'add_members' => $add_members, - 'remove_members' => $remove_members - ); + $remove_members = array_diff($cur_members, $members); + $add_members = array_diff($members, $cur_members); - foreach ($add_members as $guid) { - add_user_to_access_collection($guid, $collection_id); - } + $result = true; - foreach ($remove_members as $guid) { - remove_user_from_access_collection($guid, $collection_id); - } + foreach ($add_members as $guid) { + $result = $result && add_user_to_access_collection($guid, $collection_id); + } - return true; + foreach ($remove_members as $guid) { + $result = $result && remove_user_from_access_collection($guid, $collection_id); } - return false; + return $result; } /** @@ -527,27 +558,25 @@ function update_access_collection($collection_id, $members) { * @see update_access_collection() */ function delete_access_collection($collection_id) { + global $CONFIG; + $collection_id = (int) $collection_id; - $collections = get_write_access_array(null, null, TRUE); $params = array('collection_id' => $collection_id); if (!elgg_trigger_plugin_hook('access:collections:deletecollection', 'collection', $params, true)) { return false; } - if (array_key_exists($collection_id, $collections)) { - global $CONFIG; - $query = "delete from {$CONFIG->dbprefix}access_collection_membership" - . " where access_collection_id = {$collection_id}"; - delete_data($query); + // Deleting membership doesn't affect result of deleting ACL. + $q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership + WHERE access_collection_id = {$collection_id}"; + delete_data($q); - $query = "delete from {$CONFIG->dbprefix}access_collections where id = {$collection_id}"; - delete_data($query); - return true; - } else { - return false; - } + $q = "DELETE FROM {$CONFIG->dbprefix}access_collections + WHERE id = {$collection_id}"; + $result = delete_data($q); + return $result; } /** @@ -584,45 +613,33 @@ function get_access_collection($collection_id) { * @see remove_user_from_access_collection() */ function add_user_to_access_collection($user_guid, $collection_id) { + global $CONFIG; + $collection_id = (int) $collection_id; $user_guid = (int) $user_guid; - $collections = get_write_access_array(); + $user = get_user($user_guid); - if (!($collection = get_access_collection($collection_id))) { - return false; - } + $collection = get_access_collection($collection_id); - $user = get_user($user_guid); - if (!$user) { + if (!($user instanceof Elgguser) || !$collection) { return false; } - // to add someone to a collection, the user must be a member of the collection or - // no one must own it - if ((array_key_exists($collection_id, $collections) || $collection->owner_guid == 0)) { - $result = true; - } else { - $result = false; - } - $params = array( 'collection_id' => $collection_id, - 'collection' => $collection, 'user_guid' => $user_guid ); - $result = elgg_trigger_plugin_hook('access:collections:add_user', 'collection', $params, $result); - if ($result == false) { + if (!elgg_trigger_plugin_hook('access:collections:add_user', 'collection', $params, true)) { return false; } try { - global $CONFIG; - $query = "insert into {$CONFIG->dbprefix}access_collection_membership" - . " set access_collection_id = {$collection_id}, user_guid = {$user_guid}"; - insert_data($query); + $q = "INSERT INTO {$CONFIG->dbprefix}access_collection_membership + SET access_collection_id = {$collection_id}, + user_guid = {$user_guid}"; + insert_data($q); } catch (DatabaseException $e) { - // nothing. return false; } @@ -640,34 +657,32 @@ function add_user_to_access_collection($user_guid, $collection_id) { * @return true|false Depending on success */ function remove_user_from_access_collection($user_guid, $collection_id) { + global $CONFIG; + $collection_id = (int) $collection_id; $user_guid = (int) $user_guid; - $collections = get_write_access_array(); - $user = $user = get_user($user_guid); + $user = get_user($user_guid); - if (!($collection = get_access_collection($collection_id))) { + $collection = get_access_collection($collection_id); + + if (!($user instanceof Elgguser) || !$collection) { return false; } - if ((array_key_exists($collection_id, $collections) || $collection->owner_guid == 0) && $user) { - global $CONFIG; - $params = array( - 'collection_id' => $collection_id, - 'user_guid' => $user_guid - ); - - if (!elgg_trigger_plugin_hook('access:collections:remove_user', 'collection', $params, true)) { - return false; - } - - delete_data("delete from {$CONFIG->dbprefix}access_collection_membership " - . "where access_collection_id = {$collection_id} and user_guid = {$user_guid}"); - - return true; + $params = array( + 'collection_id' => $collection_id, + 'user_guid' => $user_guid + ); + if (!elgg_trigger_plugin_hook('access:collections:remove_user', 'collection', $params, true)) { + return false; } - return false; + $q = "DELETE FROM {$CONFIG->dbprefix}access_collection_membership + WHERE access_collection_id = {$collection_id} + AND user_guid = {$user_guid}"; + + return delete_data($q); } /** @@ -972,4 +987,4 @@ elgg_register_event_handler('init', 'system', 'access_init', 9999); elgg_register_plugin_hook_handler('permissions_check', 'all', 'elgg_override_permissions_hook'); elgg_register_plugin_hook_handler('container_permissions_check', 'all', 'elgg_override_permissions_hook'); -elgg_register_plugin_hook('unit_test', 'system', 'access_test'); +elgg_register_plugin_hook_handler('unit_test', 'system', 'access_test'); diff --git a/engine/tests/api/access_collections.php b/engine/tests/api/access_collections.php index 060587d78..d81589cc1 100644 --- a/engine/tests/api/access_collections.php +++ b/engine/tests/api/access_collections.php @@ -151,20 +151,110 @@ class ElggCoreAccessCollectionsTest extends ElggCoreUnitTest { $user->delete(); } - // groups interface - public function testNewGroupCreateACL() { + public function testCanEditACL() { + $acl_id = create_access_collection('test acl', $this->user->guid); + + // should be true since it's the owner + $result = can_edit_access_collection($acl_id, $this->user->guid); + $this->assertTrue($result); + + // should be true since IA is on. + $ia = elgg_set_ignore_access(true); + $result = can_edit_access_collection($acl_id); + $this->assertTrue($result); + elgg_set_ignore_access($ia); + // should be false since IA is off + $ia = elgg_set_ignore_access(false); + $result = can_edit_access_collection($acl_id); + $this->assertFalse($result); + elgg_set_ignore_access($ia); + + delete_access_collection($acl_id); } - public function testDeleteGroupDeleteACL() { + public function testCanEditACLHook() { + // if only we supported closures! + global $acl_test_info; + + $acl_id = create_access_collection('test acl'); + + $acl_test_info = array( + 'acl_id' => $acl_id, + 'user' => $this->user + ); + + function test_acl_access_hook($hook, $type, $value, $params) { + global $acl_test_info; + if ($params['user_id'] == $acl_test_info['user']->guid) { + $acl = get_access_collection($acl_test_info['acl_id']); + $value[$acl->id] = $acl->name; + } + + return $value; + } + + register_plugin_hook('access:collections:write', 'all', 'test_acl_access_hook'); + + // enable security since we usually run as admin + $ia = elgg_set_ignore_access(false); + $result = can_edit_access_collection($acl_id, $this->user->guid); + $this->assertTrue($result); + $ia = elgg_set_ignore_access($ia); + unregister_plugin_hook('access:collections:write', 'all', 'test_acl_access_hook'); } - public function testJoinGroupJoinACL() { + // groups interface + // only runs if the groups plugin is enabled because implementation is split between + // core and the plugin. + public function testCreateDeleteGroupACL() { + if (!is_plugin_enabled('groups')) { + return; + } + + $group = new ElggGroup(); + $group->name = 'Test group'; + $group->save(); + $acl = get_access_collection($group->group_acl); + // ACLs are owned by groups + $this->assertEqual($acl->owner_guid, $group->guid); + + // removing group and acl + $this->assertTrue($group->delete()); + + $acl = get_access_collection($group->group_acl); + $this->assertFalse($acl); + + $group->delete(); } - public function testLeaveGroupLeaveACL() { + public function testJoinLeaveGroupACL() { + if (!is_plugin_enabled('groups')) { + return; + } + + $group = new ElggGroup(); + $group->name = 'Test group'; + $group->save(); + + $result = $group->join($this->user); + $this->assertTrue($result); + + if ($result) { + $can_edit = can_edit_access_collection($group->group_acl, $this->user->guid); + $this->assertTrue($can_edit); + } + + $result = $group->leave($this->user); + $this->assertTrue($result); + + if ($result) { + $can_edit = can_edit_access_collection($group->group_acl, $this->user->guid); + $this->assertFalse($can_edit); + } + $group->delete(); } } diff --git a/languages/en.php b/languages/en.php index c30a1bdd8..b525a2043 100644 --- a/languages/en.php +++ b/languages/en.php @@ -343,6 +343,8 @@ $english = array( 'friends:nocollectionname' => "You need to give your collection a name before it can be created.", 'friends:collections:members' => "Collection members", 'friends:collections:edit' => "Edit collection", + 'friends:collections:edited' => "Saved collection", + 'friends:collection:edit_failed' => 'Could not save collection.', 'friendspicker:chararray' => 'ABCDEFGHIJKLMNOPQRSTUVWXYZ', -- cgit v1.2.3 From f068068add8645dc359fdcb00b7745a918c1c81e Mon Sep 17 00:00:00 2001 From: Brett Profitt Date: Wed, 6 Jul 2011 21:00:20 -0400 Subject: Revert "Fixes #3552. Addess ACL unit tests. These currently fail because of #3522." This reverts commit d423aee393458d6827dbe913ceacd29171fa3d74. Removing because of problems with differences in how 1.7 and 1.8 populate the acl dropdown for groups. --- engine/lib/access.php | 11 -- engine/tests/api/access_collections.php | 260 -------------------------------- 2 files changed, 271 deletions(-) delete mode 100644 engine/tests/api/access_collections.php (limited to 'engine/tests') diff --git a/engine/lib/access.php b/engine/lib/access.php index ab4580bae..855d0d53c 100644 --- a/engine/lib/access.php +++ b/engine/lib/access.php @@ -971,20 +971,9 @@ function elgg_override_permissions_hook() { return NULL; } -/** - * Runs unit tests for the entities object. - */ -function access_test($hook, $type, $value, $params) { - global $CONFIG; - $value[] = $CONFIG->path . 'engine/tests/api/access_collections.php'; - return $value; -} - // This function will let us know when 'init' has finished elgg_register_event_handler('init', 'system', 'access_init', 9999); // For overrided permissions elgg_register_plugin_hook_handler('permissions_check', 'all', 'elgg_override_permissions_hook'); elgg_register_plugin_hook_handler('container_permissions_check', 'all', 'elgg_override_permissions_hook'); - -elgg_register_plugin_hook_handler('unit_test', 'system', 'access_test'); diff --git a/engine/tests/api/access_collections.php b/engine/tests/api/access_collections.php deleted file mode 100644 index d81589cc1..000000000 --- a/engine/tests/api/access_collections.php +++ /dev/null @@ -1,260 +0,0 @@ -dbPrefix = get_config("dbprefix"); - - $user = new ElggUser(); - $user->username = 'test_user_' . rand(); - $user->email = 'fake_email@fake.com' . rand(); - $user->name = 'fake user'; - $user->access_id = ACCESS_PUBLIC; - $user->salt = generate_random_cleartext_password(); - $user->password = generate_user_password($user, rand()); - $user->owner_guid = 0; - $user->container_guid = 0; - $user->save(); - - $this->user = $user; - } - - /** - * Called before each test method. - */ - public function setUp() { - - } - - /** - * Called after each test method. - */ - public function tearDown() { - // do not allow SimpleTest to interpret Elgg notices as exceptions - $this->swallowErrors(); - } - - /** - * Called after each test object. - */ - public function __destruct() { - // all __destruct() code should go above here - $this->user->delete(); - parent::__destruct(); - } - - public function testCreateGetDeleteACL() { - global $DB_QUERY_CACHE; - - $acl_name = 'test access collection'; - $acl_id = create_access_collection($acl_name); - - $this->assertTrue(is_int($acl_id)); - - $q = "SELECT * FROM {$this->dbPrefix}access_collections WHERE id = $acl_id"; - $acl = get_data_row($q); - - $this->assertEqual($acl->id, $acl_id); - - if ($acl) { - $DB_QUERY_CACHE = array(); - - $this->assertEqual($acl->name, $acl_name); - - $result = delete_access_collection($acl_id); - $this->assertTrue($result); - - $q = "SELECT * FROM {$this->dbPrefix}access_collections WHERE id = $acl_id"; - $data = get_data($q); - $this->assertFalse($data); - } - } - - public function testAddRemoveUserToACL() { - $acl_id = create_access_collection('test acl'); - - $result = add_user_to_access_collection($this->user->guid, $acl_id); - $this->assertTrue($result); - - if ($result) { - $result = remove_user_from_access_collection($this->user->guid, $acl_id); - $this->assertTrue($result); - } - - delete_access_collection($acl_id); - } - - public function testUpdateACL() { - // another fake user to test with - $user = new ElggUser(); - $user->username = 'test_user_' . rand(); - $user->email = 'fake_email@fake.com' . rand(); - $user->name = 'fake user'; - $user->access_id = ACCESS_PUBLIC; - $user->salt = generate_random_cleartext_password(); - $user->password = generate_user_password($user, rand()); - $user->owner_guid = 0; - $user->container_guid = 0; - $user->save(); - - $acl_id = create_access_collection('test acl'); - - $member_lists = array( - // adding - array( - $this->user->guid, - $user->guid - ), - // removing one, keeping one. - array( - $user->guid - ), - // removing one, adding one - array( - $this->user->guid, - ), - // removing all. - array() - ); - - foreach ($member_lists as $members) { - $result = update_access_collection($acl_id, $members); - $this->assertTrue($result); - - if ($result) { - $q = "SELECT * FROM {$this->dbPrefix}access_collection_membership - WHERE access_collection_id = $acl_id"; - $data = get_data($q); - - if (count($members) == 0) { - $this->assertFalse($data); - } else { - $this->assertEqual(count($members), count($data)); - } - foreach ($data as $row) { - $this->assertTrue(in_array($row->user_guid, $members)); - } - } - } - - delete_access_collection($acl_id); - $user->delete(); - } - - public function testCanEditACL() { - $acl_id = create_access_collection('test acl', $this->user->guid); - - // should be true since it's the owner - $result = can_edit_access_collection($acl_id, $this->user->guid); - $this->assertTrue($result); - - // should be true since IA is on. - $ia = elgg_set_ignore_access(true); - $result = can_edit_access_collection($acl_id); - $this->assertTrue($result); - elgg_set_ignore_access($ia); - - // should be false since IA is off - $ia = elgg_set_ignore_access(false); - $result = can_edit_access_collection($acl_id); - $this->assertFalse($result); - elgg_set_ignore_access($ia); - - delete_access_collection($acl_id); - } - - public function testCanEditACLHook() { - // if only we supported closures! - global $acl_test_info; - - $acl_id = create_access_collection('test acl'); - - $acl_test_info = array( - 'acl_id' => $acl_id, - 'user' => $this->user - ); - - function test_acl_access_hook($hook, $type, $value, $params) { - global $acl_test_info; - if ($params['user_id'] == $acl_test_info['user']->guid) { - $acl = get_access_collection($acl_test_info['acl_id']); - $value[$acl->id] = $acl->name; - } - - return $value; - } - - register_plugin_hook('access:collections:write', 'all', 'test_acl_access_hook'); - - // enable security since we usually run as admin - $ia = elgg_set_ignore_access(false); - $result = can_edit_access_collection($acl_id, $this->user->guid); - $this->assertTrue($result); - $ia = elgg_set_ignore_access($ia); - - unregister_plugin_hook('access:collections:write', 'all', 'test_acl_access_hook'); - } - - // groups interface - // only runs if the groups plugin is enabled because implementation is split between - // core and the plugin. - public function testCreateDeleteGroupACL() { - if (!is_plugin_enabled('groups')) { - return; - } - - $group = new ElggGroup(); - $group->name = 'Test group'; - $group->save(); - $acl = get_access_collection($group->group_acl); - - // ACLs are owned by groups - $this->assertEqual($acl->owner_guid, $group->guid); - - // removing group and acl - $this->assertTrue($group->delete()); - - $acl = get_access_collection($group->group_acl); - $this->assertFalse($acl); - - $group->delete(); - } - - public function testJoinLeaveGroupACL() { - if (!is_plugin_enabled('groups')) { - return; - } - - $group = new ElggGroup(); - $group->name = 'Test group'; - $group->save(); - - $result = $group->join($this->user); - $this->assertTrue($result); - - if ($result) { - $can_edit = can_edit_access_collection($group->group_acl, $this->user->guid); - $this->assertTrue($can_edit); - } - - $result = $group->leave($this->user); - $this->assertTrue($result); - - if ($result) { - $can_edit = can_edit_access_collection($group->group_acl, $this->user->guid); - $this->assertFalse($can_edit); - } - - $group->delete(); - } -} -- cgit v1.2.3 From 8a2559a63b5eb09dbd736161247bc103c2c4d18a Mon Sep 17 00:00:00 2001 From: Brett Profitt Date: Mon, 15 Aug 2011 20:52:43 -0700 Subject: Refs #3355. Added ElggPriorityList. --- engine/classes/ElggPriorityList.php | 306 ++++++++++++++++++++++++++++++++++++ engine/tests/api/helpers.php | 256 +++++++++++++++++++++++++++++- 2 files changed, 561 insertions(+), 1 deletion(-) create mode 100644 engine/classes/ElggPriorityList.php (limited to 'engine/tests') diff --git a/engine/classes/ElggPriorityList.php b/engine/classes/ElggPriorityList.php new file mode 100644 index 000000000..39fe698da --- /dev/null +++ b/engine/classes/ElggPriorityList.php @@ -0,0 +1,306 @@ +add('Element 0'); + * $pl->add('Element -5', -5); + * $pl->add('Element 10', 10); + * $pl->add('Element -10', -10); + * + * $pl->remove('Element -5'); + * + * $elements = $pl->getElements(); + * var_dump($elements); + * + * Yields: + * + * array( + * -10 => 'Element -10', + * 0 => 'Element 0', + * 10 => 'Element 10', + * ) + * + * + * // Array + * $pl = new ElggPriorityList(); + * $pl[] = 'Element 0'; + * $pl[-5] = 'Element -5'; + * $pl[10] = 'Element 10'; + * $pl[-10] = 'Element -10'; + * + * $priority = $pl->getPriority('Element -5'); + * unset($pl[$priority]); + * + * foreach ($pl as $priority => $element) { + * var_dump("$priority => $element"); + * } + * + * Yields: + * -10 => Element -10 + * 0 => Element 0 + * 10 => Element 10 + * + * + * Collisions with priority are handled by inserting the element as close to the requested priority + * as possible. + * + * $pl = new ElggPriorityList(); + * $pl[5] = 'Element 5'; + * $pl[5] = 'Colliding element 5'; + * $pl[5] = 'Another colliding element 5'; + * + * var_dump($pl->getElements()); + * + * Yields: + * + * array( + * 5 => 'Element 5', + * 6 => 'Colliding element 5', + * 7 => 'Another colliding element 5' + * ) + * + * @package Elgg.Core + * @subpackage Helpers + */ + +class ElggPriorityList + implements Iterator, ArrayAccess, Countable { + + /** + * The list of elements + * + * @var array + */ + private $elements = array(); + + /** + * Create a new priority list. + * + * @param array $elements An optional array of priorities => element + */ + public function __construct(array $elements = array()) { + if ($elements) { + foreach ($elements as $priority => $element) { + $this->add($element, $priority); + } + } + } + + /** + * Adds an element to the list. + * + * @warning This returns the priority at which the element was added, which can be 0. Use + * !== false to check for success. + * + * @param mixed $element The element to add to the list. + * @param mixed $priority Priority to add the element. In priority collisions, the original element + * maintains its priority and the new element is to the next available + * slot, taking into consideration all previously registered elements. + * Negative elements are accepted. + * @return int The priority the element was added at. + */ + public function add($element, $priority = null) { + if ($priority !== null && !is_numeric($priority)) { + return false; + } else { + $priority = $this->getNextPriority($priority); + } + + $this->elements[$priority] = $element; + return $priority; + } + + /** + * Removes an element from the list. + * + * @warning The element must have the same attributes / values. If using $strict, it must have + * the same types. array(10) will fail in strict against array('10') (str vs int). + * + * @param type $element + * @return bool + */ + public function remove($element, $strict = false) { + $index = array_search($element, $this->elements, $strict); + if ($index !== false) { + unset($this->elements[$index]); + return true; + } else { + return false; + } + } + + /** + * Returns the elements + * + * @param type $elements + * @param type $sort + */ + public function getElements() { + $this->sortIfUnsorted(); + return $this->elements; + } + + /** + * Sort the elements optionally by a callback function. + * + * If no user function is provided the elements are sorted by priority registered. + * + * The callback function should accept the array of elements as the first argument and should + * return a sorted array. + * + * This function can be called multiple times. + * + * @param type $callback + * @return bool + */ + public function sort($callback = null) { + if (!$callback) { + ksort($this->elements, SORT_NUMERIC); + } else { + $sorted = call_user_func($callback, $this->elements); + + if (!$sorted) { + return false; + } + + $this->elements = $sorted; + } + + $this->sorted = true; + return true; + } + + /** + * Sort the elements if they haven't been sorted yet. + * + * @return bool + */ + private function sortIfUnsorted() { + if (!$this->sorted) { + return $this->sort(); + } + } + + /** + * Returns the next priority available. + * + * @param int $near Make the priority as close to $near as possible. + * @return int + */ + public function getNextPriority($near = 0) { + $near = (int) $near; + + while (array_key_exists($near, $this->elements)) { + $near++; + } + + return $near; + } + + + /** + * Returns the priority of an element if it exists in the list. + * + * @warning This can return 0 if the element's priority is 0. Use identical operator (===) to + * check for false if you want to know if an element exists. + * + * @param mixed $element + * @return mixed False if the element doesn't exists, the priority if it does. + */ + public function getPriority($element, $strict = false) { + return array_search($element, $this->elements, $strict); + } + + /********************** + * Interfaces methods * + **********************/ + + + /** + * Iterator + */ + + /** + * PHP Iterator Interface + * + * @see Iterator::rewind() + * @return void + */ + public function rewind() { + $this->sortIfUnsorted(); + return rewind($this->elements); + } + + /** + * PHP Iterator Interface + * + * @see Iterator::current() + * @return mixed + */ + public function current() { + $this->sortIfUnsorted(); + return current($this->elements); + } + + /** + * PHP Iterator Interface + * + * @see Iterator::key() + * @return int + */ + public function key() { + $this->sortIfUnsorted(); + return key($this->elements); + } + + /** + * PHP Iterator Interface + * + * @see Iterator::next() + * @return mixed + */ + public function next() { + $this->sortIfUnsorted(); + return next($this->elements); + } + + /** + * PHP Iterator Interface + * + * @see Iterator::valid() + * @return bool + */ + public function valid() { + $this->sortIfUnsorted(); + $key = key($this->elements); + return ($key !== NULL && $key !== FALSE); + } + + // Coutable + public function count() { + return count($this->elements); + } + + // ArrayAccess + public function offsetExists($offset) { + return isset($this->elements[$offset]); + } + + public function offsetGet($offset) { + return isset($this->elements[$offset]) ? $this->elements[$offset] : null; + } + + public function offsetSet($offset, $value) { + return $this->add($value, $offset); + } + + public function offsetUnset($offset) { + if (isset($this->elements[$offset])) { + unset($this->elements[$offset]); + } + } +} \ No newline at end of file diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php index 461627547..033970359 100644 --- a/engine/tests/api/helpers.php +++ b/engine/tests/api/helpers.php @@ -187,4 +187,258 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $js_urls = elgg_get_loaded_js('footer'); $this->assertIdentical(array(), $js_urls); } -} + + // test ElggPriorityList + public function testElggPriorityListAdd() { + $pl = new ElggPriorityList(); + $elements = array( + 'Test value', + 'Test value 2', + 'Test value 3' + ); + + shuffle($elements); + + foreach ($elements as $element) { + $this->assertTrue($pl->add($element) !== false); + } + + $test_elements = $pl->getElements(); + + $this->assertTrue(is_array($test_elements)); + + foreach ($test_elements as $i => $element) { + // should be in the array + $this->assertTrue(in_array($element, $elements)); + + // should be the only element, so priority 0 + $this->assertEqual($i, array_search($element, $elements)); + } + } + + public function testElggPriorityListAddWithPriority() { + $pl = new ElggPriorityList(); + + $elements = array( + 10 => 'Test Element 10', + 5 => 'Test Element 5', + 0 => 'Test Element 0', + 100 => 'Test Element 100', + -1 => 'Test Element -1', + -5 => 'Test Element -5' + ); + + foreach ($elements as $priority => $element) { + $pl->add($element, $priority); + } + + $test_elements = $pl->getElements(); + + // should be sorted by priority + $elements_sorted = array( + -5 => 'Test Element -5', + -1 => 'Test Element -1', + 0 => 'Test Element 0', + 5 => 'Test Element 5', + 10 => 'Test Element 10', + 100 => 'Test Element 100', + ); + + $this->assertIdentical($elements_sorted, $test_elements); + + foreach ($test_elements as $priority => $element) { + $this->assertIdentical($elements[$priority], $element); + } + } + + public function testElggPriorityListGetNextPriority() { + $pl = new ElggPriorityList(); + + $elements = array( + 2 => 'Test Element', + 0 => 'Test Element 2', + -2 => 'Test Element 3', + ); + + foreach ($elements as $priority => $element) { + $pl->add($element, $priority); + } + + // we're not specifying a priority so it should be the next consecutive to 0. + $this->assertEqual(1, $pl->getNextPriority()); + + // add another one at priority 1 + $pl->add('Test Element 1'); + + // next consecutive to 0 is now 3. + $this->assertEqual(3, $pl->getNextPriority()); + } + + public function testElggPriorityListRemove() { + $pl = new ElggPriorityList(); + + $elements = array(); + for ($i=0; $i<3; $i++) { + $element = new stdClass(); + $element->name = "Test Element $i"; + $element->someAttribute = rand(0, 9999); + $elements[] = $element; + $pl->add($element); + } + + $pl->remove($elements[1]); + + $test_elements = $pl->getElements(); + + // make sure it's gone. + $this->assertTrue(2, count($test_elements)); + $this->assertIdentical($elements[0], $test_elements[0]); + $this->assertIdentical($elements[2], $test_elements[2]); + } + + public function testElggPriorityListConstructor() { + $elements = array( + 10 => 'Test Element 10', + 5 => 'Test Element 5', + 0 => 'Test Element 0', + 100 => 'Test Element 100', + -1 => 'Test Element -1', + -5 => 'Test Element -5' + ); + + $pl = new ElggPriorityList($elements); + $test_elements = $pl->getElements(); + + $elements_sorted = array( + -5 => 'Test Element -5', + -1 => 'Test Element -1', + 0 => 'Test Element 0', + 5 => 'Test Element 5', + 10 => 'Test Element 10', + 100 => 'Test Element 100', + ); + + $this->assertIdentical($elements_sorted, $test_elements); + } + + public function testElggPriorityListGetPriority() { + $pl = new ElggPriorityList(); + + $elements = array( + 'Test element 0', + 'Test element 1', + 'Test element 2', + ); + + foreach ($elements as $element) { + $pl->add($element); + } + + $this->assertIdentical(0, $pl->getPriority($elements[0])); + $this->assertIdentical(1, $pl->getPriority($elements[1])); + $this->assertIdentical(2, $pl->getPriority($elements[2])); + } + + public function testElggPriorityListPriorityCollision() { + $pl = new ElggPriorityList(); + + $elements = array( + 5 => 'Test element 5', + 6 => 'Test element 6', + 0 => 'Test element 0', + ); + + foreach ($elements as $priority => $element) { + $pl->add($element, $priority); + } + + // add at a colliding priority + $pl->add('Colliding element', 5); + + // should float to the top closest to 5, so 7 + $this->assertEqual(7, $pl->getPriority('Colliding element')); + } + + public function testElggPriorityListArrayAccess() { + $pl = new ElggPriorityList(); + $pl[] = 'Test element 0'; + $pl[-10] = 'Test element -10'; + $pl[-1] = 'Test element -1'; + $pl[] = 'Test element 1'; + $pl[5] = 'Test element 5'; + $pl[0] = 'Test element collision with 0 (should be 2)'; + + $elements = array( + -1 => 'Test element -1', + 0 => 'Test element 0', + 1 => 'Test element 1', + 2 => 'Test element collision with 0 (should be 2)', + 5 => 'Test element 5', + ); + + $priority = $pl->getPriority('Test element -10'); + unset($pl[$priority]); + + $test_elements = $pl->getElements(); + $this->assertIdentical($elements, $test_elements); + } + + public function testElggPriorityListIterator() { + $elements = array( + -5 => 'Test element -5', + 0 => 'Test element 0', + 5 => 'Test element 5' + ); + + $pl = new ElggPriorityList($elements); + + foreach ($pl as $priority => $element) { + $this->assertIdentical($elements[$priority], $element); + } + } + + public function testElggPriorityListCountable() { + $pl = new ElggPriorityList(); + + $this->assertEqual(0, count($pl)); + + $pl[] = 'Test element 0'; + $this->assertEqual(1, count($pl)); + + $pl[] = 'Test element 1'; + $this->assertEqual(2, count($pl)); + + $pl[] = 'Test element 2'; + $this->assertEqual(3, count($pl)); + } + + public function testElggPriorityListUserSort() { + $elements = array( + 'A', + 'B', + 'C', + 'D', + 'E', + ); + + $elements_sorted_string = $elements; + + shuffle($elements); + $pl = new ElggPriorityList($elements); + + // will sort by priority + $test_elements = $pl->getElements(); + $this->assertIdentical($elements, $test_elements); + + function test_sort($elements) { + sort($elements, SORT_LOCALE_STRING); + return $elements; + } + + // force a new sort using our function + $pl->sort('test_sort'); + $test_elements = $pl->getElements(); + + $this->assertIdentical($elements_sorted_string, $test_elements); + } +} \ No newline at end of file -- cgit v1.2.3 From 62a8253d2afbb682d73939bd68e58cf81f54e663 Mon Sep 17 00:00:00 2001 From: Brett Profitt Date: Wed, 17 Aug 2011 18:22:13 -0700 Subject: Finished ElggPriorityList. Migrated external files to use it. --- engine/classes/ElggPriorityList.php | 96 ++++++++++++++++++++++++++++--- engine/lib/elgglib.php | 112 ++++++++++++++++++++++++++++-------- engine/tests/api/helpers.php | 75 +++++++++++++++++++++--- 3 files changed, 241 insertions(+), 42 deletions(-) (limited to 'engine/tests') diff --git a/engine/classes/ElggPriorityList.php b/engine/classes/ElggPriorityList.php index 39fe698da..931138106 100644 --- a/engine/classes/ElggPriorityList.php +++ b/engine/classes/ElggPriorityList.php @@ -26,6 +26,7 @@ * * * // Array + * * $pl = new ElggPriorityList(); * $pl[] = 'Element 0'; * $pl[-5] = 'Element -5'; @@ -45,24 +46,45 @@ * 10 => Element 10 * * - * Collisions with priority are handled by inserting the element as close to the requested priority - * as possible. + * Collisions with priority are handled by default differently in the OOP and the array interfaces. + * + * If using the OOP interface, the default is to insert the element as close to the requested + * priority as possible. * * $pl = new ElggPriorityList(); - * $pl[5] = 'Element 5'; - * $pl[5] = 'Colliding element 5'; - * $pl[5] = 'Another colliding element 5'; + * $pl->add('Element 5', 5); + * $pl->add('Colliding element 5', 5); + * $pl->add('Another colliding element 5', 5); * * var_dump($pl->getElements()); * * Yields: - * * array( * 5 => 'Element 5', * 6 => 'Colliding element 5', * 7 => 'Another colliding element 5' * ) * + * If using the array interface, elements are added at exactly the priority, displacing other + * elements if necessary. This behavior is also available by passing true as the 3rd argument to + * ->add(): + * + * $pl = new ElggPriorityList(); + * $pl[5] = 'Element 5'; + * $pl[6] = 'Element 6'; + * $pl[5] = 'Colliding element 5'; // shifts the previous two up by one + * $pl->add('Another colliding element 5', 5, true); // shifts the previous three up by one + * + * var_dump($pl->getElements()); + * + * Yields: + * array( + * 5 => 'Another colliding element 5', + * 6 => 'Colliding element 5', + * 7 => 'Element 5', + * 8 => 'Element 6' + * ) + * * @package Elgg.Core * @subpackage Helpers */ @@ -101,16 +123,21 @@ class ElggPriorityList * maintains its priority and the new element is to the next available * slot, taking into consideration all previously registered elements. * Negative elements are accepted. - * @return int The priority the element was added at. + * @param bool $exact If true, will put the element at exactly the priority specified, displacing + * other elements. + * @return int The priority of the added element. */ - public function add($element, $priority = null) { + public function add($element, $priority = null, $exact = false) { if ($priority !== null && !is_numeric($priority)) { return false; + } elseif ($exact) { + $this->shiftElementsSegment($priority); } else { $priority = $this->getNextPriority($priority); } $this->elements[$priority] = $element; + $this->sorted = false; return $priority; } @@ -133,6 +160,32 @@ class ElggPriorityList } } + /** + * Move an existing element to a new priority. + * + * @param int $current_priority + * @param int $new_priority + * @param bool $exact + * @return bool + */ + public function move($current_priority, $new_priority, $exact = false) { + $current_priority = (int) $current_priority; + $new_priority = (int) $new_priority; + + if (!isset($this->elements[$current_priority])) { + return false; + } + + if ($current_priority == $new_priority) { + return true; + } + + $element = $this->elements[$current_priority]; + unset($this->elements[$current_priority]); + + return $this->add($element, $new_priority, $exact); + } + /** * Returns the elements * @@ -185,6 +238,29 @@ class ElggPriorityList } } + /** + * Shift a segment of elements starting at $index up by one until the end of the array or + * there's a gap in the indexes. This produces a space at $index to insert a new element. + * + * @param type $index The index to start + * @return array + */ + private function shiftElementsSegment($index) { + $index = (int) $index; + // @todo probably a better way. + $replace_elements = array(); + while (isset($this->elements[$index])) { + $replace_elements[$index + 1] = $this->elements[$index]; + unset($this->elements[$index]); + $index++; + } + + // insert old ones + foreach ($replace_elements as $index => $element) { + $this->elements[$index] = $element; + } + } + /** * Returns the next priority available. * @@ -295,7 +371,9 @@ class ElggPriorityList } public function offsetSet($offset, $value) { - return $this->add($value, $offset); + // for $pl[] = 'New element' + $exact = ($offset !== null); + return $this->add($value, $offset, $exact); } public function offsetUnset($offset) { diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index cb736f418..b6b603e79 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -172,7 +172,7 @@ function forward($location = "", $reason = 'system') { * @return bool * @since 1.8.0 */ -function elgg_register_js($name, $url, $location = 'head', $priority = 500) { +function elgg_register_js($name, $url, $location = 'head', $priority = null) { return elgg_register_external_file('js', $name, $url, $location, $priority); } @@ -225,7 +225,7 @@ function elgg_get_loaded_js($location = 'head') { * @return bool * @since 1.8.0 */ -function elgg_register_css($name, $url, $priority = 500) { +function elgg_register_css($name, $url, $priority = null) { return elgg_register_external_file('css', $name, $url, 'head', $priority); } @@ -278,7 +278,7 @@ function elgg_get_loaded_css() { * @return bool * @since 1.8.0 */ -function elgg_register_external_file($type, $name, $url, $location, $priority = 500) { +function elgg_register_external_file($type, $name, $url, $location, $priority = null) { global $CONFIG; if (empty($name) || empty($url)) { @@ -292,26 +292,35 @@ function elgg_register_external_file($type, $name, $url, $location, $priority = $CONFIG->externals = array(); } - if (!isset($CONFIG->externals[$type])) { - $CONFIG->externals[$type] = array(); + if (!$CONFIG->externals[$type] instanceof ElggPriorityList) { + $CONFIG->externals[$type] = new ElggPriorityList(); } $name = trim(strtolower($name)); + $priority = max((int)$priority, 0); - if (isset($CONFIG->externals[$type][$name])) { - // update a registered item - $item = $CONFIG->externals[$type][$name]; + $index = elgg_get_external_file_priority($name, $type); + + if ($index !== false) { + // updating a registered item + $item = $CONFIG->externals[$type][$index]; + $item->url = $url; + $item->location = $location; + // remove old saved priority + elgg_remove_external_file_priority($name, $type); + $priority = $CONFIG->externals[$type]->move($index, $priority); } else { $item = new stdClass(); $item->loaded = false; - } + $item->url = $url; + $item->location = $location; - $item->url = $url; - $item->priority = max((int)$priority, 0); - $item->location = $location; + $priority = $CONFIG->externals[$type]->add($item, $priority); + } - $CONFIG->externals[$type][$name] = $item; + // save priority map so we can update if added again + elgg_save_external_file_priority($priority, $name, $type); return true; } @@ -332,14 +341,17 @@ function elgg_unregister_external_file($type, $name) { return false; } - if (!isset($CONFIG->externals[$type])) { + if (!$CONFIG->externals[$type] instanceof ElggPriorityList) { return false; } $name = trim(strtolower($name)); - if (array_key_exists($name, $CONFIG->externals[$type])) { - unset($CONFIG->externals[$type][$name]); + $priority = elgg_get_external_file_priority($name, $type); + + if ($priority !== false) { + elgg_remove_external_file_priority($name, $type); + unset($CONFIG->externals[$type][$priority]); return true; } @@ -362,24 +374,75 @@ function elgg_load_external_file($type, $name) { $CONFIG->externals = array(); } - if (!isset($CONFIG->externals[$type])) { - $CONFIG->externals[$type] = array(); + if (!$CONFIG->externals[$type] instanceof ElggPriorityList) { + $CONFIG->externals[$type] = new ElggPriorityList(); } $name = trim(strtolower($name)); - if (isset($CONFIG->externals[$type][$name])) { + $priority = elgg_get_external_file_priority($name, $type); + + if ($priority !== false) { // update a registered item - $CONFIG->externals[$type][$name]->loaded = true; + $CONFIG->externals[$type][$priority]->loaded = true; } else { $item = new stdClass(); $item->loaded = true; $item->url = ''; $item->location = ''; - $item->priority = 500; - $CONFIG->externals[$type][$name] = $item; + $priority = $CONFIG->externals[$type]->add($item); + elgg_save_external_file_priority($priority, $name, $type); + } +} + +/** + * Gets the priority of an external by name and type. + * + * @param type $name + * @param type $type + * @return type + */ +function elgg_get_external_file_priority($name, $type) { + global $CONFIG; + + if (!isset($CONFIG->externals_priorities[$type][$name])) { + return false; + } + + return $CONFIG->externals_priorities[$type][$name]; +} + +function elgg_save_external_file_priority($priority, $name, $type) { + global $CONFIG; + + if (!isset($CONFIG->externals_priorities)) { + $CONFIG->externals_priorities = array(); + } + + if (!isset($CONFIG->externals_priorities[$type])) { + $CONFIG->externals_priorities[$type] = array(); + } + + $CONFIG->externals_priorities[$type][$name] = $priority; + + return true; +} + +function elgg_remove_external_file_priority($name, $type) { + global $CONFIG; + + if (!isset($CONFIG->externals_priorities)) { + $CONFIG->externals_priorities = array(); } + + if (!isset($CONFIG->externals_priorities[$type])) { + $CONFIG->externals_priorities[$type] = array(); + } + + unset($CONFIG->externals_priorities[$type][$name]); + + return true; } /** @@ -394,13 +457,12 @@ function elgg_load_external_file($type, $name) { function elgg_get_loaded_external_files($type, $location) { global $CONFIG; - if (isset($CONFIG->externals) && isset($CONFIG->externals[$type])) { - $items = array_values($CONFIG->externals[$type]); + if (isset($CONFIG->externals) && $CONFIG->externals[$type] instanceof ElggPriorityList) { + $items = $CONFIG->externals[$type]->getElements(); $callback = "return \$v->loaded == true && \$v->location == '$location';"; $items = array_filter($items, create_function('$v', $callback)); if ($items) { - usort($items, create_function('$a,$b','return $a->priority >= $b->priority;')); array_walk($items, create_function('&$v,$k', '$v = $v->url;')); } return $items; diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php index 033970359..cceb762be 100644 --- a/engine/tests/api/helpers.php +++ b/engine/tests/api/helpers.php @@ -31,6 +31,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { global $CONFIG; unset($CONFIG->externals); + unset($CONFIG->externals_priorities); } /** @@ -106,7 +107,9 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { // specify name $result = elgg_register_js('key', 'http://test1.com', 'footer'); $this->assertTrue($result); - $this->assertIdentical('http://test1.com', $CONFIG->externals['js']['key']->url); + $this->assertTrue(isset($CONFIG->externals_priorities['js']['key'])); + $index = $CONFIG->externals_priorities['js']['key']; + $this->assertIdentical('http://test1.com', $CONFIG->externals['js'][$index]->url); // send a bad url $result = @elgg_register_js('bad'); @@ -122,7 +125,9 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { // specify name $result = elgg_register_css('key', 'http://test1.com'); $this->assertTrue($result); - $this->assertIdentical('http://test1.com', $CONFIG->externals['css']['key']->url); + $this->assertTrue(isset($CONFIG->externals_priorities['css']['key'])); + $index = elgg_get_external_file_priority('css', 'key'); + $this->assertIdentical('http://test1.com', $CONFIG->externals['css'][$index]->url); } /** @@ -140,7 +145,13 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $result = elgg_unregister_js('id1'); $this->assertTrue($result); - @$this->assertNULL($CONFIG->externals['js']['head']['id1']); + + $js = $CONFIG->externals['js']; + $elements = $js->getElements(); + $this->assertFalse(isset($CONFIG->externals_priorities['js']['id1'])); + foreach ($elements as $element) { + $this->assertFalse($element->name == 'id1'); + } $result = elgg_unregister_js('id1'); $this->assertFalse($result); @@ -148,7 +159,15 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $this->assertFalse($result); $result = elgg_unregister_js('id2'); - $this->assertIdentical($urls['id3'], $CONFIG->externals['js']['id3']->url); + $elements = $js->getElements(); + $this->assertFalse(isset($CONFIG->externals_priorities['js']['id2'])); + foreach ($elements as $element) { + $this->assertFalse($element->name == 'id2'); + } + + $this->assertTrue(isset($CONFIG->externals_priorities['js']['id3'])); + $priority = $CONFIG->externals_priorities['js']['id3']; + $this->assertIdentical($urls['id3'], $CONFIG->externals['js'][$priority]->url); } /** @@ -361,18 +380,19 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { public function testElggPriorityListArrayAccess() { $pl = new ElggPriorityList(); + $pl[] = 'Test element 0'; $pl[-10] = 'Test element -10'; $pl[-1] = 'Test element -1'; $pl[] = 'Test element 1'; $pl[5] = 'Test element 5'; - $pl[0] = 'Test element collision with 0 (should be 2)'; + $pl[0] = 'Test element collision with 0'; $elements = array( -1 => 'Test element -1', - 0 => 'Test element 0', - 1 => 'Test element 1', - 2 => 'Test element collision with 0 (should be 2)', + 0 => 'Test element collision with 0', + 1 => 'Test element 0', + 2 => 'Test element 1', 5 => 'Test element 5', ); @@ -441,4 +461,43 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $this->assertIdentical($elements_sorted_string, $test_elements); } + + function testElggPriorityListShiftElementsSegment() { + $elements = array( + 0 => 'Element 0', + 1 => 'Element 1', + 2 => 'Element 2', + 4 => 'Element 4', + ); + + $pl = new ElggPriorityList($elements); + + // add a new element directly at 1. + $pl->add('New Element', 1, true); + + $elements_sorted = array( + 0 => 'Element 0', + 1 => 'New Element', + 2 => 'Element 1', + 3 => 'Element 2', + 4 => 'Element 4', + ); + + $test_elements = $pl->getElements(); + $this->assertIdentical($elements_sorted, $test_elements); + + $pl->add('New Element 10', 10, true); + + $elements_sorted = array( + 0 => 'Element 0', + 1 => 'New Element', + 2 => 'Element 1', + 3 => 'Element 2', + 4 => 'Element 4', + 10 => 'New Element 10' + ); + + $test_elements = $pl->getElements(); + $this->assertIdentical($elements_sorted, $test_elements); + } } \ No newline at end of file -- cgit v1.2.3 From 5285471b7c6f2b4ef7dc02fb2a9c231e2216eef7 Mon Sep 17 00:00:00 2001 From: Brett Profitt Date: Tue, 23 Aug 2011 15:46:22 -0700 Subject: Fixes #3355. Added ElggPriorityList. Adapted the externals system to use it. --- engine/classes/ElggPriorityList.php | 218 ++++++++++++++++-------------------- engine/lib/elgglib.php | 139 ++++++++--------------- engine/lib/views.php | 29 ++--- engine/tests/api/helpers.php | 167 +++++++++++++-------------- 4 files changed, 241 insertions(+), 312 deletions(-) (limited to 'engine/tests') diff --git a/engine/classes/ElggPriorityList.php b/engine/classes/ElggPriorityList.php index 931138106..17ce228bc 100644 --- a/engine/classes/ElggPriorityList.php +++ b/engine/classes/ElggPriorityList.php @@ -2,40 +2,11 @@ /** * Iterate over elements in a specific priority. * - * You can add, remove, and access elements using OOP or array interfaces: - * - * // OOP * $pl = new ElggPriorityList(); * $pl->add('Element 0'); - * $pl->add('Element -5', -5); * $pl->add('Element 10', 10); * $pl->add('Element -10', -10); * - * $pl->remove('Element -5'); - * - * $elements = $pl->getElements(); - * var_dump($elements); - * - * Yields: - * - * array( - * -10 => 'Element -10', - * 0 => 'Element 0', - * 10 => 'Element 10', - * ) - * - * - * // Array - * - * $pl = new ElggPriorityList(); - * $pl[] = 'Element 0'; - * $pl[-5] = 'Element -5'; - * $pl[10] = 'Element 10'; - * $pl[-10] = 'Element -10'; - * - * $priority = $pl->getPriority('Element -5'); - * unset($pl[$priority]); - * * foreach ($pl as $priority => $element) { * var_dump("$priority => $element"); * } @@ -45,52 +16,84 @@ * 0 => Element 0 * 10 => Element 10 * - * - * Collisions with priority are handled by default differently in the OOP and the array interfaces. - * - * If using the OOP interface, the default is to insert the element as close to the requested - * priority as possible. + * Collisions on priority are handled by inserting the element at or as close to the + * requested priority as possible: * * $pl = new ElggPriorityList(); * $pl->add('Element 5', 5); * $pl->add('Colliding element 5', 5); * $pl->add('Another colliding element 5', 5); * - * var_dump($pl->getElements()); + * foreach ($pl as $priority => $element) { + * var_dump("$priority => $element"); + * } * * Yields: - * array( * 5 => 'Element 5', * 6 => 'Colliding element 5', * 7 => 'Another colliding element 5' - * ) * - * If using the array interface, elements are added at exactly the priority, displacing other - * elements if necessary. This behavior is also available by passing true as the 3rd argument to - * ->add(): + * You can do priority lookups by element: * * $pl = new ElggPriorityList(); - * $pl[5] = 'Element 5'; - * $pl[6] = 'Element 6'; - * $pl[5] = 'Colliding element 5'; // shifts the previous two up by one - * $pl->add('Another colliding element 5', 5, true); // shifts the previous three up by one + * $pl->add('Element 0'); + * $pl->add('Element -5', -5); + * $pl->add('Element 10', 10); + * $pl->add('Element -10', -10); * - * var_dump($pl->getElements()); + * $priority = $pl->getPriority('Element -5'); + * + * Or element lookups by priority. + * $element = $pl->getElement(-5); * - * Yields: - * array( - * 5 => 'Another colliding element 5', - * 6 => 'Colliding element 5', - * 7 => 'Element 5', - * 8 => 'Element 6' - * ) + * To remove elements, pass the element. + * $pl->remove('Element -10'); + * + * To check if an element exists: + * $pl->contains('Element -5'); + * + * To move an element: + * $pl->move('Element -5', -3); + * + * ElggPriorityList only tracks priority. No checking is done in ElggPriorityList for duplicates or + * updating. If you need to track this use objects and an external map: + * + * function elgg_register_something($id, $display_name, $location, $priority = 500) { + * // $id => $element. + * static $map = array(); + * static $list; + * + * if (!$list) { + * $list = new ElggPriorityList(); + * } + * + * // update if already registered. + * if (isset($map[$id])) { + * $element = $map[$id]; + * // move it first because we have to pass the original element. + * if (!$list->move($element, $priority)) { + * return false; + * } + * $element->display_name = $display_name; + * $element->location = $location; + * } else { + * $element = new stdClass(); + * $element->display_name = $display_name; + * $element->location = $location; + * if (!$list->add($element, $priority)) { + * return false; + * } + * $map[$id] = $element; + * } + * + * return true; + * } * * @package Elgg.Core * @subpackage Helpers */ - class ElggPriorityList - implements Iterator, ArrayAccess, Countable { + implements Iterator, Countable { /** * The list of elements @@ -123,15 +126,11 @@ class ElggPriorityList * maintains its priority and the new element is to the next available * slot, taking into consideration all previously registered elements. * Negative elements are accepted. - * @param bool $exact If true, will put the element at exactly the priority specified, displacing - * other elements. * @return int The priority of the added element. */ public function add($element, $priority = null, $exact = false) { if ($priority !== null && !is_numeric($priority)) { return false; - } elseif ($exact) { - $this->shiftElementsSegment($priority); } else { $priority = $this->getNextPriority($priority); } @@ -163,16 +162,16 @@ class ElggPriorityList /** * Move an existing element to a new priority. * - * @param int $current_priority - * @param int $new_priority - * @param bool $exact - * @return bool + * @param mixed $current_priority + * @param int $new_priority + * + * @return int The new priority. */ - public function move($current_priority, $new_priority, $exact = false) { - $current_priority = (int) $current_priority; + public function move($element, $new_priority, $strict = false) { $new_priority = (int) $new_priority; - - if (!isset($this->elements[$current_priority])) { + + $current_priority = $this->getPriority($element, $strict); + if (!$current_priority) { return false; } @@ -180,17 +179,16 @@ class ElggPriorityList return true; } - $element = $this->elements[$current_priority]; + // move the actual element so strict operations still work + $element = $this->getElement($current_priority); unset($this->elements[$current_priority]); - - return $this->add($element, $new_priority, $exact); + return $this->add($element, $new_priority); } /** * Returns the elements * - * @param type $elements - * @param type $sort + * @return array */ public function getElements() { $this->sortIfUnsorted(); @@ -238,29 +236,6 @@ class ElggPriorityList } } - /** - * Shift a segment of elements starting at $index up by one until the end of the array or - * there's a gap in the indexes. This produces a space at $index to insert a new element. - * - * @param type $index The index to start - * @return array - */ - private function shiftElementsSegment($index) { - $index = (int) $index; - // @todo probably a better way. - $replace_elements = array(); - while (isset($this->elements[$index])) { - $replace_elements[$index + 1] = $this->elements[$index]; - unset($this->elements[$index]); - $index++; - } - - // insert old ones - foreach ($replace_elements as $index => $element) { - $this->elements[$index] = $element; - } - } - /** * Returns the next priority available. * @@ -277,25 +252,45 @@ class ElggPriorityList return $near; } - /** * Returns the priority of an element if it exists in the list. * - * @warning This can return 0 if the element's priority is 0. Use identical operator (===) to - * check for false if you want to know if an element exists. + * @warning This can return 0 if the element's priority is 0. * - * @param mixed $element + * @param mixed $element The element to check for. + * @param bool $strict Use strict checking? * @return mixed False if the element doesn't exists, the priority if it does. */ public function getPriority($element, $strict = false) { return array_search($element, $this->elements, $strict); } + /** + * Returns the element at $priority. + * + * @param int $priority + * @return mixed The element or false on fail. + */ + public function getElement($priority) { + return (isset($this->elements[$priority])) ? $this->elements[$priority] : false; + } + + /** + * Returns if the list contains $element. + * + * @param mixed $element The element to check. + * @param bool $strict Use strict checking? + * @return bool + */ + public function contains($element, $strict = false) { + return $this->getPriority($element, $strict) !== false; + } + + /********************** - * Interfaces methods * + * Interface methods * **********************/ - /** * Iterator */ @@ -356,29 +351,8 @@ class ElggPriorityList return ($key !== NULL && $key !== FALSE); } - // Coutable + // Countable public function count() { return count($this->elements); } - - // ArrayAccess - public function offsetExists($offset) { - return isset($this->elements[$offset]); - } - - public function offsetGet($offset) { - return isset($this->elements[$offset]) ? $this->elements[$offset] : null; - } - - public function offsetSet($offset, $value) { - // for $pl[] = 'New element' - $exact = ($offset !== null); - return $this->add($value, $offset, $exact); - } - - public function offsetUnset($offset) { - if (isset($this->elements[$offset])) { - unset($this->elements[$offset]); - } - } } \ No newline at end of file diff --git a/engine/lib/elgglib.php b/engine/lib/elgglib.php index b6b603e79..198ffe60c 100644 --- a/engine/lib/elgglib.php +++ b/engine/lib/elgglib.php @@ -167,7 +167,7 @@ function forward($location = "", $reason = 'system') { * @param string $name An identifier for the JavaScript library * @param string $url URL of the JavaScript file * @param string $location Page location: head or footer. (default: head) - * @param int $priority Priority of the CSS file (lower numbers load earlier) + * @param int $priority Priority of the JS file (lower numbers load earlier) * * @return bool * @since 1.8.0 @@ -288,28 +288,24 @@ function elgg_register_external_file($type, $name, $url, $location, $priority = $url = elgg_format_url($url); $url = elgg_normalize_url($url); - if (!isset($CONFIG->externals)) { - $CONFIG->externals = array(); - } - - if (!$CONFIG->externals[$type] instanceof ElggPriorityList) { - $CONFIG->externals[$type] = new ElggPriorityList(); - } + elgg_bootstrap_externals_data_structure($type); $name = trim(strtolower($name)); $priority = max((int)$priority, 0); + $item = elgg_extract($name, $CONFIG->externals_map[$type]); - $index = elgg_get_external_file_priority($name, $type); - - if ($index !== false) { + if ($item) { // updating a registered item - $item = $CONFIG->externals[$type][$index]; + // don't update loaded because it could already be set $item->url = $url; $item->location = $location; - // remove old saved priority - elgg_remove_external_file_priority($name, $type); - $priority = $CONFIG->externals[$type]->move($index, $priority); + // if loaded before registered, that means it hasn't been added to the list yet + if ($CONFIG->externals[$type]->contains($item)) { + $priority = $CONFIG->externals[$type]->move($item, $priority); + } else { + $priority = $CONFIG->externals[$type]->add($item, $priority); + } } else { $item = new stdClass(); $item->loaded = false; @@ -319,10 +315,9 @@ function elgg_register_external_file($type, $name, $url, $location, $priority = $priority = $CONFIG->externals[$type]->add($item, $priority); } - // save priority map so we can update if added again - elgg_save_external_file_priority($priority, $name, $type); + $CONFIG->externals_map[$type][$name] = $item; - return true; + return $priority !== false; } /** @@ -337,22 +332,14 @@ function elgg_register_external_file($type, $name, $url, $location, $priority = function elgg_unregister_external_file($type, $name) { global $CONFIG; - if (!isset($CONFIG->externals)) { - return false; - } - - if (!$CONFIG->externals[$type] instanceof ElggPriorityList) { - return false; - } + elgg_bootstrap_externals_data_structure($type); $name = trim(strtolower($name)); - - $priority = elgg_get_external_file_priority($name, $type); + $item = elgg_extract($name, $CONFIG->externals_map[$type]); - if ($priority !== false) { - elgg_remove_external_file_priority($name, $type); - unset($CONFIG->externals[$type][$priority]); - return true; + if ($item) { + unset($CONFIG->externals_map[$type][$name]); + return $CONFIG->externals[$type]->remove($item); } return false; @@ -370,21 +357,15 @@ function elgg_unregister_external_file($type, $name) { function elgg_load_external_file($type, $name) { global $CONFIG; - if (!isset($CONFIG->externals)) { - $CONFIG->externals = array(); - } - - if (!$CONFIG->externals[$type] instanceof ElggPriorityList) { - $CONFIG->externals[$type] = new ElggPriorityList(); - } + elgg_bootstrap_externals_data_structure($type); $name = trim(strtolower($name)); - $priority = elgg_get_external_file_priority($name, $type); + $item = elgg_extract($name, $CONFIG->externals_map[$type]); - if ($priority !== false) { + if ($item) { // update a registered item - $CONFIG->externals[$type][$priority]->loaded = true; + $item->loaded = true; } else { $item = new stdClass(); $item->loaded = true; @@ -392,59 +373,10 @@ function elgg_load_external_file($type, $name) { $item->location = ''; $priority = $CONFIG->externals[$type]->add($item); - elgg_save_external_file_priority($priority, $name, $type); + $CONFIG->externals_map[$type][$name] = $item; } } -/** - * Gets the priority of an external by name and type. - * - * @param type $name - * @param type $type - * @return type - */ -function elgg_get_external_file_priority($name, $type) { - global $CONFIG; - - if (!isset($CONFIG->externals_priorities[$type][$name])) { - return false; - } - - return $CONFIG->externals_priorities[$type][$name]; -} - -function elgg_save_external_file_priority($priority, $name, $type) { - global $CONFIG; - - if (!isset($CONFIG->externals_priorities)) { - $CONFIG->externals_priorities = array(); - } - - if (!isset($CONFIG->externals_priorities[$type])) { - $CONFIG->externals_priorities[$type] = array(); - } - - $CONFIG->externals_priorities[$type][$name] = $priority; - - return true; -} - -function elgg_remove_external_file_priority($name, $type) { - global $CONFIG; - - if (!isset($CONFIG->externals_priorities)) { - $CONFIG->externals_priorities = array(); - } - - if (!isset($CONFIG->externals_priorities[$type])) { - $CONFIG->externals_priorities[$type] = array(); - } - - unset($CONFIG->externals_priorities[$type][$name]); - - return true; -} - /** * Get external resource descriptors * @@ -470,6 +402,31 @@ function elgg_get_loaded_external_files($type, $location) { return array(); } +/** + * Bootstraps the externals data structure in $CONFIG. + * + * @param string $type The type of external, js or css. + */ +function elgg_bootstrap_externals_data_structure($type) { + global $CONFIG; + + if (!isset($CONFIG->externals)) { + $CONFIG->externals = array(); + } + + if (!$CONFIG->externals[$type] instanceof ElggPriorityList) { + $CONFIG->externals[$type] = new ElggPriorityList(); + } + + if (!isset($CONFIG->externals_map)) { + $CONFIG->externals_map = array(); + } + + if (!isset($CONFIG->externals_map[$type])) { + $CONFIG->externals_map[$type] = array(); + } +} + /** * Returns a list of files in $directory. * diff --git a/engine/lib/views.php b/engine/lib/views.php index 7686a8bef..fe3265347 100644 --- a/engine/lib/views.php +++ b/engine/lib/views.php @@ -1479,21 +1479,6 @@ function autoregister_views($view_base, $folder, $base_location_path, $viewtype) return FALSE; } -/** - * Add the core Elgg head elements that could be cached - * - * @return void - */ -function elgg_views_register_core_head_elements() { - $url = elgg_get_simplecache_url('js', 'elgg'); - elgg_register_js('elgg', $url, 'head', 10); - elgg_load_js('elgg'); - - $url = elgg_get_simplecache_url('css', 'elgg'); - elgg_register_css('elgg', $url, 10); - elgg_load_css('elgg'); -} - /** * Add the rss link to the extras when if needed * @@ -1548,12 +1533,17 @@ function elgg_views_boot() { elgg_register_simplecache_view('css/ie6'); elgg_register_simplecache_view('js/elgg'); - elgg_register_js('jquery', '/vendors/jquery/jquery-1.6.2.min.js', 'head', 1); - elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.16.min.js', 'head', 2); + elgg_register_js('jquery', '/vendors/jquery/jquery-1.6.2.min.js', 'head'); + elgg_register_js('jquery-ui', '/vendors/jquery/jquery-ui-1.8.16.min.js', 'head'); elgg_register_js('jquery.form', '/vendors/jquery/jquery.form.js'); + + $elgg_js_url = elgg_get_simplecache_url('js', 'elgg'); + elgg_register_js('elgg', $elgg_js_url, 'head'); + elgg_load_js('jquery'); elgg_load_js('jquery-ui'); elgg_load_js('jquery.form'); + elgg_load_js('elgg'); elgg_register_simplecache_view('js/lightbox'); $lightbox_js_url = elgg_get_simplecache_url('js', 'lightbox'); @@ -1561,7 +1551,10 @@ function elgg_views_boot() { $lightbox_css_url = 'vendors/jquery/fancybox/jquery.fancybox-1.3.4.css'; elgg_register_css('lightbox', $lightbox_css_url); - elgg_register_event_handler('ready', 'system', 'elgg_views_register_core_head_elements'); + $elgg_css_url = elgg_get_simplecache_url('css', 'elgg'); + elgg_register_css('elgg', $elgg_css_url, 1); + elgg_load_css('elgg'); + elgg_register_event_handler('pagesetup', 'system', 'elgg_views_add_rss_link'); // discover the built-in view types diff --git a/engine/tests/api/helpers.php b/engine/tests/api/helpers.php index cceb762be..ee2e64cfe 100644 --- a/engine/tests/api/helpers.php +++ b/engine/tests/api/helpers.php @@ -31,7 +31,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { global $CONFIG; unset($CONFIG->externals); - unset($CONFIG->externals_priorities); + unset($CONFIG->externals_map); } /** @@ -107,9 +107,16 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { // specify name $result = elgg_register_js('key', 'http://test1.com', 'footer'); $this->assertTrue($result); - $this->assertTrue(isset($CONFIG->externals_priorities['js']['key'])); - $index = $CONFIG->externals_priorities['js']['key']; - $this->assertIdentical('http://test1.com', $CONFIG->externals['js'][$index]->url); + $this->assertTrue(isset($CONFIG->externals_map['js']['key'])); + + $item = $CONFIG->externals_map['js']['key']; + $this->assertTrue($CONFIG->externals['js']->contains($item)); + + $priority = $CONFIG->externals['js']->getPriority($item); + $this->assertTrue($priority !== false); + + $item = $CONFIG->externals['js']->getElement($priority); + $this->assertIdentical('http://test1.com', $item->url); // send a bad url $result = @elgg_register_js('bad'); @@ -121,13 +128,20 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { */ public function testElggRegisterCSS() { global $CONFIG; - + // specify name $result = elgg_register_css('key', 'http://test1.com'); $this->assertTrue($result); - $this->assertTrue(isset($CONFIG->externals_priorities['css']['key'])); - $index = elgg_get_external_file_priority('css', 'key'); - $this->assertIdentical('http://test1.com', $CONFIG->externals['css'][$index]->url); + $this->assertTrue(isset($CONFIG->externals_map['css']['key'])); + + $item = $CONFIG->externals_map['css']['key']; + $this->assertTrue($CONFIG->externals['css']->contains($item)); + + $priority = $CONFIG->externals['css']->getPriority($item); + $this->assertTrue($priority !== false); + + $item = $CONFIG->externals['css']->getElement($priority); + $this->assertIdentical('http://test1.com', $item->url); } /** @@ -139,6 +153,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $base = trim(elgg_get_site_url(), "/"); $urls = array('id1' => "$base/urla", 'id2' => "$base/urlb", 'id3' => "$base/urlc"); + foreach ($urls as $id => $url) { elgg_register_js($id, $url); } @@ -148,26 +163,33 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $js = $CONFIG->externals['js']; $elements = $js->getElements(); - $this->assertFalse(isset($CONFIG->externals_priorities['js']['id1'])); + $this->assertFalse(isset($CONFIG->externals_map['js']['id1'])); + foreach ($elements as $element) { $this->assertFalse($element->name == 'id1'); } $result = elgg_unregister_js('id1'); $this->assertFalse($result); + $result = elgg_unregister_js('', 'does_not_exist'); $this->assertFalse($result); $result = elgg_unregister_js('id2'); $elements = $js->getElements(); - $this->assertFalse(isset($CONFIG->externals_priorities['js']['id2'])); + + $this->assertFalse(isset($CONFIG->externals_map['js']['id2'])); foreach ($elements as $element) { $this->assertFalse($element->name == 'id2'); } - $this->assertTrue(isset($CONFIG->externals_priorities['js']['id3'])); - $priority = $CONFIG->externals_priorities['js']['id3']; - $this->assertIdentical($urls['id3'], $CONFIG->externals['js'][$priority]->url); + $this->assertTrue(isset($CONFIG->externals_map['js']['id3'])); + + $priority = $CONFIG->externals['js']->getPriority($CONFIG->externals_map['js']['id3']); + $this->assertTrue($priority !== false); + + $item = $CONFIG->externals['js']->getElement($priority); + $this->assertIdentical($urls['id3'], $item->url); } /** @@ -180,6 +202,7 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { elgg_load_js('key'); $result = elgg_register_js('key', 'http://test1.com', 'footer'); $this->assertTrue($result); + $js_urls = elgg_get_loaded_js('footer'); $this->assertIdentical(array('http://test1.com'), $js_urls); } @@ -192,7 +215,12 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $base = trim(elgg_get_site_url(), "/"); - $urls = array('id1' => "$base/urla", 'id2' => "$base/urlb", 'id3' => "$base/urlc"); + $urls = array( + 'id1' => "$base/urla", + 'id2' => "$base/urlb", + 'id3' => "$base/urlc" + ); + foreach ($urls as $id => $url) { elgg_register_js($id, $url); elgg_load_js($id); @@ -315,6 +343,28 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $this->assertIdentical($elements[2], $test_elements[2]); } + public function testElggPriorityListMove() { + $pl = new ElggPriorityList(); + + $elements = array( + -5 => 'Test Element -5', + 0 => 'Test Element 0', + 5 => 'Test Element 5', + ); + + foreach ($elements as $priority => $element) { + $pl->add($element, $priority); + } + + $this->assertTrue($pl->move($elements[-5], 10)); + + // check it's at the new place + $this->assertIdentical($elements[-5], $pl->getElement(10)); + + // check it's not at the old + $this->assertFalse($pl->getElement(-5)); + } + public function testElggPriorityListConstructor() { $elements = array( 10 => 'Test Element 10', @@ -358,6 +408,25 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $this->assertIdentical(2, $pl->getPriority($elements[2])); } + public function testElggPriorityListGetElement() { + $pl = new ElggPriorityList(); + $priorities = array(); + + $elements = array( + 'Test element 0', + 'Test element 1', + 'Test element 2', + ); + + foreach ($elements as $element) { + $priorities[] = $pl->add($element); + } + + $this->assertIdentical($elements[0], $pl->getElement($priorities[0])); + $this->assertIdentical($elements[1], $pl->getElement($priorities[1])); + $this->assertIdentical($elements[2], $pl->getElement($priorities[2])); + } + public function testElggPriorityListPriorityCollision() { $pl = new ElggPriorityList(); @@ -378,31 +447,6 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $this->assertEqual(7, $pl->getPriority('Colliding element')); } - public function testElggPriorityListArrayAccess() { - $pl = new ElggPriorityList(); - - $pl[] = 'Test element 0'; - $pl[-10] = 'Test element -10'; - $pl[-1] = 'Test element -1'; - $pl[] = 'Test element 1'; - $pl[5] = 'Test element 5'; - $pl[0] = 'Test element collision with 0'; - - $elements = array( - -1 => 'Test element -1', - 0 => 'Test element collision with 0', - 1 => 'Test element 0', - 2 => 'Test element 1', - 5 => 'Test element 5', - ); - - $priority = $pl->getPriority('Test element -10'); - unset($pl[$priority]); - - $test_elements = $pl->getElements(); - $this->assertIdentical($elements, $test_elements); - } - public function testElggPriorityListIterator() { $elements = array( -5 => 'Test element -5', @@ -422,13 +466,13 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $this->assertEqual(0, count($pl)); - $pl[] = 'Test element 0'; + $pl->add('Test element 0'); $this->assertEqual(1, count($pl)); - $pl[] = 'Test element 1'; + $pl->add('Test element 1'); $this->assertEqual(2, count($pl)); - $pl[] = 'Test element 2'; + $pl->add('Test element 2'); $this->assertEqual(3, count($pl)); } @@ -461,43 +505,4 @@ class ElggCoreHelpersTest extends ElggCoreUnitTest { $this->assertIdentical($elements_sorted_string, $test_elements); } - - function testElggPriorityListShiftElementsSegment() { - $elements = array( - 0 => 'Element 0', - 1 => 'Element 1', - 2 => 'Element 2', - 4 => 'Element 4', - ); - - $pl = new ElggPriorityList($elements); - - // add a new element directly at 1. - $pl->add('New Element', 1, true); - - $elements_sorted = array( - 0 => 'Element 0', - 1 => 'New Element', - 2 => 'Element 1', - 3 => 'Element 2', - 4 => 'Element 4', - ); - - $test_elements = $pl->getElements(); - $this->assertIdentical($elements_sorted, $test_elements); - - $pl->add('New Element 10', 10, true); - - $elements_sorted = array( - 0 => 'Element 0', - 1 => 'New Element', - 2 => 'Element 1', - 3 => 'Element 2', - 4 => 'Element 4', - 10 => 'New Element 10' - ); - - $test_elements = $pl->getElements(); - $this->assertIdentical($elements_sorted, $test_elements); - } } \ No newline at end of file -- cgit v1.2.3