on-demand release 4.0dev+
[moodle.git] / blocks / myoverview / classes / output / main.php
CommitLineData
9ac2e865
RW
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 * Class containing data for my overview block.
19 *
20 * @package block_myoverview
21 * @copyright 2017 Ryan Wyllie <ryan@moodle.com>
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24namespace block_myoverview\output;
25defined('MOODLE_INTERNAL') || die();
26
27use renderable;
28use renderer_base;
29use templatable;
5f59a4c0 30use stdClass;
3f0c421b 31
3cfff885 32require_once($CFG->dirroot . '/blocks/myoverview/lib.php');
c5515a34 33
9ac2e865
RW
34/**
35 * Class containing data for my overview block.
36 *
e4b4b9e7 37 * @copyright 2018 Bas Brands <bas@moodle.com>
9ac2e865
RW
38 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
39 */
40class main implements renderable, templatable {
3cfff885
BB
41
42 /**
5f59a4c0 43 * Store the grouping preference.
3cfff885
BB
44 *
45 * @var string String matching the grouping constants defined in myoverview/lib.php
46 */
47 private $grouping;
48
49 /**
5f59a4c0 50 * Store the sort preference.
3cfff885
BB
51 *
52 * @var string String matching the sort constants defined in myoverview/lib.php
53 */
54 private $sort;
55
56 /**
5f59a4c0 57 * Store the view preference.
3cfff885
BB
58 *
59 * @var string String matching the view/display constants defined in myoverview/lib.php
60 */
61 private $view;
62
11988d74 63 /**
5f59a4c0 64 * Store the paging preference.
11988d74
P
65 *
66 * @var string String matching the paging constants defined in myoverview/lib.php
67 */
68 private $paging;
69
5ae4db88 70 /**
5f59a4c0 71 * Store the display categories config setting.
5ae4db88
TD
72 *
73 * @var boolean
74 */
75 private $displaycategories;
76
5f59a4c0
TD
77 /**
78 * Store the configuration values for the myoverview block.
79 *
80 * @var array Array of available layouts matching view/display constants defined in myoverview/lib.php
81 */
82 private $layouts;
83
2276614c
AB
84 /**
85 * Store a course grouping option setting
86 *
87 * @var boolean
88 */
89 private $displaygroupingallincludinghidden;
90
91 /**
92 * Store a course grouping option setting.
93 *
94 * @var boolean
95 */
96 private $displaygroupingall;
97
98 /**
99 * Store a course grouping option setting.
100 *
101 * @var boolean
102 */
103 private $displaygroupinginprogress;
104
105 /**
106 * Store a course grouping option setting.
107 *
108 * @var boolean
109 */
110 private $displaygroupingfuture;
111
112 /**
113 * Store a course grouping option setting.
114 *
115 * @var boolean
116 */
117 private $displaygroupingpast;
118
119 /**
120 * Store a course grouping option setting.
121 *
122 * @var boolean
123 */
2d2189ae 124 private $displaygroupingfavourites;
2276614c
AB
125
126 /**
127 * Store a course grouping option setting.
128 *
129 * @var boolean
130 */
131 private $displaygroupinghidden;
132
8d166d77
DS
133 /**
134 * Store a course grouping option setting.
135 *
136 * @var bool
137 */
138 private $displaygroupingcustomfield;
139
140 /**
141 * Store the custom field used by customfield grouping.
142 *
143 * @var string
144 */
145 private $customfiltergrouping;
146
147 /**
148 * Store the selected custom field value to group by.
149 *
150 * @var string
151 */
152 private $customfieldvalue;
153
3cfff885
BB
154 /**
155 * main constructor.
156 * Initialize the user preferences
157 *
158 * @param string $grouping Grouping user preference
159 * @param string $sort Sort user preference
160 * @param string $view Display user preference
8d166d77
DS
161 * @param int $paging
162 * @param string $customfieldvalue
5f59a4c0
TD
163 *
164 * @throws \dml_exception
3cfff885 165 */
8d166d77 166 public function __construct($grouping, $sort, $view, $paging, $customfieldvalue = null) {
ad2ef9dd 167 global $CFG;
2276614c
AB
168 // Get plugin config.
169 $config = get_config('block_myoverview');
170
171 // Build the course grouping option name to check if the given grouping is enabled afterwards.
172 $groupingconfigname = 'displaygrouping'.$grouping;
173 // Check the given grouping and remember it if it is enabled.
174 if ($grouping && $config->$groupingconfigname == true) {
175 $this->grouping = $grouping;
176
177 // Otherwise fall back to another grouping in a reasonable order.
178 // This is done to prevent one-time UI glitches in the case when a user has chosen a grouping option previously which
179 // was then disabled by the admin in the meantime.
2276614c 180 } else {
8d166d77 181 $this->grouping = $this->get_fallback_grouping($config);
2276614c
AB
182 }
183 unset ($groupingconfigname);
184
8d166d77
DS
185 // Remember which custom field value we were using, if grouping by custom field.
186 $this->customfieldvalue = $customfieldvalue;
187
2276614c 188 // Check and remember the given sorting.
ad2ef9dd 189 if ($sort) {
190 $this->sort = $sort;
191 } else if ($CFG->courselistshortnames) {
192 $this->sort = BLOCK_MYOVERVIEW_SORTING_SHORTNAME;
193 } else {
194 $this->sort = BLOCK_MYOVERVIEW_SORTING_TITLE;
195 }
196 // In case sorting remembered is shortname and display extended course names not checked,
197 // we should revert sorting to title.
198 if (!$CFG->courselistshortnames && $sort == BLOCK_MYOVERVIEW_SORTING_SHORTNAME) {
199 $this->sort = BLOCK_MYOVERVIEW_SORTING_TITLE;
200 }
2276614c
AB
201
202 // Check and remember the given view.
203 $this->view = $view ? $view : BLOCK_MYOVERVIEW_VIEW_CARD;
204
c00fc970
TD
205 // Check and remember the given page size, `null` indicates no page size set
206 // while a `0` indicates a paging size of `All`.
207 if (!is_null($paging) && $paging == BLOCK_MYOVERVIEW_PAGING_ALL) {
c0add7c7
TD
208 $this->paging = BLOCK_MYOVERVIEW_PAGING_ALL;
209 } else {
210 $this->paging = $paging ? $paging : BLOCK_MYOVERVIEW_PAGING_12;
211 }
5f59a4c0 212
2276614c 213 // Check and remember if the course categories should be shown or not.
5ae4db88
TD
214 if (!$config->displaycategories) {
215 $this->displaycategories = BLOCK_MYOVERVIEW_DISPLAY_CATEGORIES_OFF;
216 } else {
217 $this->displaycategories = BLOCK_MYOVERVIEW_DISPLAY_CATEGORIES_ON;
218 }
5f59a4c0 219
2276614c 220 // Get and remember the available layouts.
5f59a4c0
TD
221 $this->set_available_layouts();
222 $this->view = $view ? $view : reset($this->layouts);
2276614c
AB
223
224 // Check and remember if the particular grouping options should be shown or not.
225 $this->displaygroupingallincludinghidden = $config->displaygroupingallincludinghidden;
226 $this->displaygroupingall = $config->displaygroupingall;
227 $this->displaygroupinginprogress = $config->displaygroupinginprogress;
228 $this->displaygroupingfuture = $config->displaygroupingfuture;
229 $this->displaygroupingpast = $config->displaygroupingpast;
2d2189ae 230 $this->displaygroupingfavourites = $config->displaygroupingfavourites;
2276614c 231 $this->displaygroupinghidden = $config->displaygroupinghidden;
8d166d77
DS
232 $this->displaygroupingcustomfield = ($config->displaygroupingcustomfield && $config->customfiltergrouping);
233 $this->customfiltergrouping = $config->customfiltergrouping;
2276614c
AB
234
235 // Check and remember if the grouping selector should be shown at all or not.
236 // It will be shown if more than 1 grouping option is enabled.
237 $displaygroupingselectors = array($this->displaygroupingallincludinghidden,
238 $this->displaygroupingall,
239 $this->displaygroupinginprogress,
240 $this->displaygroupingfuture,
241 $this->displaygroupingpast,
2d2189ae 242 $this->displaygroupingfavourites,
2276614c
AB
243 $this->displaygroupinghidden);
244 $displaygroupingselectorscount = count(array_filter($displaygroupingselectors));
8d166d77 245 if ($displaygroupingselectorscount > 1 || $this->displaygroupingcustomfield) {
2276614c
AB
246 $this->displaygroupingselector = true;
247 } else {
248 $this->displaygroupingselector = false;
249 }
250 unset ($displaygroupingselectors, $displaygroupingselectorscount);
3cfff885 251 }
8d166d77
DS
252 /**
253 * Determine the most sensible fallback grouping to use (in cases where the stored selection
254 * is no longer available).
255 * @param object $config
256 * @return string
257 */
258 private function get_fallback_grouping($config) {
259 if ($config->displaygroupingall == true) {
260 return BLOCK_MYOVERVIEW_GROUPING_ALL;
261 }
262 if ($config->displaygroupingallincludinghidden == true) {
263 return BLOCK_MYOVERVIEW_GROUPING_ALLINCLUDINGHIDDEN;
264 }
265 if ($config->displaygroupinginprogress == true) {
266 return BLOCK_MYOVERVIEW_GROUPING_INPROGRESS;
267 }
268 if ($config->displaygroupingfuture == true) {
269 return BLOCK_MYOVERVIEW_GROUPING_FUTURE;
270 }
271 if ($config->displaygroupingpast == true) {
272 return BLOCK_MYOVERVIEW_GROUPING_PAST;
273 }
2d2189ae 274 if ($config->displaygroupingfavourites == true) {
8d166d77
DS
275 return BLOCK_MYOVERVIEW_GROUPING_FAVOURITES;
276 }
277 if ($config->displaygroupinghidden == true) {
278 return BLOCK_MYOVERVIEW_GROUPING_HIDDEN;
279 }
280 if ($config->displaygroupingcustomfield == true) {
281 return BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD;
282 }
283 // In this case, no grouping option is enabled and the grouping is not needed at all.
284 // But it's better not to leave $this->grouping unset for any unexpected case.
285 return BLOCK_MYOVERVIEW_GROUPING_ALLINCLUDINGHIDDEN;
286 }
5f59a4c0 287
3cfff885 288 /**
5f59a4c0
TD
289 * Set the available layouts based on the config table settings,
290 * if none are available, defaults to the cards view.
291 *
292 * @throws \dml_exception
293 *
294 */
295 public function set_available_layouts() {
296
297 if ($config = get_config('block_myoverview', 'layouts')) {
298 $this->layouts = explode(',', $config);
299 } else {
300 $this->layouts = array(BLOCK_MYOVERVIEW_VIEW_CARD);
301 }
302 }
303
304 /**
305 * Get the user preferences as an array to figure out what has been selected.
3cfff885
BB
306 *
307 * @return array $preferences Array with the pref as key and value set to true
308 */
309 public function get_preferences_as_booleans() {
310 $preferences = [];
3cfff885
BB
311 $preferences[$this->sort] = true;
312 $preferences[$this->grouping] = true;
5f59a4c0
TD
313 // Only use the user view/display preference if it is in available layouts.
314 if (in_array($this->view, $this->layouts)) {
315 $preferences[$this->view] = true;
316 } else {
317 $preferences[reset($this->layouts)] = true;
318 }
3cfff885
BB
319
320 return $preferences;
321 }
322
5f59a4c0
TD
323 /**
324 * Format a layout into an object for export as a Context variable to template.
325 *
326 * @param string $layoutname
327 *
328 * @return \stdClass $layout an object representation of a layout
329 * @throws \coding_exception
330 */
331 public function format_layout_for_export($layoutname) {
332 $layout = new stdClass();
333
334 $layout->id = $layoutname;
335 $layout->name = get_string($layoutname, 'block_myoverview');
336 $layout->active = $this->view == $layoutname ? true : false;
337 $layout->arialabel = get_string('aria:' . $layoutname, 'block_myoverview');
338
339 return $layout;
340 }
341
342 /**
343 * Get the available layouts formatted for export.
344 *
345 * @return array an array of objects representing available layouts
346 */
347 public function get_formatted_available_layouts_for_export() {
348
349 return array_map(array($this, 'format_layout_for_export'), $this->layouts);
350
351 }
352
8d166d77
DS
353 /**
354 * Get the list of values to add to the grouping dropdown
355 * @return object[] containing name, value and active fields
356 */
357 public function get_customfield_values_for_export() {
358 global $DB, $USER;
359 if (!$this->displaygroupingcustomfield) {
360 return [];
361 }
362 $fieldid = $DB->get_field('customfield_field', 'id', ['shortname' => $this->customfiltergrouping]);
363 if (!$fieldid) {
364 return [];
365 }
366 $courses = enrol_get_all_users_courses($USER->id, true);
367 if (!$courses) {
368 return [];
369 }
370 list($csql, $params) = $DB->get_in_or_equal(array_keys($courses), SQL_PARAMS_NAMED);
371 $select = "instanceid $csql AND fieldid = :fieldid";
372 $params['fieldid'] = $fieldid;
62969935 373 $distinctablevalue = $DB->sql_compare_text('value');
c2164fa6 374 $values = $DB->get_records_select_menu('customfield_data', $select, $params, '',
62969935 375 "DISTINCT $distinctablevalue, $distinctablevalue AS value2");
c2164fa6 376 \core_collator::asort($values, \core_collator::SORT_NATURAL);
8d166d77
DS
377 $values = array_filter($values);
378 if (!$values) {
379 return [];
380 }
381 $field = \core_customfield\field_controller::create($fieldid);
5a119f31
SA
382 $isvisible = $field->get_configdata_property('visibility') == \core_course\customfield\course_handler::VISIBLETOALL;
383 // Only visible fields to everybody supporting course grouping will be displayed.
384 if (!$field->supports_course_grouping() || !$isvisible) {
8d166d77
DS
385 return []; // The field shouldn't have been selectable in the global settings, but just skip it now.
386 }
387 $values = $field->course_grouping_format_values($values);
388 $customfieldactive = ($this->grouping === BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD);
389 $ret = [];
390 foreach ($values as $value => $name) {
391 $ret[] = (object)[
392 'name' => $name,
393 'value' => $value,
394 'active' => ($customfieldactive && ($this->customfieldvalue == $value)),
395 ];
396 }
397 return $ret;
398 }
399
9ac2e865
RW
400 /**
401 * Export this data so it can be used as the context for a mustache template.
402 *
403 * @param \renderer_base $output
3cfff885 404 * @return array Context variables for the template
c0add7c7
TD
405 * @throws \coding_exception
406 *
9ac2e865
RW
407 */
408 public function export_for_template(renderer_base $output) {
ad2ef9dd 409 global $CFG, $USER;
4a995a1f 410
01a95b86 411 $nocoursesurl = $output->image_url('courses', 'block_myoverview')->out();
9ac2e865 412
8d166d77
DS
413 $customfieldvalues = $this->get_customfield_values_for_export();
414 $selectedcustomfield = '';
415 if ($this->grouping == BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD) {
416 foreach ($customfieldvalues as $field) {
417 if ($field->value == $this->customfieldvalue) {
418 $selectedcustomfield = $field->name;
419 break;
420 }
421 }
422 // If the selected custom field value has not been found (possibly because the field has
423 // been changed in the settings) find a suitable fallback.
424 if (!$selectedcustomfield) {
425 $this->grouping = $this->get_fallback_grouping(get_config('block_myoverview'));
426 if ($this->grouping == BLOCK_MYOVERVIEW_GROUPING_CUSTOMFIELD) {
427 // If the fallback grouping is still customfield, then select the first field.
428 $firstfield = reset($customfieldvalues);
429 if ($firstfield) {
430 $selectedcustomfield = $firstfield->name;
431 $this->customfieldvalue = $firstfield->value;
432 }
433 }
434 }
435 }
5f59a4c0
TD
436 $preferences = $this->get_preferences_as_booleans();
437 $availablelayouts = $this->get_formatted_available_layouts_for_export();
ad2ef9dd 438 $sort = '';
439 if ($this->sort == BLOCK_MYOVERVIEW_SORTING_SHORTNAME) {
440 $sort = 'shortname';
441 } else {
442 $sort = $this->sort == BLOCK_MYOVERVIEW_SORTING_TITLE ? 'fullname' : 'ul.timeaccess desc';
443 }
5f59a4c0 444
3cfff885 445 $defaultvariables = [
c0add7c7 446 'totalcoursecount' => count(enrol_get_all_users_courses($USER->id, true)),
3cfff885
BB
447 'nocoursesimg' => $nocoursesurl,
448 'grouping' => $this->grouping,
ad2ef9dd 449 'sort' => $sort,
5f59a4c0
TD
450 // If the user preference display option is not available, default to first available layout.
451 'view' => in_array($this->view, $this->layouts) ? $this->view : reset($this->layouts),
5ae4db88 452 'paging' => $this->paging,
5f59a4c0 453 'layouts' => $availablelayouts,
5ae4db88 454 'displaycategories' => $this->displaycategories,
5f59a4c0 455 'displaydropdown' => (count($availablelayouts) > 1) ? true : false,
2276614c
AB
456 'displaygroupingallincludinghidden' => $this->displaygroupingallincludinghidden,
457 'displaygroupingall' => $this->displaygroupingall,
458 'displaygroupinginprogress' => $this->displaygroupinginprogress,
459 'displaygroupingfuture' => $this->displaygroupingfuture,
460 'displaygroupingpast' => $this->displaygroupingpast,
2d2189ae 461 'displaygroupingfavourites' => $this->displaygroupingfavourites,
2276614c
AB
462 'displaygroupinghidden' => $this->displaygroupinghidden,
463 'displaygroupingselector' => $this->displaygroupingselector,
8d166d77
DS
464 'displaygroupingcustomfield' => $this->displaygroupingcustomfield && $customfieldvalues,
465 'customfieldname' => $this->customfiltergrouping,
466 'customfieldvalue' => $this->customfieldvalue,
467 'customfieldvalues' => $customfieldvalues,
468 'selectedcustomfield' => $selectedcustomfield,
ad2ef9dd 469 'showsortbyshortname' => $CFG->courselistshortnames,
9ac2e865 470 ];
3cfff885
BB
471 return array_merge($defaultvariables, $preferences);
472
9ac2e865 473 }
8d166d77 474}