Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401] [Versions 400 and 401]

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