Commit | Line | Data |
---|---|---|
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 | ||
25 | namespace core_user\output\myprofile; | |
26 | defined('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 | */ | |
36 | class 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 | } |