Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.0.x will end 8 May 2023 (12 months).
  • Bug fixes for security issues in 4.0.x will end 13 November 2023 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: the minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is also supported.

Differences Between: [Versions 400 and 401] [Versions 400 and 402] [Versions 400 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_reportbuilder\local\helpers;
  20  
  21  use core_customfield_generator;
  22  use core_reportbuilder_generator;
  23  use core_reportbuilder_testcase;
  24  use core_reportbuilder\local\entities\course;
  25  use core_reportbuilder\local\helpers\user_filter_manager;
  26  use core_reportbuilder\local\filters\boolean_select;
  27  use core_reportbuilder\local\filters\date;
  28  use core_reportbuilder\local\filters\select;
  29  use core_reportbuilder\local\filters\text;
  30  use core_reportbuilder\local\report\column;
  31  use core_reportbuilder\local\report\filter;
  32  use core_course\reportbuilder\datasource\courses;
  33  
  34  defined('MOODLE_INTERNAL') || die();
  35  
  36  global $CFG;
  37  require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
  38  
  39  /**
  40   * Unit tests for custom fields helper
  41   *
  42   * @package     core_reportbuilder
  43   * @covers      \core_reportbuilder\local\helpers\custom_fields
  44   * @copyright   2021 David Matamoros <davidmc@moodle.com>
  45   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  46   */
  47  class custom_fields_test extends core_reportbuilder_testcase {
  48  
  49      /**
  50       * Generate custom fields, one of each type
  51       *
  52       * @return custom_fields
  53       */
  54      private function generate_customfields(): custom_fields {
  55  
  56          /** @var core_customfield_generator $generator */
  57          $generator = $this->getDataGenerator()->get_plugin_generator('core_customfield');
  58          $category = $generator->create_category([
  59              'component' => 'core_course',
  60              'area' => 'course',
  61              'itemid' => 0,
  62              'contextid' => \context_system::instance()->id
  63          ]);
  64  
  65          $generator->create_field(
  66              ['categoryid' => $category->get('id'), 'type' => 'text', 'name' => 'Text', 'shortname' => 'text']);
  67  
  68          $generator->create_field(
  69              ['categoryid' => $category->get('id'), 'type' => 'checkbox', 'name' => 'Checkbox', 'shortname' => 'checkbox']);
  70  
  71          $generator->create_field(
  72              ['categoryid' => $category->get('id'), 'type' => 'date', 'name' => 'Date', 'shortname' => 'date']);
  73  
  74          $generator->create_field(
  75              ['categoryid' => $category->get('id'), 'type' => 'select', 'name' => 'Select', 'shortname' => 'select',
  76                  'configdata' => ['options' => "Cat\nDog", 'defaultvalue' => 'Cat']]);
  77  
  78          $courseentity = new course();
  79          $coursealias = $courseentity->get_table_alias('course');
  80  
  81          // Create an instance of the customfields helper.
  82          return new custom_fields($coursealias . '.id', $courseentity->get_entity_name(),
  83              'core_course', 'course');
  84      }
  85  
  86      /**
  87       * Test for get_columns
  88       */
  89      public function test_get_columns(): void {
  90          $this->resetAfterTest();
  91  
  92          $customfields = $this->generate_customfields();
  93          $columns = $customfields->get_columns();
  94  
  95          $this->assertCount(4, $columns);
  96          $this->assertContainsOnlyInstancesOf(column::class, $columns);
  97  
  98          [$column0, $column1, $column2, $column3] = $columns;
  99          $this->assertEqualsCanonicalizing(['Text', 'Checkbox', 'Date', 'Select'],
 100              [$column0->get_title(), $column1->get_title(), $column2->get_title(), $column3->get_title()]);
 101  
 102          $this->assertEquals(column::TYPE_TEXT, $column0->get_type());
 103          $this->assertEquals('course', $column0->get_entity_name());
 104          $this->assertStringStartsWith('LEFT JOIN {customfield_data}', $column0->get_joins()[0]);
 105          // Column of type TEXT is sortable.
 106          $this->assertTrue($column0->get_is_sortable());
 107      }
 108  
 109      /**
 110       * Test for add_join
 111       */
 112      public function test_add_join(): void {
 113          $this->resetAfterTest();
 114  
 115          $customfields = $this->generate_customfields();
 116          $columns = $customfields->get_columns();
 117          $this->assertCount(1, ($columns[0])->get_joins());
 118  
 119          $customfields->add_join('JOIN {test} t ON t.id = id');
 120          $columns = $customfields->get_columns();
 121          $this->assertCount(2, ($columns[0])->get_joins());
 122      }
 123  
 124      /**
 125       * Test for add_joins
 126       */
 127      public function test_add_joins(): void {
 128          $this->resetAfterTest();
 129  
 130          $customfields = $this->generate_customfields();
 131          $columns = $customfields->get_columns();
 132          $this->assertCount(1, ($columns[0])->get_joins());
 133  
 134          $customfields->add_joins(['JOIN {test} t ON t.id = id', 'JOIN {test2} t2 ON t2.id = id']);
 135          $columns = $customfields->get_columns();
 136          $this->assertCount(3, ($columns[0])->get_joins());
 137      }
 138  
 139      /**
 140       * Test for get_filters
 141       */
 142      public function test_get_filters(): void {
 143          $this->resetAfterTest();
 144  
 145          $customfields = $this->generate_customfields();
 146          $filters = $customfields->get_filters();
 147  
 148          $this->assertCount(4, $filters);
 149          $this->assertContainsOnlyInstancesOf(filter::class, $filters);
 150  
 151          [$filter0, $filter1, $filter2, $filter3] = $filters;
 152          $this->assertEqualsCanonicalizing(['Text', 'Checkbox', 'Date', 'Select'],
 153              [$filter0->get_header(), $filter1->get_header(), $filter2->get_header(), $filter3->get_header()]);
 154      }
 155  
 156      /**
 157       * Test that adding custom field columns to a report returns expected values
 158       */
 159      public function test_custom_report_content(): void {
 160          $this->resetAfterTest();
 161  
 162          $this->generate_customfields();
 163  
 164          $course = $this->getDataGenerator()->create_course(['customfields' => [
 165              ['shortname' => 'text', 'value' => 'Hello'],
 166              ['shortname' => 'checkbox', 'value' => true],
 167              ['shortname' => 'date', 'value' => 1669852800],
 168              ['shortname' => 'select', 'value' => 2],
 169          ]]);
 170  
 171          /** @var core_reportbuilder_generator $generator */
 172          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 173          $report = $generator->create_report(['name' => 'Courses', 'source' => courses::class, 'default' => 0]);
 174  
 175          // Add user profile field columns to the report.
 176          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
 177          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_text']);
 178          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_checkbox']);
 179          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_date']);
 180          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:customfield_select']);
 181  
 182          $content = $this->get_custom_report_content($report->get('id'));
 183  
 184          $this->assertEquals([
 185              $course->fullname,
 186              'Hello',
 187              'Yes',
 188              userdate(1669852800),
 189              'Dog'
 190          ], array_values($content[0]));
 191      }
 192  
 193      /**
 194       * Data provider for {@see test_custom_report_filter}
 195       *
 196       * @return array[]
 197       */
 198      public function custom_report_filter_provider(): array {
 199          return [
 200              'Filter by text custom field' => ['course:customfield_text', [
 201                  'course:customfield_text_operator' => text::IS_EQUAL_TO,
 202                  'course:customfield_text_value' => 'Hello',
 203              ], true],
 204              'Filter by text custom field (no match)' => ['course:customfield_text', [
 205                  'course:customfield_text_operator' => text::IS_EQUAL_TO,
 206                  'course:customfield_text_value' => 'Goodbye',
 207              ], false],
 208              'Filter by checkbox custom field' => ['course:customfield_checkbox', [
 209                  'course:customfield_checkbox_operator' => boolean_select::CHECKED,
 210              ], true],
 211              'Filter by checkbox custom field (no match)' => ['course:customfield_checkbox', [
 212                  'course:customfield_checkbox_operator' => boolean_select::NOT_CHECKED,
 213              ], false],
 214              'Filter by date custom field' => ['course:customfield_date', [
 215                  'course:customfield_date_operator' => date::DATE_RANGE,
 216                  'course:customfield_date_from' => 1622502000,
 217              ], true],
 218              'Filter by date custom field (no match)' => ['course:customfield_date', [
 219                  'course:customfield_date_operator' => date::DATE_RANGE,
 220                  'course:customfield_date_to' => 1622502000,
 221              ], false],
 222              'Filter by select custom field' => ['course:customfield_select', [
 223                  'course:customfield_select_operator' => select::EQUAL_TO,
 224                  'course:customfield_select_value' => 2,
 225              ], true],
 226              'Filter by select custom field (no match)' => ['course:customfield_select', [
 227                  'course:customfield_select_operator' => select::EQUAL_TO,
 228                  'course:customfield_select_value' => 1,
 229              ], false],
 230          ];
 231      }
 232  
 233      /**
 234       * Test filtering report by custom fields
 235       *
 236       * @param string $filtername
 237       * @param array $filtervalues
 238       * @param bool $expectmatch
 239       *
 240       * @dataProvider custom_report_filter_provider
 241       */
 242      public function test_custom_report_filter(string $filtername, array $filtervalues, bool $expectmatch): void {
 243          $this->resetAfterTest();
 244  
 245          $this->generate_customfields();
 246  
 247          $course = $this->getDataGenerator()->create_course(['customfields' => [
 248              ['shortname' => 'text', 'value' => 'Hello'],
 249              ['shortname' => 'checkbox', 'value' => true],
 250              ['shortname' => 'date', 'value' => 1669852800],
 251              ['shortname' => 'select', 'value' => 2],
 252          ]]);
 253  
 254          /** @var core_reportbuilder_generator $generator */
 255          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 256  
 257          // Create report containing single column, and given filter.
 258          $report = $generator->create_report(['name' => 'Users', 'source' => courses::class, 'default' => 0]);
 259          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'course:fullname']);
 260  
 261          // Add filter, set it's values.
 262          $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
 263          user_filter_manager::set($report->get('id'), $filtervalues);
 264  
 265          $content = $this->get_custom_report_content($report->get('id'));
 266  
 267          if ($expectmatch) {
 268              $this->assertCount(1, $content);
 269              $this->assertEquals($course->fullname, reset($content[0]));
 270          } else {
 271              $this->assertEmpty($content);
 272          }
 273      }
 274  }
 275