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 401 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  declare(strict_types=1);
  18  
  19  namespace core_course\reportbuilder\local\entities;
  20  
  21  use context_course;
  22  use core_course\reportbuilder\local\formatters\enrolment as enrolment_formatter;
  23  use core_reportbuilder\local\entities\base;
  24  use core_reportbuilder\local\filters\date;
  25  use core_reportbuilder\local\filters\select;
  26  use core_reportbuilder\local\helpers\database;
  27  use core_reportbuilder\local\helpers\format;
  28  use core_reportbuilder\local\report\column;
  29  use core_reportbuilder\local\report\filter;
  30  use core_user\output\status_field;
  31  use enrol_plugin;
  32  use lang_string;
  33  use stdClass;
  34  
  35  /**
  36   * Course enrolment entity implementation
  37   *
  38   * @package     core_course
  39   * @copyright   2022 David Matamoros <davidmc@moodle.com>
  40   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41   */
  42  class enrolment extends base {
  43  
  44      /**
  45       * Database tables that this entity uses and their default aliases
  46       *
  47       * @return array
  48       */
  49      protected function get_default_table_aliases(): array {
  50          return ['user_enrolments' => 'ue', 'enrol' => 'e'];
  51      }
  52  
  53      /**
  54       * The default title for this entity in the list of columns/conditions/filters in the report builder
  55       *
  56       * @return lang_string
  57       */
  58      protected function get_default_entity_title(): lang_string {
  59          return new lang_string('enrolment', 'enrol');
  60      }
  61  
  62      /**
  63       * Initialise the entity
  64       *
  65       * @return base
  66       */
  67      public function initialise(): base {
  68          foreach ($this->get_all_columns() as $column) {
  69              $this->add_column($column);
  70          }
  71  
  72          // All the filters defined by the entity can also be used as conditions.
  73          foreach ($this->get_all_filters() as $filter) {
  74              $this
  75                  ->add_filter($filter)
  76                  ->add_condition($filter);
  77          }
  78  
  79          return $this;
  80      }
  81  
  82      /**
  83       * Returns list of all available columns
  84       *
  85       * @return column[]
  86       */
  87      protected function get_all_columns(): array {
  88          $userenrolments = $this->get_table_alias('user_enrolments');
  89          $enrol = $this->get_table_alias('enrol');
  90  
  91          // Enrolment method column.
  92          $columns[] = (new column(
  93              'method',
  94              new lang_string('method', 'enrol'),
  95              $this->get_entity_name()
  96          ))
  97              ->add_joins($this->get_joins())
  98              ->set_type(column::TYPE_TEXT)
  99              ->add_fields("{$enrol}.enrol, {$enrol}.id")
 100              ->set_is_sortable(true)
 101              ->add_callback([enrolment_formatter::class, 'enrolment_name']);
 102  
 103          // Enrolment time created.
 104          $columns[] = (new column(
 105              'timecreated',
 106              new lang_string('timecreated', 'moodle'),
 107              $this->get_entity_name()
 108          ))
 109              ->add_joins($this->get_joins())
 110              ->set_type(column::TYPE_TIMESTAMP)
 111              ->add_field("{$userenrolments}.timecreated")
 112              ->set_is_sortable(true)
 113              ->add_callback([format::class, 'userdate']);
 114  
 115          // Enrolment time started.
 116          $columns[] = (new column(
 117              'timestarted',
 118              new lang_string('timestarted', 'enrol'),
 119              $this->get_entity_name()
 120          ))
 121              ->add_joins($this->get_joins())
 122              ->set_type(column::TYPE_TIMESTAMP)
 123              ->add_field("
 124                  CASE WHEN {$userenrolments}.timestart = 0
 125                       THEN {$userenrolments}.timecreated
 126                       ELSE {$userenrolments}.timestart
 127                   END", 'timestarted')
 128              ->set_is_sortable(true)
 129              ->add_callback([format::class, 'userdate']);
 130  
 131          // Enrolment time ended.
 132          $columns[] = (new column(
 133              'timeended',
 134              new lang_string('timeended', 'enrol'),
 135              $this->get_entity_name()
 136          ))
 137              ->add_joins($this->get_joins())
 138              ->set_type(column::TYPE_TIMESTAMP)
 139              ->add_field("{$userenrolments}.timeend")
 140              ->set_is_sortable(true)
 141              ->add_callback([format::class, 'userdate']);
 142  
 143          // Enrolment status.
 144          $columns[] = (new column(
 145              'status',
 146              new lang_string('status', 'moodle'),
 147              $this->get_entity_name()
 148          ))
 149              ->add_joins($this->get_joins())
 150              ->set_type(column::TYPE_TEXT)
 151              ->add_field($this->get_status_field_sql(), 'status')
 152              ->set_is_sortable(true)
 153              ->add_callback([enrolment_formatter::class, 'enrolment_status']);
 154  
 155          // Role method column.
 156          $ctx = database::generate_alias();
 157          $ra = database::generate_alias();
 158          $r = database::generate_alias();
 159          $columns[] = (new column(
 160              'role',
 161              new lang_string('role', 'moodle'),
 162              $this->get_entity_name()
 163          ))
 164              ->add_joins($this->get_joins())
 165              ->add_join("LEFT JOIN {context} {$ctx}
 166                  ON {$ctx}.instanceid = {$enrol}.courseid AND {$ctx}.contextlevel = " . CONTEXT_COURSE)
 167              ->add_join("LEFT JOIN {role_assignments} {$ra}
 168                  ON {$ra}.contextid = {$ctx}.id AND {$ra}.userid = {$userenrolments}.userid")
 169              ->add_join("LEFT JOIN {role} {$r} ON {$r}.id = {$ra}.roleid")
 170              ->set_type(column::TYPE_TEXT)
 171              ->add_fields("{$r}.id, {$r}.name, {$r}.shortname, {$ctx}.instanceid")
 172              ->set_is_sortable(true, ["{$r}.shortname"])
 173              ->add_callback(static function(?string $value, stdClass $row): string {
 174                  if (!$row->id) {
 175                      return '';
 176                  }
 177                  $context = context_course::instance($row->instanceid);
 178                  return role_get_name($row, $context, ROLENAME_ALIAS);
 179              });
 180  
 181          return $columns;
 182      }
 183  
 184      /**
 185       * Generate SQL snippet suitable for returning enrolment status field
 186       *
 187       * @return string
 188       */
 189      private function get_status_field_sql(): string {
 190          $time = time();
 191          $userenrolments = $this->get_table_alias('user_enrolments');
 192          $enrol = $this->get_table_alias('enrol');
 193  
 194          return "
 195              CASE WHEN {$userenrolments}.status = " . ENROL_USER_ACTIVE . "
 196                   THEN CASE WHEN ({$userenrolments}.timestart > {$time})
 197                               OR ({$userenrolments}.timeend > 0 AND {$userenrolments}.timeend < {$time})
 198                               OR ({$enrol}.status = " . ENROL_INSTANCE_DISABLED . ")
 199                             THEN " . status_field::STATUS_NOT_CURRENT . "
 200                             ELSE " . status_field::STATUS_ACTIVE . "
 201                        END
 202                   ELSE {$userenrolments}.status
 203              END";
 204      }
 205  
 206      /**
 207       * Return list of all available filters
 208       *
 209       * @return filter[]
 210       */
 211      protected function get_all_filters(): array {
 212          $userenrolments = $this->get_table_alias('user_enrolments');
 213          $enrol = $this->get_table_alias('enrol');
 214  
 215          // Enrolment method.
 216          $enrolmentmethods = static function(): array {
 217              return array_map(static function(enrol_plugin $plugin): string {
 218                  return get_string('pluginname', 'enrol_' . $plugin->get_name());
 219              }, enrol_get_plugins(true));
 220          };
 221          $filters[] = (new filter(
 222              select::class,
 223              'method',
 224              new lang_string('method', 'enrol'),
 225              $this->get_entity_name(),
 226              "{$enrol}.enrol"
 227          ))
 228              ->add_joins($this->get_joins())
 229              ->set_options_callback($enrolmentmethods);
 230  
 231          // Enrolment time created.
 232          $filters[] = (new filter(
 233              date::class,
 234              'timecreated',
 235              new lang_string('timecreated', 'moodle'),
 236              $this->get_entity_name(),
 237              "{$userenrolments}.timecreated"
 238          ))
 239              ->add_joins($this->get_joins())
 240              ->set_limited_operators([
 241                  date::DATE_ANY,
 242                  date::DATE_NOT_EMPTY,
 243                  date::DATE_EMPTY,
 244                  date::DATE_RANGE,
 245                  date::DATE_LAST,
 246                  date::DATE_CURRENT,
 247              ]);
 248  
 249          // Enrolment time started.
 250          $filters[] = (new filter(
 251              date::class,
 252              'timestarted',
 253              new lang_string('timestarted', 'enrol'),
 254              $this->get_entity_name(),
 255              "CASE WHEN {$userenrolments}.timestart = 0
 256                            THEN {$userenrolments}.timecreated
 257                            ELSE {$userenrolments}.timestart
 258                        END"
 259          ))
 260              ->add_joins($this->get_joins())
 261              ->set_limited_operators([
 262                  date::DATE_ANY,
 263                  date::DATE_NOT_EMPTY,
 264                  date::DATE_EMPTY,
 265                  date::DATE_RANGE,
 266                  date::DATE_LAST,
 267                  date::DATE_CURRENT,
 268              ]);
 269  
 270          // Enrolment time ended.
 271          $filters[] = (new filter(
 272              date::class,
 273              'timeended',
 274              new lang_string('timeended', 'enrol'),
 275              $this->get_entity_name(),
 276              "{$userenrolments}.timeend"
 277          ))
 278              ->add_joins($this->get_joins())
 279              ->set_limited_operators([
 280                  date::DATE_ANY,
 281                  date::DATE_NOT_EMPTY,
 282                  date::DATE_EMPTY,
 283                  date::DATE_RANGE,
 284                  date::DATE_LAST,
 285                  date::DATE_CURRENT,
 286              ]);
 287  
 288          // Enrolment status.
 289          $filters[] = (new filter(
 290              select::class,
 291              'status',
 292              new lang_string('status', 'moodle'),
 293              $this->get_entity_name(),
 294              $this->get_status_field_sql()
 295          ))
 296              ->add_joins($this->get_joins())
 297              ->set_options(enrolment_formatter::enrolment_values());
 298  
 299          return $filters;
 300      }
 301  }