MDL-48932 myprofile: Add apis to make my profile pluggable
authorAnkit Agarwal <ankit@moodle.com>
Wed, 25 Feb 2015 09:05:34 +0000 (14:35 +0530)
committerAdrian Greeve <adrian@moodle.com>
Fri, 10 Apr 2015 09:17:06 +0000 (17:17 +0800)
user/classes/output/myprofile/category.php [new file with mode: 0644]
user/classes/output/myprofile/manager.php [new file with mode: 0644]
user/classes/output/myprofile/node.php [new file with mode: 0644]
user/classes/output/myprofile/tree.php [new file with mode: 0644]

diff --git a/user/classes/output/myprofile/category.php b/user/classes/output/myprofile/category.php
new file mode 100644 (file)
index 0000000..5c28302
--- /dev/null
@@ -0,0 +1,150 @@
+<?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/>.
+
+/**
+ * Defines a category in my profile page navigation.
+ *
+ * @package   core_user
+ * @copyright 2015 onwards Ankit Agarwal
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_user\output\myprofile;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Defines a category in my profile page navigation.
+ *
+ * @since     Moodle 2.9
+ * @package   core_user
+ * @copyright 2015 onwards Ankit Agarwal
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class category implements \renderable {
+
+    /**
+     * @var string Name of the category after which this category should appear.
+     */
+    private $after;
+
+    /**
+     * @var string Name of the category.
+     */
+    private $name;
+
+    /**
+     * @var string Title of the category.
+     */
+    private $title;
+
+    /**
+     * @var node[] Array of nodes associated with this category.
+     */
+    private $nodes = array();
+
+    /**
+     * @var array list of properties publicly accessible via __get.
+     */
+    private $properties = array('after', 'name', 'title', 'nodes');
+
+    /**
+     * Constructor for category class.
+     *
+     * @param string $name Category name.
+     * @param string $title category title.
+     * @param null|string $after Name of category after which this category should appear.
+     */
+    public function __construct($name, $title, $after = null) {
+        $this->after = $after;
+        $this->name = $name;
+        $this->title = $title;
+    }
+
+    /**
+     * Add a node to this category.
+     *
+     * @param node $node node object.
+     * @see \core_user\output\myprofile\tree::add_node()
+     *
+     * @throws \coding_exception
+     */
+    public function add_node(\core_user\output\myprofile\node $node) {
+        $name = $node->name;
+        if (isset($this->nodes[$name])) {
+            throw new \coding_exception("Node with name $name already exists");
+        }
+        if ($node->parentcat !== $this->name) {
+            throw new \coding_exception("Node parent must match with the category it is added to");
+        }
+        $this->nodes[$node->name] = $node;
+    }
+
+    /**
+     * Sort nodes of the category in the order in which they should be displayed.
+     *
+     * @see \core_user\output\myprofile\tree::sort_categories()
+     * @throws \coding_exception
+     */
+    public function sort_nodes() {
+        $tempnodes = array();
+        foreach ($this->nodes as $node) {
+            $after = $node->after;
+            if ($after == null) {
+                // Can go anywhere in the cat.
+                $tempnodes = array_merge($tempnodes, array($node->name => $node), $this->find_nodes_after($node));
+            }
+        }
+        if (count($tempnodes) !== count($this->nodes)) {
+            // Orphan nodes found.
+            throw new \coding_exception('Some of the nodes specified contains invalid \'after\' property');
+        }
+        $this->nodes = $tempnodes;
+    }
+
+    /**
+     * Given a node object find all node objects that should appear after it.
+     *
+     * @param node $node node object
+     *
+     * @return array
+     */
+    protected function find_nodes_after($node) {
+        $return = array();
+        $nodearray = $this->nodes;
+        foreach ($nodearray as $nodeelement) {
+            if ($nodeelement->after === $node->name) {
+                // Find all nodes that comes after this node as well.
+                $return = array_merge($return, array($nodeelement), $this->find_nodes_after($nodeelement));
+            }
+        }
+        return $return;
+    }
+
+    /**
+     * Magic get method.
+     *
+     * @param string $prop property to get.
+     *
+     * @return mixed
+     * @throws \coding_exception
+     */
+    public function __get($prop) {
+        if (in_array($prop, $this->properties)) {
+            return $this->$prop;
+        }
+        throw new \coding_exception('Property "' . $prop . '" doesn\'t exist');
+    }
+}
diff --git a/user/classes/output/myprofile/manager.php b/user/classes/output/myprofile/manager.php
new file mode 100644 (file)
index 0000000..17ae6ce
--- /dev/null
@@ -0,0 +1,87 @@
+<?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/>.
+
+/**
+ * Defines Manager class for my profile navigation tree.
+ *
+ * @package   core_user
+ * @copyright 2015 onwards Ankit Agarwal
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_user\output\myprofile;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Defines MAnager class for myprofile navigation tree.
+ *
+ * @since     Moodle 2.9
+ * @package   core_user
+ * @copyright 2015 onwards Ankit Agarwal
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class manager {
+    /**
+     * Parse all callbacks and builds the tree.
+     *
+     * @param integer   $user ID of the user for which the profile is displayed.
+     * @param bool      $iscurrentuser true if the profile being viewed is of current user, else false.
+     * @param \stdClass $course Course object
+     *
+     * @return tree Fully build tree to be rendered on my profile page.
+     */
+    public static function build_tree($user, $iscurrentuser, $course = null) {
+        global $CFG;
+        $tree = new tree();
+
+        // Add core nodes.
+        $file = $CFG->libdir . "/myprofilelib.php";
+        if (is_readable($file)) {
+            require_once($file);
+            $function = "core_myprofile_navigation";
+            if (function_exists($function)) {
+                $function($tree, $user, $iscurrentuser, $course);
+            }
+        }
+
+        // Core components.
+        $components = \core_component::get_core_subsystems();
+        foreach ($components as $component => $directory) {
+            if (empty($directory)) {
+                continue;
+            }
+            $file = $directory . "/lib.php";
+            if (is_readable($file)) {
+                require_once($file);
+                $function = "core_" . $component . "_myprofile_navigation";
+                if (function_exists($function)) {
+                    $function($tree, $user, $iscurrentuser, $course);
+                }
+            }
+        }
+
+        // Plugins.
+        $types = \core_component::get_plugin_types();
+        foreach ($types as $type => $dir) {
+            $pluginlist = get_plugin_list_with_function($type, "myprofile_navigation", "lib.php");
+            foreach ($pluginlist as $function) {
+                $function($tree, $user, $iscurrentuser, $course);
+            }
+        }
+        $tree->sort_categories();
+        return $tree;
+    }
+}
diff --git a/user/classes/output/myprofile/node.php b/user/classes/output/myprofile/node.php
new file mode 100644 (file)
index 0000000..254d743
--- /dev/null
@@ -0,0 +1,112 @@
+<?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/>.
+
+/**
+ * Defines a node in my profile page navigation.
+ *
+ * @package   core_user
+ * @copyright 2015 onwards Ankit Agarwal
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_user\output\myprofile;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Defines a node in my profile page navigation.
+ *
+ * @since     Moodle 2.9
+ * @package   core_user
+ * @copyright 2015 onwards Ankit Agarwal
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class node implements \renderable {
+    /**
+     * @var string Name of parent category.
+     */
+    private $parentcat;
+
+    /**
+     * @var string Name of this node.
+     */
+    private $name;
+
+    /**
+     * @var string Name of the node after which this node should appear.
+     */
+    private $after;
+
+    /**
+     * @var string Title of this node.
+     */
+    private $title;
+
+    /**
+     * @var string|\moodle_url Url that this node should link to.
+     */
+    private $url;
+
+    /**
+     * @var string Content to display under this node.
+     */
+    private $content;
+
+    /**
+     * @var string|\pix_icon Icon for this node.
+     */
+    private $icon;
+
+    /**
+     * @var array list of properties accessible via __get.
+     */
+    private $properties = array('parentcat', 'after', 'name', 'title', 'url', 'content', 'icon');
+
+    /**
+     * Constructor for the node.
+     *
+     * @param string $parentcat Name of parent category.
+     * @param string $name Name of this node.
+     * @param string $title Title of this node.
+     * @param null|string $after Name of the node after which this node should appear.
+     * @param null|string|\moodle_url $url Url that this node should link to.
+     * @param null|string $content Content to display under this node.
+     * @param null|string|\pix_icon $icon Icon for this node.
+     */
+    public function __construct($parentcat, $name, $title, $after = null, $url = null, $content = null, $icon = null) {
+        $this->parentcat = $parentcat;
+        $this->after = $after;
+        $this->name = $name;
+        $this->title = $title;
+        $this->url = new \moodle_url($url);
+        $this->content = $content;
+        $this->icon = $icon;
+    }
+
+    /**
+     * Magic get method.
+     *
+     * @param string $prop property to get.
+     *
+     * @return mixed
+     * @throws \coding_exception
+     */
+    public function __get($prop) {
+        if (in_array($prop, $this->properties)) {
+            return $this->$prop;
+        }
+        throw new \coding_exception('Property "' . $prop . '" doesn\'t exist');
+    }
+}
diff --git a/user/classes/output/myprofile/tree.php b/user/classes/output/myprofile/tree.php
new file mode 100644 (file)
index 0000000..cb3d2ba
--- /dev/null
@@ -0,0 +1,158 @@
+<?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/>.
+
+/**
+ * Defines profile page navigation tree.
+ *
+ * @package   core_user
+ * @copyright 2015 onwards Ankit Agarwal
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_user\output\myprofile;
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Defines my profile page navigation tree.
+ *
+ * @since     Moodle 2.9
+ * @package   core_user
+ * @copyright 2015 onwards Ankit Agarwal
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class tree implements \renderable {
+    /**
+     * @var category[] Array of categories in the tree.
+     */
+    private $categories = array();
+
+    /**
+     * @var node[] Array of nodes in the tree that were directly added to the tree.
+     */
+    private $nodes = array();
+
+    /**
+     * @var array List of properties accessible via __get.
+     */
+    private $properties = array('categories', 'nodes');
+
+    /**
+     * Add a node to the tree.
+     *
+     * @param node $node node object.
+     *
+     * @throws \coding_exception
+     */
+    public function add_node(node $node) {
+        $name = $node->name;
+        if (isset($this->nodes[$name])) {
+            throw new \coding_exception("Node name $name already used");
+        }
+        $this->nodes[$node->name] = $node;
+    }
+
+    /**
+     * Add a category to the tree.
+     *
+     * @param category $cat category object.
+     *
+     * @throws \coding_exception
+     */
+    public function add_category(category $cat) {
+        $name = $cat->name;
+        if (isset($this->categories[$name])) {
+            throw new \coding_exception("Category name $name already used");
+        }
+        $this->categories[$cat->name] = $cat;
+    }
+
+    /**
+     * Sort categories and nodes. Builds the tree structure that would be displayed to the user.
+     *
+     * @throws \coding_exception
+     */
+    public function sort_categories() {
+        $this->attach_nodes_to_categories();
+        $tempcategories = array();
+        foreach ($this->categories as $category) {
+            $after = $category->after;
+            if ($after == null) {
+                // Can go anywhere in the tree.
+                $category->sort_nodes();
+                $tempcategories = array_merge($tempcategories, array($category->name => $category),
+                        $this->find_categories_after($category));
+            }
+        }
+        if (count($tempcategories) !== count($this->categories)) {
+            // Orphan categories found.
+            throw new \coding_exception('Some of the categories specified contains invalid \'after\' property');
+        }
+        $this->categories = $tempcategories;
+    }
+
+    /**
+     * Attach various nodes to their respective categories.
+     *
+     * @throws \coding_exception
+     */
+    protected function attach_nodes_to_categories() {
+        foreach ($this->nodes as $node) {
+            $parentcat = $node->parentcat;
+            if (!isset($this->categories[$parentcat])) {
+                throw new \coding_exception("Category $parentcat doesn't exist");
+            } else {
+                $this->categories[$parentcat]->add_node($node);
+            }
+        }
+    }
+
+    /**
+     * Find all category nodes that should be displayed after a given a category node.
+     * 
+     * @param category $category category object
+     *
+     * @return category[] array of category objects
+     * @throws \coding_exception
+     */
+    protected function find_categories_after($category) {
+        $return = array();
+        $categoryarray = $this->categories;
+        foreach ($categoryarray as $categoryelement) {
+            if ($categoryelement->after == $category->name) {
+                // Find all categories that comes after this category as well.
+                $categoryelement->sort_nodes();
+                $return = array_merge($return, array($categoryelement->name => $categoryelement),
+                        $this->find_categories_after($categoryelement));
+            }
+        }
+        return $return;
+    }
+
+    /**
+     * Magic get method.
+     *
+     * @param string $prop property to get.
+     *
+     * @return mixed
+     * @throws \coding_exception
+     */
+    public function __get($prop) {
+        if (in_array($prop, $this->properties)) {
+            return $this->$prop;
+        }
+        throw new \coding_exception('Property "' . $prop . '" doesn\'t exist');
+    }
+}