See Release Notes
Long Term Support Release
<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. /** * Class for rendering user filters on the course participants page. * * @package core_user * @copyright 2020 Michael Hawkins <michaelh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ namespace core_user\output;< use context_course;use core_user\fields;< use renderable;use renderer_base; use stdClass;< use templatable;/** * Class for rendering user filters on the course participants page. * * @copyright 2020 Michael Hawkins <michaelh@moodle.com> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */< class participants_filter implements renderable, templatable { < < /** @var context_course $context The context where the filters are being rendered. */ < protected $context; < < /** @var string $tableregionid The table to be updated by this filter */ < protected $tableregionid; < < /** @var stdClass $course The course shown */ < protected $course; < < /** < * Participants filter constructor. < * < * @param context_course $context The context where the filters are being rendered. < * @param string $tableregionid The table to be updated by this filter < */ < public function __construct(context_course $context, string $tableregionid) { < $this->context = $context; < $this->tableregionid = $tableregionid; < < $this->course = get_course($context->instanceid); < }> class participants_filter extends \core\output\datafilter {/** * Get data for all filter types. * * @return array */ protected function get_filtertypes(): array { $filtertypes = []; $filtertypes[] = $this->get_keyword_filter(); if ($filtertype = $this->get_enrolmentstatus_filter()) { $filtertypes[] = $filtertype; } if ($filtertype = $this->get_roles_filter()) { $filtertypes[] = $filtertype; } if ($filtertype = $this->get_enrolments_filter()) { $filtertypes[] = $filtertype; } if ($filtertype = $this->get_groups_filter()) { $filtertypes[] = $filtertype; } if ($filtertype = $this->get_accesssince_filter()) { $filtertypes[] = $filtertype; } if ($filtertype = $this->get_country_filter()) { $filtertypes[] = $filtertype; } return $filtertypes; } /** * Get data for the enrolment status filter. * * @return stdClass|null */ protected function get_enrolmentstatus_filter(): ?stdClass { if (!has_capability('moodle/course:enrolreview', $this->context)) { return null; } return $this->get_filter_object( 'status', get_string('participationstatus', 'core_enrol'), false, true, null, [ (object) [ 'value' => ENROL_USER_ACTIVE, 'title' => get_string('active'), ], (object) [ 'value' => ENROL_USER_SUSPENDED, 'title' => get_string('inactive'), ], ] ); } /** * Get data for the roles filter. * * @return stdClass|null */ protected function get_roles_filter(): ?stdClass { $roles = []; $roles += [-1 => get_string('noroles', 'role')]; $roles += get_viewable_roles($this->context, null, ROLENAME_BOTH); if (has_capability('moodle/role:assign', $this->context)) { $roles += get_assignable_roles($this->context, ROLENAME_BOTH); } return $this->get_filter_object( 'roles', get_string('roles', 'core_role'), false, true, null, array_map(function($id, $title) { return (object) [ 'value' => $id, 'title' => $title, ]; }, array_keys($roles), array_values($roles)) ); } /** * Get data for the roles filter. * * @return stdClass|null */ protected function get_enrolments_filter(): ?stdClass { if (!has_capability('moodle/course:enrolreview', $this->context)) { return null; } if ($this->course->id == SITEID) { // No enrolment methods for the site. return null; } $instances = enrol_get_instances($this->course->id, true); $plugins = enrol_get_plugins(false); return $this->get_filter_object( 'enrolments', get_string('enrolmentinstances', 'core_enrol'), false, true, null, array_filter(array_map(function($instance) use ($plugins): ?stdClass { if (!array_key_exists($instance->enrol, $plugins)) { return null; } return (object) [ 'value' => $instance->id, 'title' => $plugins[$instance->enrol]->get_instance_name($instance), ]; }, array_values($instances))) ); } /** * Get data for the groups filter. * * @return stdClass|null */ protected function get_groups_filter(): ?stdClass { global $USER; // Filter options for groups, if available. $seeallgroups = has_capability('moodle/site:accessallgroups', $this->context); $seeallgroups = $seeallgroups || ($this->course->groupmode != SEPARATEGROUPS); if ($seeallgroups) { $groups = []; $groups += [USERSWITHOUTGROUP => (object) [ 'id' => USERSWITHOUTGROUP, 'name' => get_string('nogroup', 'group'), ]]; $groups += groups_get_all_groups($this->course->id); } else { // Otherwise, just list the groups the user belongs to. $groups = groups_get_all_groups($this->course->id, $USER->id); } // Return no data if no groups found (which includes if the only value is 'No group'). if (empty($groups) || (count($groups) === 1 && array_key_exists(-1, $groups))) { return null; } return $this->get_filter_object( 'groups', get_string('groups', 'core_group'), false, true, null, array_map(function($group) { return (object) [ 'value' => $group->id, 'title' => format_string($group->name, true, ['context' => $this->context]), ]; }, array_values($groups)) ); } /** * Get data for the accesssince filter. * * @return stdClass|null */ protected function get_accesssince_filter(): ?stdClass { global $CFG, $DB; $hiddenfields = []; if (!has_capability('moodle/course:viewhiddenuserfields', $this->context)) { $hiddenfields = array_flip(explode(',', $CFG->hiddenuserfields)); } if (array_key_exists('lastaccess', $hiddenfields)) { return null; } // Get minimum lastaccess for this course and display a dropbox to filter by lastaccess going back this far. // We need to make it diferently for normal courses and site course. if (!$this->course->id == SITEID) { // Regular course. $params = [ 'courseid' => $this->course->id, 'timeaccess' => 0, ]; $select = 'courseid = :courseid AND timeaccess != :timeaccess'; $minlastaccess = $DB->get_field_select('user_lastaccess', 'MIN(timeaccess)', $select, $params); $lastaccess0exists = $DB->record_exists('user_lastaccess', $params); } else { // Front page. $params = ['lastaccess' => 0]; $select = 'lastaccess != :lastaccess'; $minlastaccess = $DB->get_field_select('user', 'MIN(lastaccess)', $select, $params); $lastaccess0exists = $DB->record_exists('user', $params); } $now = usergetmidnight(time()); $timeoptions = []; $criteria = get_string('usersnoaccesssince'); $getoptions = function(int $count, string $singletype, string $type) use ($now, $minlastaccess): array { $values = []; for ($i = 1; $i <= $count; $i++) { $timestamp = strtotime("-{$i} {$type}", $now); if ($timestamp < $minlastaccess) { break; } if ($i === 1) { $title = get_string("num{$singletype}", 'moodle', $i); } else { $title = get_string("num{$type}", 'moodle', $i); } $values[] = [ 'value' => $timestamp, 'title' => $title, ]; } return $values; }; $values = array_merge( $getoptions(6, 'day', 'days'), $getoptions(10, 'week', 'weeks'), $getoptions(11, 'month', 'months'), $getoptions(1, 'year', 'years') ); if ($lastaccess0exists) { $values[] = [ 'value' => time(), 'title' => get_string('never', 'moodle'), ]; } if (count($values) <= 1) { // Nothing to show. return null; } return $this->get_filter_object( 'accesssince', get_string('usersnoaccesssince'), false, false, null, $values ); } /** * Get data for the country filter * * @return stdClass|null */ protected function get_country_filter(): ?stdClass { $extrauserfields = fields::get_identity_fields($this->context, false); if (array_search('country', $extrauserfields) === false) { return null; } $countries = get_string_manager()->get_list_of_countries(true); return $this->get_filter_object( 'country', get_string('country'), false, true,< 'core_user/local/participantsfilter/filtertypes/country',> 'core/datafilter/filtertypes/country',array_map(function(string $code, string $name): stdClass { return (object) [ 'value' => $code, 'title' => $name, ]; }, array_keys($countries), array_values($countries)) ); } /** * Get data for the keywords filter. * * @return stdClass|null */ protected function get_keyword_filter(): ?stdClass { return $this->get_filter_object( 'keywords', get_string('filterbykeyword', 'core_user'), true, true,< 'core_user/local/participantsfilter/filtertypes/keyword',> 'core/datafilter/filtertypes/keyword',[], true ); } /** * Export the renderer data in a mustache template friendly format. * * @param renderer_base $output Unused. * @return stdClass Data in a format compatible with a mustache template. */ public function export_for_template(renderer_base $output): stdClass { return (object) [ 'tableregionid' => $this->tableregionid, 'courseid' => $this->context->instanceid, 'filtertypes' => $this->get_filtertypes(), 'rownumber' => 1, ]; return $data;< } < < /** < * Get a standardised filter object. < * < * @param string $name < * @param string $title < * @param bool $custom < * @param bool $multiple < * @param string|null $filterclass < * @param array $values < * @param bool $allowempty < * @return stdClass|null < */ < protected function get_filter_object( < string $name, < string $title, < bool $custom, < bool $multiple, < ?string $filterclass, < array $values, < bool $allowempty = false < ): ?stdClass { < < if (!$allowempty && empty($values)) { < // Do not show empty filters. < return null; < } < < return (object) [ < 'name' => $name, < 'title' => $title, < 'allowcustom' => $custom, < 'allowmultiple' => $multiple, < 'filtertypeclass' => $filterclass, < 'values' => $values, < ];} }