MDL-49819 navigation: Admin section in user profile update.
[moodle.git] / user / classes / output / myprofile / category.php
CommitLineData
0807601d
AA
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 a category in my profile page navigation.
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
25namespace core_user\output\myprofile;
26defined('MOODLE_INTERNAL') || die();
27
28/**
29 * Defines a category in my profile page navigation.
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 */
36class category implements \renderable {
37
38 /**
39 * @var string Name of the category after which this category should appear.
40 */
41 private $after;
42
43 /**
44 * @var string Name of the category.
45 */
46 private $name;
47
48 /**
49 * @var string Title of the category.
50 */
51 private $title;
52
53 /**
54 * @var node[] Array of nodes associated with this category.
55 */
56 private $nodes = array();
57
b19cc4ef
AA
58 /**
59 * @var string HTML class attribute for this category. Classes should be separated by a space, e.g. 'class1 class2'
60 */
61 private $classes;
62
0807601d
AA
63 /**
64 * @var array list of properties publicly accessible via __get.
65 */
b19cc4ef 66 private $properties = array('after', 'name', 'title', 'nodes', 'classes');
0807601d
AA
67
68 /**
69 * Constructor for category class.
70 *
71 * @param string $name Category name.
72 * @param string $title category title.
73 * @param null|string $after Name of category after which this category should appear.
b19cc4ef 74 * @param null|string $classes a list of css classes.
0807601d 75 */
b19cc4ef 76 public function __construct($name, $title, $after = null, $classes = null) {
0807601d
AA
77 $this->after = $after;
78 $this->name = $name;
79 $this->title = $title;
b19cc4ef 80 $this->classes = $classes;
0807601d
AA
81 }
82
83 /**
84 * Add a node to this category.
85 *
86 * @param node $node node object.
87 * @see \core_user\output\myprofile\tree::add_node()
88 *
89 * @throws \coding_exception
90 */
b19cc4ef 91 public function add_node(node $node) {
0807601d
AA
92 $name = $node->name;
93 if (isset($this->nodes[$name])) {
94 throw new \coding_exception("Node with name $name already exists");
95 }
96 if ($node->parentcat !== $this->name) {
97 throw new \coding_exception("Node parent must match with the category it is added to");
98 }
99 $this->nodes[$node->name] = $node;
100 }
101
102 /**
103 * Sort nodes of the category in the order in which they should be displayed.
104 *
105 * @see \core_user\output\myprofile\tree::sort_categories()
106 * @throws \coding_exception
107 */
108 public function sort_nodes() {
109 $tempnodes = array();
b19cc4ef
AA
110 $this->validate_after_order();
111
112 // First content noes.
0807601d
AA
113 foreach ($this->nodes as $node) {
114 $after = $node->after;
b19cc4ef 115 $content = $node->content;
3a13707a 116 if (($after == null && !empty($content)) || $node->name === 'editprofile') {
b19cc4ef 117 // Can go anywhere in the cat. Also show content nodes first.
0807601d
AA
118 $tempnodes = array_merge($tempnodes, array($node->name => $node), $this->find_nodes_after($node));
119 }
120 }
b19cc4ef
AA
121
122 // Now nodes with no content.
123 foreach ($this->nodes as $node) {
124 $after = $node->after;
125 $content = $node->content;
126 if ($after == null && empty($content)) {
127 // Can go anywhere in the cat. Also show content nodes first.
128 $tempnodes = array_merge($tempnodes, array($node->name => $node), $this->find_nodes_after($node));
129 }
130 }
131
0807601d
AA
132 if (count($tempnodes) !== count($this->nodes)) {
133 // Orphan nodes found.
134 throw new \coding_exception('Some of the nodes specified contains invalid \'after\' property');
135 }
136 $this->nodes = $tempnodes;
137 }
138
b19cc4ef
AA
139 /**
140 * Verifies that node with content can come after node with content only . Also verifies the same thing for nodes without
141 * content.
142 * @throws \coding_exception
143 */
144 protected function validate_after_order() {
145 $nodearray = $this->nodes;
146 foreach ($this->nodes as $node) {
147 $after = $node->after;
148 if (!empty($after)) {
149 if (empty($nodearray[$after])) {
150 throw new \coding_exception('node {$node->name} specified contains invalid \'after\' property');
151 } else {
152 // Valid node found.
153 $afternode = $nodearray[$after];
154 $beforecontent = $node->content;
155 $aftercontent = $afternode->content;
156
157 if ((empty($beforecontent) && !empty($aftercontent)) || (!empty($beforecontent) && empty($aftercontent))) {
158 // Only node with content are allowed after content nodes. Same goes for no content nodes.
159 throw new \coding_exception('node {$node->name} specified contains invalid \'after\' property');
160 }
161 }
162 }
163 }
164 }
165
0807601d
AA
166 /**
167 * Given a node object find all node objects that should appear after it.
168 *
169 * @param node $node node object
170 *
171 * @return array
172 */
173 protected function find_nodes_after($node) {
174 $return = array();
175 $nodearray = $this->nodes;
176 foreach ($nodearray as $nodeelement) {
177 if ($nodeelement->after === $node->name) {
178 // Find all nodes that comes after this node as well.
b19cc4ef 179 $return = array_merge($return, array($nodeelement->name => $nodeelement), $this->find_nodes_after($nodeelement));
0807601d
AA
180 }
181 }
182 return $return;
183 }
184
185 /**
186 * Magic get method.
187 *
188 * @param string $prop property to get.
189 *
190 * @return mixed
191 * @throws \coding_exception
192 */
193 public function __get($prop) {
194 if (in_array($prop, $this->properties)) {
195 return $this->$prop;
196 }
197 throw new \coding_exception('Property "' . $prop . '" doesn\'t exist');
198 }
199}