. /** * 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 string HTML class attribute for this category. Classes should be separated by a space, e.g. 'class1 class2' */ private $classes; /** * @var array list of properties publicly accessible via __get. */ private $properties = array('after', 'name', 'title', 'nodes', 'classes'); /** * 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. * @param null|string $classes a list of css classes. */ public function __construct($name, $title, $after = null, $classes = null) { $this->after = $after; $this->name = $name; $this->title = $title; $this->classes = $classes; } /** * 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(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(); $this->validate_after_order(); // First content noes. foreach ($this->nodes as $node) { $after = $node->after; $content = $node->content; if (($after == null && !empty($content)) || $node->name === 'editprofile') { // Can go anywhere in the cat. Also show content nodes first. $tempnodes = array_merge($tempnodes, array($node->name => $node), $this->find_nodes_after($node)); } } // Now nodes with no content. foreach ($this->nodes as $node) { $after = $node->after; $content = $node->content; if ($after == null && empty($content)) { // Can go anywhere in the cat. Also show content nodes first. $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; } /** * Verifies that node with content can come after node with content only . Also verifies the same thing for nodes without * content. * @throws \coding_exception */ protected function validate_after_order() { $nodearray = $this->nodes; foreach ($this->nodes as $node) { $after = $node->after; if (!empty($after)) { if (empty($nodearray[$after])) { throw new \coding_exception('node {$node->name} specified contains invalid \'after\' property'); } else { // Valid node found. $afternode = $nodearray[$after]; $beforecontent = $node->content; $aftercontent = $afternode->content; if ((empty($beforecontent) && !empty($aftercontent)) || (!empty($beforecontent) && empty($aftercontent))) { // Only node with content are allowed after content nodes. Same goes for no content nodes. throw new \coding_exception('node {$node->name} specified contains invalid \'after\' property'); } } } } } /** * 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->name => $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'); } }