Merge branch 'MDL-38497-admintree-beforesibling' of git://github.com/mudrd8mz/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 19 Mar 2013 16:16:32 +0000 (17:16 +0100)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Tue, 19 Mar 2013 16:16:32 +0000 (17:16 +0100)
Conflicts:
lib/upgrade.txt

admin/settings/plugins.php
admin/tool/unsuproles/settings.php
lib/adminlib.php
lib/tests/admintree_test.php [new file with mode: 0644]
lib/upgrade.txt

index f2d6f58..61d2477 100644 (file)
@@ -196,9 +196,9 @@ if ($hassiteconfig) {
         50, PARAM_INT, 3));
 
     $ADMIN->add('portfoliosettings', $temp);
-    $ADMIN->add('portfoliosettings', new admin_externalpage('portfolionew', new lang_string('addnewportfolio', 'portfolio'), $url, 'moodle/site:config', true), '', $url);
-    $ADMIN->add('portfoliosettings', new admin_externalpage('portfoliodelete', new lang_string('deleteportfolio', 'portfolio'), $url, 'moodle/site:config', true), '', $url);
-    $ADMIN->add('portfoliosettings', new admin_externalpage('portfoliocontroller', new lang_string('manageportfolios', 'portfolio'), $url, 'moodle/site:config', true), '', $url);
+    $ADMIN->add('portfoliosettings', new admin_externalpage('portfolionew', new lang_string('addnewportfolio', 'portfolio'), $url, 'moodle/site:config', true));
+    $ADMIN->add('portfoliosettings', new admin_externalpage('portfoliodelete', new lang_string('deleteportfolio', 'portfolio'), $url, 'moodle/site:config', true));
+    $ADMIN->add('portfoliosettings', new admin_externalpage('portfoliocontroller', new lang_string('manageportfolios', 'portfolio'), $url, 'moodle/site:config', true));
 
     foreach (portfolio_instances(false, false) as $portfolio) {
         require_once($CFG->dirroot . '/portfolio/' . $portfolio->get('plugin') . '/lib.php');
@@ -234,20 +234,15 @@ if ($hassiteconfig) {
     $temp->add(new admin_setting_configcheckbox('legacyfilesinnewcourses', new lang_string('legacyfilesinnewcourses', 'admin'), new lang_string('legacyfilesinnewcourses_help', 'admin'), 0));
     $ADMIN->add('repositorysettings', $temp);
     $ADMIN->add('repositorysettings', new admin_externalpage('repositorynew',
-        new lang_string('addplugin', 'repository'), $url, 'moodle/site:config', true),
-        '', $url);
+        new lang_string('addplugin', 'repository'), $url, 'moodle/site:config', true));
     $ADMIN->add('repositorysettings', new admin_externalpage('repositorydelete',
-        new lang_string('deleterepository', 'repository'), $url, 'moodle/site:config', true),
-        '', $url);
+        new lang_string('deleterepository', 'repository'), $url, 'moodle/site:config', true));
     $ADMIN->add('repositorysettings', new admin_externalpage('repositorycontroller',
-        new lang_string('manage', 'repository'), $url, 'moodle/site:config', true),
-        '', $url);
+        new lang_string('manage', 'repository'), $url, 'moodle/site:config', true));
     $ADMIN->add('repositorysettings', new admin_externalpage('repositoryinstancenew',
-        new lang_string('createrepository', 'repository'), $url, 'moodle/site:config', true),
-        '', $url);
+        new lang_string('createrepository', 'repository'), $url, 'moodle/site:config', true));
     $ADMIN->add('repositorysettings', new admin_externalpage('repositoryinstanceedit',
-        new lang_string('editrepositoryinstance', 'repository'), $url, 'moodle/site:config', true),
-        '', $url);
+        new lang_string('editrepositoryinstance', 'repository'), $url, 'moodle/site:config', true));
     foreach ($allplugins['repository'] as $repositorytype) {
         $repositorytype->load_settings($ADMIN, 'repositorysettings', $hassiteconfig);
     }
