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 402] [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\datasource;
  20  
  21  use completion_completion;
  22  use core_reportbuilder\local\filters\boolean_select;
  23  use core_reportbuilder\local\filters\date;
  24  use core_reportbuilder\local\filters\select;
  25  use core_reportbuilder_generator;
  26  use core_reportbuilder_testcase;
  27  use grade_item;
  28  
  29  defined('MOODLE_INTERNAL') || die();
  30  
  31  global $CFG;
  32  require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
  33  require_once("{$CFG->libdir}/gradelib.php");
  34  
  35  /**
  36   * Course participants datasource tests
  37   *
  38   * @package     core_course
  39   * @covers      \core_course\reportbuilder\datasource\participants
  40   * @covers      \core_course\reportbuilder\local\formatters\completion
  41   * @covers      \core_course\reportbuilder\local\formatters\enrolment
  42   * @copyright   2022 David Matamoros <davidmc@moodle.com>
  43   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  44   */
  45  class participants_test extends core_reportbuilder_testcase {
  46  
  47      /**
  48       * Test participants datasource
  49       */
  50      public function test_participants_datasource(): void {
  51          global $DB;
  52          $this->resetAfterTest();
  53  
  54          $timestart = time() - DAYSECS;
  55          $timeend = $timestart + 3 * DAYSECS;
  56          $timecompleted = $timestart + 2 * DAYSECS;
  57          $timelastaccess = time() + 4 * DAYSECS;
  58  
  59          $category = $this->getDataGenerator()->create_category(['name' => 'Music']);
  60          $course = $this->getDataGenerator()->create_course([
  61              'category' => $category->id,
  62              'fullname' => 'All about Lionel at the work place',
  63              'enablecompletion' => true,
  64              'startdate' => $timestart,
  65              'enddate' => $timeend,
  66          ]);
  67  
  68          $user1 = self::getDataGenerator()->create_user();
  69          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student',
  70              'manual', $timestart, $timeend, ENROL_USER_ACTIVE);
  71  
  72          // Add them to a group.
  73          $group = self::getDataGenerator()->create_group(['courseid' => $course->id]);
  74          self::getDataGenerator()->create_group_member(['groupid' => $group->id, 'userid' => $user1->id]);
  75  
  76          // Mark course as completed for the user.
  77          $ccompletion = new completion_completion(array('course' => $course->id, 'userid' => $user1->id));
  78          $ccompletion->mark_enrolled($timestart);
  79          $ccompletion->mark_complete($timecompleted);
  80  
  81          // Update final grade for the user.
  82          $courseitem = grade_item::fetch_course_item($course->id);
  83          $courseitem->update_final_grade($user1->id, 42.5);
  84  
  85          // Set some last access value for the user in the course.
  86          $DB->insert_record('user_lastaccess',
  87              ['userid' => $user1->id, 'courseid' => $course->id, 'timeaccess' => $timelastaccess]);
  88  
  89          /** @var core_reportbuilder_generator $generator */
  90          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
  91          $report = $generator->create_report(['name' => 'Courses', 'source' => participants::class, 'default' => false]);
  92  
  93          $generator->create_column(['reportid' => $report->get('id'),
  94              'uniqueidentifier' => 'course:fullname']);
  95          $generator->create_column(['reportid' => $report->get('id'),
  96              'uniqueidentifier' => 'course_category:name']);
  97          $generator->create_column(['reportid' => $report->get('id'),
  98              'uniqueidentifier' => 'user:fullname']);
  99          // Order by enrolment method.
 100          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'enrolment:method', 'sortenabled' => 1]);
 101          $generator->create_column(['reportid' => $report->get('id'),
 102              'uniqueidentifier' => 'group:name']);
 103          $generator->create_column(['reportid' => $report->get('id'),
 104              'uniqueidentifier' => 'completion:completed']);
 105          $generator->create_column(['reportid' => $report->get('id'),
 106              'uniqueidentifier' => 'access:timeaccess']);
 107          $generator->create_column(['reportid' => $report->get('id'),
 108              'uniqueidentifier' => 'completion:progresspercent']);
 109          $generator->create_column(['reportid' => $report->get('id'),
 110              'uniqueidentifier' => 'completion:timeenrolled']);
 111          $generator->create_column(['reportid' => $report->get('id'),
 112              'uniqueidentifier' => 'completion:timestarted']);
 113          $generator->create_column(['reportid' => $report->get('id'),
 114              'uniqueidentifier' => 'completion:timecompleted']);
 115          $generator->create_column(['reportid' => $report->get('id'),
 116              'uniqueidentifier' => 'completion:reaggregate']);
 117          $generator->create_column(['reportid' => $report->get('id'),
 118              'uniqueidentifier' => 'completion:dayscourse']);
 119          $generator->create_column(['reportid' => $report->get('id'),
 120              'uniqueidentifier' => 'completion:daysuntilcompletion']);
 121          $generator->create_column(['reportid' => $report->get('id'),
 122              'uniqueidentifier' => 'completion:grade']);
 123  
 124          // Add filter to the report.
 125          $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'enrolment:method']);
 126  
 127          $content = $this->get_custom_report_content($report->get('id'));
 128  
 129          // It should get 3 records (manual enrolment, self and guest).
 130          $this->assertCount(3, $content);
 131  
 132          // Filter by Manual enrolment method.
 133          $content = $this->get_custom_report_content($report->get('id'), 30, [
 134              'enrolment:method_operator' => select::EQUAL_TO,
 135              'enrolment:method_value' => 'manual',
 136          ]);
 137  
 138          $this->assertCount(1, $content);
 139  
 140          $this->assertEquals([
 141              'All about Lionel at the work place', // Course name.
 142              'Music', // Course category name.
 143              fullname($user1), // User fullname.
 144              'Manual enrolments', // Enrolment method.
 145              $group->name, // Group name.
 146              'Yes', // Course completed.
 147              userdate($timelastaccess), // Time last access.
 148              '100.0%', // Progress percentage.
 149              userdate($timestart), // Time enrolled.
 150              '', // Time started.
 151              userdate($timecompleted), // Time completed.
 152              '', // Reagreggate.
 153              '2', // Days taking course.
 154              '2', // Days until completion.
 155              '42.50', // Grade.
 156          ], array_values($content[0]));
 157      }
 158  
 159      /**
 160       * Data provider for {@see test_report_filters}
 161       *
 162       * @return array
 163       */
 164      public function filters_data_provider(): array {
 165          return [
 166              [
 167                  'enrolment:status',
 168                  [
 169                      'enrolment:status_operator' => select::EQUAL_TO,
 170                      'enrolment:status_value' => 1,
 171                  ],
 172                  'Luna'
 173              ],
 174              [
 175                  'enrolment:timecreated',
 176                  [
 177                      'enrolment:timecreated_operator' => date::DATE_CURRENT,
 178                      'enrolment:timecreated_unit' => date::DATE_UNIT_DAY,
 179                  ],
 180                  'Kira'
 181              ],
 182              [
 183                  'enrolment:timestarted',
 184                  [
 185                      'enrolment:timestarted_operator' => date::DATE_CURRENT,
 186                      'enrolment:timecreated_unit' => date::DATE_UNIT_DAY,
 187                  ],
 188                  'Luna'
 189              ],
 190              [
 191                  'enrolment:timeended',
 192                  [
 193                      'enrolment:timeended_operator' => date::DATE_CURRENT,
 194                      'enrolment:timeended_unit' => date::DATE_UNIT_DAY,
 195                  ],
 196                  'Luna'
 197              ],
 198              [
 199                  'completion:completed',
 200                  [
 201                      'completion:completed_operator' => boolean_select::CHECKED,
 202                      'completion:completed_unit' => 1,
 203                  ],
 204                  'Lionel'
 205              ],
 206              [
 207                  'completion:timecompleted',
 208                  [
 209                      'completion:timecompleted_operator' => date::DATE_NOT_EMPTY,
 210                  ],
 211                  'Lionel'
 212              ],
 213          ];
 214      }
 215  
 216      /**
 217       * Test getting filter SQL
 218       *
 219       * @param string $filter
 220       * @param array $filtervalues
 221       * @param string $expected
 222       *
 223       * @dataProvider filters_data_provider
 224       */
 225      public function test_report_filters(string $filter, array $filtervalues, string $expected): void {
 226          global $DB;
 227          $this->resetAfterTest();
 228  
 229          $timestart = time() - DAYSECS;
 230          $timeend = $timestart + 3 * DAYSECS;
 231          $timecompleted = $timestart + 2 * DAYSECS;
 232          $timelastaccess = time() + 4 * DAYSECS;
 233  
 234          $category = $this->getDataGenerator()->create_category(['name' => 'Music']);
 235          $course = $this->getDataGenerator()->create_course([
 236              'category' => $category->id,
 237              'fullname' => 'All about Lionel at the work place',
 238              'enablecompletion' => true,
 239              'startdate' => $timestart,
 240              'enddate' => $timeend,
 241          ]);
 242  
 243          $user1 = self::getDataGenerator()->create_user(['firstname' => 'Lionel']);
 244          $user2 = self::getDataGenerator()->create_user(['firstname' => 'Kira']);
 245          $user3 = self::getDataGenerator()->create_user(['firstname' => 'Luna']);
 246  
 247          $this->getDataGenerator()->enrol_user($user1->id, $course->id, 'student',
 248              'manual', $timestart - 8 * DAYSECS, $timeend, ENROL_USER_ACTIVE);
 249          $this->getDataGenerator()->enrol_user($user2->id, $course->id, 'student',
 250              'manual', $timestart, $timeend, ENROL_USER_ACTIVE);
 251          $this->getDataGenerator()->enrol_user($user3->id, $course->id, 'student',
 252              'manual', time(), time(), ENROL_USER_SUSPENDED);
 253  
 254          // Mark course as completed for the user.
 255          $ccompletion = new completion_completion(array('course' => $course->id, 'userid' => $user1->id));
 256          $ccompletion->mark_enrolled($timestart);
 257          $ccompletion->mark_complete($timecompleted);
 258  
 259          // Set some last access value for the user in the course.
 260          $DB->insert_record('user_lastaccess',
 261              ['userid' => $user1->id, 'courseid' => $course->id, 'timeaccess' => $timelastaccess]);
 262  
 263          /** @var core_reportbuilder_generator $generator */
 264          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 265          $report = $generator->create_report(['name' => 'Courses', 'source' => participants::class, 'default' => false]);
 266  
 267          // Add user firstname column to the report.
 268          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:firstname']);
 269  
 270          $DB->set_field('user_enrolments', 'timecreated', 0, ['userid' => $user1->id]);
 271          $DB->set_field('user_enrolments', 'timecreated', 0, ['userid' => $user3->id]);
 272  
 273          // Add filters to the report.
 274          $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => 'enrolment:method']);
 275          $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filter]);
 276  
 277          // Apply filters.
 278          $filtermanual = ['enrolment:method_operator' => select::EQUAL_TO, 'enrolment:method_value' => 'manual'];
 279          $content = $this->get_custom_report_content($report->get('id'), 30, $filtermanual + $filtervalues);
 280  
 281          $this->assertCount(1, $content);
 282          $this->assertEquals($expected, $content[0]['c0_firstname']);
 283      }
 284  
 285      /**
 286       * Stress test datasource
 287       *
 288       * In order to execute this test PHPUNIT_LONGTEST should be defined as true in phpunit.xml or directly in config.php
 289       */
 290      public function test_stress_datasource(): void {
 291          if (!PHPUNIT_LONGTEST) {
 292              $this->markTestSkipped('PHPUNIT_LONGTEST is not defined');
 293          }
 294  
 295          $this->resetAfterTest();
 296  
 297          $course = $this->getDataGenerator()->create_course();
 298          $this->getDataGenerator()->create_and_enrol($course);
 299  
 300          $this->datasource_stress_test_columns(participants::class);
 301          $this->datasource_stress_test_columns_aggregation(participants::class);
 302          $this->datasource_stress_test_conditions(participants::class, 'course:idnumber');
 303      }
 304  }