Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
<?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 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);
    }

    /**
     * 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;
        }

        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);
> $roles += get_viewable_roles($this->context, null, ROLENAME_BOTH);
if (has_capability('moodle/role:assign', $this->context)) {
< $roles += get_assignable_roles($this->context, ROLENAME_ALIAS);
> $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 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', [], 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, ]; } }