index 5d30c44..e803291 100644 (file)
@@ -26,5 +26,5 @@
 defined('MOODLE_INTERNAL') || die;
 
 if ($hassiteconfig) {
-    $ADMIN->add('roles', new admin_externalpage('toolunsuproles', get_string('pluginname', 'tool_unsuproles'), "$CFG->wwwroot/$CFG->admin/tool/unsuproles/index.php"), array('moodle/site:config', 'moodle/role:assign'));
+    $ADMIN->add('roles', new admin_externalpage('toolunsuproles', get_string('pluginname', 'tool_unsuproles'), "$CFG->wwwroot/$CFG->admin/tool/unsuproles/index.php", array('moodle/site:config', 'moodle/role:assign')));
 }
index 1782445..fbd7df3 100644 (file)
@@ -802,11 +802,16 @@ interface parentable_part_of_admin_tree extends part_of_admin_tree {
  * $this->name. If it doesn't, add should be called on child objects that are
  * also parentable_part_of_admin_tree's.
  *
+ * $something should be appended as the last child in the $destinationname. If the
+ * $beforesibling is specified, $something should be prepended to it. If the given
+ * sibling is not found, $something should be appended to the end of $destinationname
+ * and a developer debugging message should be displayed.
+ *
  * @param string $destinationname The internal name of the new parent for $something.
  * @param part_of_admin_tree $something The object to be added.
  * @return bool True on success, false on failure.
  */
-    public function add($destinationname, $something);
+    public function add($destinationname, $something, $beforesibling = null);
 
 }
 
