See Release Notes
Long Term Support Release
Differences Between: [Versions 39 and 310] [Versions 39 and 311] [Versions 39 and 400] [Versions 39 and 401] [Versions 39 and 402] [Versions 39 and 403]
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 for rendering user filters on the course participants page. 19 * 20 * @package core_user 21 * @copyright 2020 Michael Hawkins <michaelh@moodle.com> 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 namespace core_user\output; 25 26 use context_course; 27 use renderable; 28 use renderer_base; 29 use stdClass; 30 use templatable; 31 32 /** 33 * Class for rendering user filters on the course participants page. 34 * 35 * @copyright 2020 Michael Hawkins <michaelh@moodle.com> 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class participants_filter implements renderable, templatable { 39 40 /** @var context_course $context The context where the filters are being rendered. */ 41 protected $context; 42 43 /** @var string $tableregionid The table to be updated by this filter */ 44 protected $tableregionid; 45 46 /** @var stdClass $course The course shown */ 47 protected $course; 48 49 /** 50 * Participants filter constructor. 51 * 52 * @param context_course $context The context where the filters are being rendered. 53 * @param string $tableregionid The table to be updated by this filter 54 */ 55 public function __construct(context_course $context, string $tableregionid) { 56 $this->context = $context; 57 $this->tableregionid = $tableregionid; 58 59 $this->course = get_course($context->instanceid); 60 } 61 62 /** 63 * Get data for all filter types. 64 * 65 * @return array 66 */ 67 protected function get_filtertypes(): array { 68 $filtertypes = []; 69 70 $filtertypes[] = $this->get_keyword_filter(); 71 72 if ($filtertype = $this->get_enrolmentstatus_filter()) { 73 $filtertypes[] = $filtertype; 74 } 75 76 if ($filtertype = $this->get_roles_filter()) { 77 $filtertypes[] = $filtertype; 78 } 79 80 if ($filtertype = $this->get_enrolments_filter()) { 81 $filtertypes[] = $filtertype; 82 } 83 84 if ($filtertype = $this->get_groups_filter()) { 85 $filtertypes[] = $filtertype; 86 } 87 88 if ($filtertype = $this->get_accesssince_filter()) { 89 $filtertypes[] = $filtertype; 90 } 91 92 return $filtertypes; 93 } 94 95 /** 96 * Get data for the enrolment status filter. 97 * 98 * @return stdClass|null 99 */ 100 protected function get_enrolmentstatus_filter(): ?stdClass { 101 if (!has_capability('moodle/course:enrolreview', $this->context)) { 102 return null; 103 } 104 105 return $this->get_filter_object( 106 'status', 107 get_string('participationstatus', 'core_enrol'), 108 false, 109 true, 110 null, 111 [ 112 (object) [ 113 'value' => ENROL_USER_ACTIVE, 114 'title' => get_string('active'), 115 ], 116 (object) [ 117 'value' => ENROL_USER_SUSPENDED, 118 'title' => get_string('inactive'), 119 ], 120 ] 121 ); 122 } 123 124 /** 125 * Get data for the roles filter. 126 * 127 * @return stdClass|null 128 */ 129 protected function get_roles_filter(): ?stdClass { 130 $roles = []; 131 $roles += [-1 => get_string('noroles', 'role')]; 132 $roles += get_viewable_roles($this->context); 133 134 if (has_capability('moodle/role:assign', $this->context)) { 135 $roles += get_assignable_roles($this->context, ROLENAME_ALIAS); 136 } 137 138 return $this->get_filter_object( 139 'roles', 140 get_string('roles', 'core_role'), 141 false, 142 true, 143 null, 144 array_map(function($id, $title) { 145 return (object) [ 146 'value' => $id, 147 'title' => $title, 148 ]; 149 }, array_keys($roles), array_values($roles)) 150 ); 151 } 152 153 /** 154 * Get data for the roles filter. 155 * 156 * @return stdClass|null 157 */ 158 protected function get_enrolments_filter(): ?stdClass { 159 if (!has_capability('moodle/course:enrolreview', $this->context)) { 160 return null; 161 } 162 163 if ($this->course->id == SITEID) { 164 // No enrolment methods for the site. 165 return null; 166 } 167 168 $instances = enrol_get_instances($this->course->id, true); 169 $plugins = enrol_get_plugins(false); 170 171 return $this->get_filter_object( 172 'enrolments', 173 get_string('enrolmentinstances', 'core_enrol'), 174 false, 175 true, 176 null, 177 array_filter(array_map(function($instance) use ($plugins): ?stdClass { 178 if (!array_key_exists($instance->enrol, $plugins)) { 179 return null; 180 } 181 182 return (object) [ 183 'value' => $instance->id, 184 'title' => $plugins[$instance->enrol]->get_instance_name($instance), 185 ]; 186 }, array_values($instances))) 187 ); 188 } 189 190 /** 191 * Get data for the groups filter. 192 * 193 * @return stdClass|null 194 */ 195 protected function get_groups_filter(): ?stdClass { 196 global $USER; 197 198 // Filter options for groups, if available. 199 $seeallgroups = has_capability('moodle/site:accessallgroups', $this->context); 200 $seeallgroups = $seeallgroups || ($this->course->groupmode != SEPARATEGROUPS); 201 if ($seeallgroups) { 202 $groups = []; 203 $groups += [USERSWITHOUTGROUP => (object) [ 204 'id' => USERSWITHOUTGROUP, 205 'name' => get_string('nogroup', 'group'), 206 ]]; 207 $groups += groups_get_all_groups($this->course->id); 208 } else { 209 // Otherwise, just list the groups the user belongs to. 210 $groups = groups_get_all_groups($this->course->id, $USER->id); 211 } 212 213 // Return no data if no groups found (which includes if the only value is 'No group'). 214 if (empty($groups) || (count($groups) === 1 && array_key_exists(-1, $groups))) { 215 return null; 216 } 217 218 return $this->get_filter_object( 219 'groups', 220 get_string('groups', 'core_group'), 221 false, 222 true, 223 null, 224 array_map(function($group) { 225 return (object) [ 226 'value' => $group->id, 227 'title' => format_string($group->name, true, ['context' => $this->context]), 228 ]; 229 }, array_values($groups)) 230 ); 231 } 232 233 /** 234 * Get data for the accesssince filter. 235 * 236 * @return stdClass|null 237 */ 238 protected function get_accesssince_filter(): ?stdClass { 239 global $CFG, $DB; 240 241 $hiddenfields = []; 242 if (!has_capability('moodle/course:viewhiddenuserfields', $this->context)) { 243 $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields)); 244 } 245 246 if (array_key_exists('lastaccess', $hiddenfields)) { 247 return null; 248 } 249 250 // Get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far. 251 // We need to make it diferently for normal courses and site course. 252 if (!$this->course->id == SITEID) { 253 // Regular course. 254 $params = [ 255 'courseid' => $this->course->id, 256 'timeaccess' => 0, 257 ]; 258 $select = 'courseid = :courseid AND timeaccess != :timeaccess'; 259 $minlastaccess = $DB->get_field_select('user_lastaccess', 'MIN(timeaccess)', $select, $params); 260 $lastaccess0exists = $DB->record_exists('user_lastaccess', $params); 261 } else { 262 // Front page. 263 $params = ['lastaccess' => 0]; 264 $select = 'lastaccess != :lastaccess'; 265 $minlastaccess = $DB->get_field_select('user', 'MIN(lastaccess)', $select, $params); 266 $lastaccess0exists = $DB->record_exists('user', $params); 267 } 268 269 $now = usergetmidnight(time()); 270 $timeoptions = []; 271 $criteria = get_string('usersnoaccesssince'); 272 273 $getoptions = function(int $count, string $singletype, string $type) use ($now, $minlastaccess): array { 274 $values = []; 275 for ($i = 1; $i <= $count; $i++) { 276 $timestamp = strtotime("-{$i} {$type}", $now); 277 if ($timestamp < $minlastaccess) { 278 break; 279 } 280 281 if ($i === 1) { 282 $title = get_string("num{$singletype}", 'moodle', $i); 283 } else { 284 $title = get_string("num{$type}", 'moodle', $i); 285 } 286 287 $values[] = [ 288 'value' => $timestamp, 289 'title' => $title, 290 ]; 291 } 292 293 return $values; 294 }; 295 296 $values = array_merge( 297 $getoptions(6, 'day', 'days'), 298 $getoptions(10, 'week', 'weeks'), 299 $getoptions(11, 'month', 'months'), 300 $getoptions(1, 'year', 'years') 301 ); 302 303 if ($lastaccess0exists) { 304 $values[] = [ 305 'value' => time(), 306 'title' => get_string('never', 'moodle'), 307 ]; 308 } 309 310 if (count($values) <= 1) { 311 // Nothing to show. 312 return null; 313 } 314 315 return $this->get_filter_object( 316 'accesssince', 317 get_string('usersnoaccesssince'), 318 false, 319 false, 320 null, 321 $values 322 ); 323 } 324 325 /** 326 * Get data for the keywords filter. 327 * 328 * @return stdClass|null 329 */ 330 protected function get_keyword_filter(): ?stdClass { 331 return $this->get_filter_object( 332 'keywords', 333 get_string('filterbykeyword', 'core_user'), 334 true, 335 true, 336 'core_user/local/participantsfilter/filtertypes/keyword', 337 [], 338 true 339 ); 340 } 341 342 /** 343 * Export the renderer data in a mustache template friendly format. 344 * 345 * @param renderer_base $output Unused. 346 * @return stdClass Data in a format compatible with a mustache template. 347 */ 348 public function export_for_template(renderer_base $output): stdClass { 349 return (object) [ 350 'tableregionid' => $this->tableregionid, 351 'courseid' => $this->context->instanceid, 352 'filtertypes' => $this->get_filtertypes(), 353 'rownumber' => 1, 354 ]; 355 356 return $data; 357 } 358 359 /** 360 * Get a standardised filter object. 361 * 362 * @param string $name 363 * @param string $title 364 * @param bool $custom 365 * @param bool $multiple 366 * @param string|null $filterclass 367 * @param array $values 368 * @param bool $allowempty 369 * @return stdClass|null 370 */ 371 protected function get_filter_object( 372 string $name, 373 string $title, 374 bool $custom, 375 bool $multiple, 376 ?string $filterclass, 377 array $values, 378 bool $allowempty = false 379 ): ?stdClass { 380 381 if (!$allowempty && empty($values)) { 382 // Do not show empty filters. 383 return null; 384 } 385 386 return (object) [ 387 'name' => $name, 388 'title' => $title, 389 'allowcustom' => $custom, 390 'allowmultiple' => $multiple, 391 'filtertypeclass' => $filterclass, 392 'values' => $values, 393 ]; 394 } 395 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body