Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * Defines profile page navigation tree.
  19   *
  20   * @package   core_user
  21   * @copyright 2015 onwards Ankit Agarwal
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  namespace core_user\output\myprofile;
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /**
  29   * Defines my profile page navigation tree.
  30   *
  31   * @since     Moodle 2.9
  32   * @package   core_user
  33   * @copyright 2015 onwards Ankit Agarwal
  34   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   */
  36  class tree implements \renderable {
  37      /**
  38       * @var category[] Array of categories in the tree.
  39       */
  40      private $categories = array();
  41  
  42      /**
  43       * @var node[] Array of nodes in the tree that were directly added to the tree.
  44       */
  45      private $nodes = array();
  46  
  47      /**
  48       * @var array List of properties accessible via __get.
  49       */
  50      private $properties = array('categories', 'nodes');
  51  
  52      /**
  53       * Add a node to the tree.
  54       *
  55       * @param node $node node object.
  56       *
  57       * @throws \coding_exception
  58       */
  59      public function add_node(node $node) {
  60          $name = $node->name;
  61          if (isset($this->nodes[$name])) {
  62              throw new \coding_exception("Node name $name already used");
  63          }
  64          $this->nodes[$node->name] = $node;
  65      }
  66  
  67      /**
  68       * Add a category to the tree.
  69       *
  70       * @param category $cat category object.
  71       *
  72       * @throws \coding_exception
  73       */
  74      public function add_category(category $cat) {
  75          $name = $cat->name;
  76          if (isset($this->categories[$name])) {
  77              throw new \coding_exception("Category name $name already used");
  78          }
  79          $this->categories[$cat->name] = $cat;
  80      }
  81  
  82      /**
  83       * Sort categories and nodes. Builds the tree structure that would be displayed to the user.
  84       *
  85       * @throws \coding_exception
  86       */
  87      public function sort_categories() {
  88          $this->attach_nodes_to_categories();
  89          $tempcategories = array();
  90          foreach ($this->categories as $category) {
  91              $after = $category->after;
  92              if ($after == null) {
  93                  // Can go anywhere in the tree.
  94                  $category->sort_nodes();
  95                  $tempcategories = array_merge($tempcategories, array($category->name => $category),
  96                          $this->find_categories_after($category));
  97              }
  98          }
  99          if (count($tempcategories) !== count($this->categories)) {
 100              // Orphan categories found.
 101              throw new \coding_exception('Some of the categories specified contains invalid \'after\' property');
 102          }
 103          $this->categories = $tempcategories;
 104      }
 105  
 106      /**
 107       * Attach various nodes to their respective categories.
 108       *
 109       * @throws \coding_exception
 110       */
 111      protected function attach_nodes_to_categories() {
 112          foreach ($this->nodes as $node) {
 113              $parentcat = $node->parentcat;
 114              if (!isset($this->categories[$parentcat])) {
 115                  throw new \coding_exception("Category $parentcat doesn't exist");
 116              } else {
 117                  $this->categories[$parentcat]->add_node($node);
 118              }
 119          }
 120      }
 121  
 122      /**
 123       * Find all category nodes that should be displayed after a given a category node.
 124       *
 125       * @param category $category category object
 126       *
 127       * @return category[] array of category objects
 128       * @throws \coding_exception
 129       */
 130      protected function find_categories_after($category) {
 131          $return = array();
 132          $categoryarray = $this->categories;
 133          foreach ($categoryarray as $categoryelement) {
 134              if ($categoryelement->after == $category->name) {
 135                  // Find all categories that comes after this category as well.
 136                  $categoryelement->sort_nodes();
 137                  $return = array_merge($return, array($categoryelement->name => $categoryelement),
 138                          $this->find_categories_after($categoryelement));
 139              }
 140          }
 141          return $return;
 142      }
 143  
 144      /**
 145       * Magic get method.
 146       *
 147       * @param string $prop property to get.
 148       *
 149       * @return mixed
 150       * @throws \coding_exception
 151       */
 152      public function __get($prop) {
 153          if (in_array($prop, $this->properties)) {
 154              return $this->$prop;
 155          }
 156          throw new \coding_exception('Property "' . $prop . '" doesn\'t exist');
 157      }
 158  }