@@ -944,11 +949,18 @@ class admin_category implements parentable_part_of_admin_tree {
     /**
      * Adds a part_of_admin_tree to a child or grandchild (or great-grandchild, and so forth) of this object.
      *
+     * By default the new part of the tree is appended as the last child of the parent. You
+     * can specify a sibling node that the new part should be prepended to. If the given
+     * sibling is not found, the part is appended to the end (as it would be by default) and
+     * a developer debugging message is displayed.
+     *
+     * @throws coding_exception if the $beforesibling is empty string or is not string at all.
      * @param string $destinationame The internal name of the immediate parent that we want for $something.
      * @param mixed $something A part_of_admin_tree or setting instance to be added.
+     * @param string $beforesibling The name of the parent's child the $something should be prepended to.
      * @return bool True if successfully added, false if $something can not be added.
      */
-    public function add($parentname, $something) {
+    public function add($parentname, $something, $beforesibling = null) {
         $parent = $this->locate($parentname);
         if (is_null($parent)) {
             debugging('parent does not exist!');
@@ -965,7 +977,32 @@ class admin_category implements parentable_part_of_admin_tree {
                 // It is intentional to check for the debug level before performing the check.
                 debugging('Duplicate admin page name: ' . $something->name, DEBUG_DEVELOPER);
             }
-            $parent->children[] = $something;
+            if (is_null($beforesibling)) {
+                // Append $something as the parent's last child.
+                $parent->children[] = $something;
+            } else {
+                if (!is_string($beforesibling) or trim($beforesibling) === '') {
+                    throw new coding_exception('Unexpected value of the beforesibling parameter');
+                }
+                // Try to find the position of the sibling.
+                $siblingposition = null;
+                foreach ($parent->children as $childposition => $child) {
+                    if ($child->name === $beforesibling) {
+                        $siblingposition = $childposition;
+                        break;
+                    }
+                }
+                if (is_null($siblingposition)) {
+                    debugging('Sibling '.$beforesibling.' not found', DEBUG_DEVELOPER);
+                    $parent->children[] = $something;
+                } else {
+                    $parent->children = array_merge(
+                        array_slice($parent->children, 0, $siblingposition),
+                        array($something),
+                        array_slice($parent->children, $siblingposition)
+                    );
+                }
+            }
             if (is_array($this->category_cache) and ($something instanceof admin_category)) {
                 if (isset($this->category_cache[$something->name])) {
                     debugging('Duplicate admin category name: '.$something->name);
diff --git a/lib/tests/admintree_test.php b/lib/tests/admintree_test.php
new file mode 100644 (file)
index 0000000..f633bd7
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Unit tests for those parts of adminlib.php that implement the admin tree
+ * functionality.
+ *
+ * @package     core
+ * @category    test
+ * @copyright   2013 David Mudrak <david@moodle.com>
+ * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->libdir.'/adminlib.php');
+
+/**
+ * Provides the unit tests for admin tree functionality.
+ */
+class admintree_testcase extends advanced_testcase {
+
+    /**
+     * Adding nodes into the admin tree
+     */
+    public function test_add_nodes() {
+
+        $tree = new admin_root(true);
+        $tree->add('root', $one = new admin_category('one', 'One'));
+        $tree->add('root', new admin_category('three', 'Three'));
+        $tree->add('one', new admin_category('one-one', 'One-one'));
+        $tree->add('one', new admin_category('one-three', 'One-three'));
+
+        // Check the order of nodes in the root.
+        $map = array();
+        foreach ($tree->children as $child) {
+            $map[] = $child->name;
+        }
+        $this->assertEquals(array('one', 'three'), $map);
+
+        // Insert a node into the middle.
+        $tree->add('root', new admin_category('two', 'Two'), 'three');
+        $map = array();
+        foreach ($tree->children as $child) {
+            $map[] = $child->name;
+        }
+        $this->assertEquals(array('one', 'two', 'three'), $map);
+
+        // Non-existing sibling.
+        $tree->add('root', new admin_category('four', 'Four'), 'five');
+        $this->assertDebuggingCalled('Sibling five not found', DEBUG_DEVELOPER);
+
+        $tree->add('root', new admin_category('five', 'Five'));
+        $map = array();
+        foreach ($tree->children as $child) {
+            $map[] = $child->name;
+        }
+        $this->assertEquals(array('one', 'two', 'three', 'four', 'five'), $map);
+
+        // Insert a node into the middle of the subcategory
+        $tree->add('one', new admin_category('one-two', 'One-two'), 'one-three');
+        $map = array();
+        foreach ($one->children as $child) {
+            $map[] = $child->name;
+        }
+        $this->assertEquals(array('one-one', 'one-two', 'one-three'), $map);
+
+        // Check just siblings, not parents or children.
+        $tree->add('one', new admin_category('one-four', 'One-four'), 'one');
+        $this->assertDebuggingCalled('Sibling one not found', DEBUG_DEVELOPER);
+
+        $tree->add('root', new admin_category('six', 'Six'), 'one-two');
+        $this->assertDebuggingCalled('Sibling one-two not found', DEBUG_DEVELOPER);
+
+        // Me! Me! I wanna be first!
+        $tree->add('root', new admin_externalpage('zero', 'Zero', 'http://foo.bar'), 'one');
+        $map = array();
+        foreach ($tree->children as $child) {
+            $map[] = $child->name;
+        }
+        $this->assertEquals(array('zero', 'one', 'two', 'three', 'four', 'five', 'six'), $map);
+    }
+
+    /**
+     * @expectedException coding_exception
+     */
+    public function test_add_nodes_before_invalid1() {
+        $tree = new admin_root(true);
+        $tree->add('root', new admin_externalpage('foo', 'Foo', 'http://foo.bar'), array('moodle:site/config'));
+    }
+
+    /**
+     * @expectedException coding_exception
+     */
+    public function test_add_nodes_before_invalid2() {
+        $tree = new admin_root(true);
+        $tree->add('root', new admin_category('bar', 'Bar'), '');
+    }
+}
index 0a1c3df..4a9e78b 100644 (file)
@@ -1,4 +1,4 @@
-This files describes API changes in core lbraries and APIs,
+This files describes API changes in core libraries and APIs,
 information provided here is intended especially for developers.
 
 === 2.5 ===
@@ -28,6 +28,9 @@ information provided here is intended especially for developers.
   and not included in get_user function, it will not be returned by get_users_listing.
 * The add_* functions in course/dnduploadlib.php have been deprecated. Plugins should be using the
   MODNAME_dndupload_register callback instead.
+* The signature of the add() method of classes implementing the parentable_part_of_admin_tree
+  interface (such as admin_category) has been extended. The new parameter allows the caller
+  to prepend the new node before an existing sibling in the admin tree.
 
 YUI changes:
 * M.util.help_icon has been deprecated. Code should be updated to use moodle-core-popuphelp