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_reportbuilder_generator;
  22  use core_reportbuilder_testcase;
  23  use core_reportbuilder\local\entities\user;
  24  use core_reportbuilder\local\filters\boolean_select;
  25  use core_reportbuilder\local\filters\date;
  26  use core_reportbuilder\local\filters\select;
  27  use core_reportbuilder\local\filters\text;
  28  use core_reportbuilder\local\helpers\user_filter_manager;
  29  use core_reportbuilder\local\report\column;
  30  use core_reportbuilder\local\report\filter;
  31  use core_user\reportbuilder\datasource\users;
  32  
  33  defined('MOODLE_INTERNAL') || die();
  34  
  35  global $CFG;
  36  require_once("{$CFG->dirroot}/reportbuilder/tests/helpers.php");
  37  
  38  /**
  39   * Unit tests for user profile fields helper
  40   *
  41   * @package     core_reportbuilder
  42   * @covers      \core_reportbuilder\local\helpers\user_profile_fields
  43   * @copyright   2021 David Matamoros <davidmc@moodle.com>
  44   * @license     http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  45   */
  46  class user_profile_fields_test extends core_reportbuilder_testcase {
  47  
  48      /**
  49       * Generate custom profile fields, one of each type
  50       *
  51       * @return user_profile_fields
  52       */
  53      private function generate_userprofilefields(): user_profile_fields {
  54          $this->getDataGenerator()->create_custom_profile_field([
  55              'shortname' => 'checkbox', 'name' => 'Checkbox field', 'datatype' => 'checkbox']);
  56  
  57          $this->getDataGenerator()->create_custom_profile_field([
  58              'shortname' => 'datetime', 'name' => 'Date field', 'datatype' => 'datetime', 'param2' => 2022, 'param3' => 0]);
  59  
  60          $this->getDataGenerator()->create_custom_profile_field([
  61              'shortname' => 'menu', 'name' => 'Menu field', 'datatype' => 'menu', 'param1' => "Cat\nDog"]);
  62  
  63          $this->getDataGenerator()->create_custom_profile_field([
  64              'shortname' => 'Social', 'name' => 'msn', 'datatype' => 'social', 'param1' => 'msn']);
  65  
  66          $this->getDataGenerator()->create_custom_profile_field([
  67              'shortname' => 'text', 'name' => 'Text field', 'datatype' => 'text']);
  68  
  69          $this->getDataGenerator()->create_custom_profile_field([
  70              'shortname' => 'textarea', 'name' => 'Textarea field', 'datatype' => 'textarea']);
  71  
  72          $userentity = new user();
  73          $useralias = $userentity->get_table_alias('user');
  74  
  75          // Create an instance of the userprofilefield helper.
  76          return new user_profile_fields("$useralias.id", $userentity->get_entity_name());
  77      }
  78  
  79      /**
  80       * Test for get_columns
  81       */
  82      public function test_get_columns(): void {
  83          $this->resetAfterTest();
  84  
  85          $userentity = new user();
  86          $useralias = $userentity->get_table_alias('user');
  87  
  88          // Get pre-existing user profile fields.
  89          $initialuserprofilefields = new user_profile_fields("$useralias.id", $userentity->get_entity_name());
  90          $initialcolumns = $initialuserprofilefields->get_columns();
  91          $initialcolumntitles = array_map(static function(column $column): string {
  92              return $column->get_title();
  93          }, $initialcolumns);
  94          $initialcolumntypes = array_map(static function(column $column): int {
  95              return $column->get_type();
  96          }, $initialcolumns);
  97  
  98          // Add new custom profile fields.
  99          $userprofilefields = $this->generate_userprofilefields();
 100          $columns = $userprofilefields->get_columns();
 101  
 102          // Columns count should be equal to start + 6.
 103          $this->assertCount(count($initialcolumns) + 6, $columns);
 104          $this->assertContainsOnlyInstancesOf(column::class, $columns);
 105  
 106          // Assert column titles.
 107          $columntitles = array_map(static function(column $column): string {
 108              return $column->get_title();
 109          }, $columns);
 110          $expectedcolumntitles = array_merge($initialcolumntitles, [
 111              'Checkbox field',
 112              'Date field',
 113              'Menu field',
 114              'MSN ID',
 115              'Text field',
 116              'Textarea field',
 117          ]);
 118          $this->assertEquals($expectedcolumntitles, $columntitles);
 119  
 120          // Assert column types.
 121          $columntypes = array_map(static function(column $column): int {
 122              return $column->get_type();
 123          }, $columns);
 124          $expectedcolumntypes = array_merge($initialcolumntypes, [
 125              column::TYPE_BOOLEAN,
 126              column::TYPE_TIMESTAMP,
 127              column::TYPE_TEXT,
 128              column::TYPE_TEXT,
 129              column::TYPE_TEXT,
 130              column::TYPE_LONGTEXT,
 131          ]);
 132          $this->assertEquals($expectedcolumntypes, $columntypes);
 133      }
 134  
 135      /**
 136       * Test for add_join
 137       */
 138      public function test_add_join(): void {
 139          $this->resetAfterTest();
 140  
 141          $userprofilefields = $this->generate_userprofilefields();
 142          $columns = $userprofilefields->get_columns();
 143          $this->assertCount(1, ($columns[0])->get_joins());
 144  
 145          $userprofilefields->add_join('JOIN {test} t ON t.id = id');
 146          $columns = $userprofilefields->get_columns();
 147          $this->assertCount(2, ($columns[0])->get_joins());
 148      }
 149  
 150      /**
 151       * Test for add_joins
 152       */
 153      public function test_add_joins(): void {
 154          $this->resetAfterTest();
 155  
 156          $userprofilefields = $this->generate_userprofilefields();
 157          $columns = $userprofilefields->get_columns();
 158          $this->assertCount(1, ($columns[0])->get_joins());
 159  
 160          $userprofilefields->add_joins(['JOIN {test} t ON t.id = id', 'JOIN {test2} t2 ON t2.id = id']);
 161          $columns = $userprofilefields->get_columns();
 162          $this->assertCount(3, ($columns[0])->get_joins());
 163      }
 164  
 165      /**
 166       * Test for get_filters
 167       */
 168      public function test_get_filters(): void {
 169          $this->resetAfterTest();
 170  
 171          $userentity = new user();
 172          $useralias = $userentity->get_table_alias('user');
 173  
 174          // Get pre-existing user profile fields.
 175          $initialuserprofilefields = new user_profile_fields("$useralias.id", $userentity->get_entity_name());
 176          $initialfilters = $initialuserprofilefields->get_filters();
 177          $initialfilterheaders = array_map(static function(filter $filter): string {
 178              return $filter->get_header();
 179          }, $initialfilters);
 180  
 181          // Add new custom profile fields.
 182          $userprofilefields = $this->generate_userprofilefields();
 183          $filters = $userprofilefields->get_filters();
 184  
 185          // Filters count should be equal to start + 6.
 186          $this->assertCount(count($initialfilters) + 6, $filters);
 187          $this->assertContainsOnlyInstancesOf(filter::class, $filters);
 188  
 189          // Assert filter headers.
 190          $filterheaders = array_map(static function(filter $filter): string {
 191              return $filter->get_header();
 192          }, $filters);
 193          $expectedfilterheaders = array_merge($initialfilterheaders, [
 194              'Checkbox field',
 195              'Date field',
 196              'Menu field',
 197              'MSN ID',
 198              'Text field',
 199              'Textarea field',
 200          ]);
 201          $this->assertEquals($expectedfilterheaders, $filterheaders);
 202      }
 203  
 204      /**
 205       * Test that adding user profile field columns to a report returns expected values
 206       */
 207      public function test_custom_report_content(): void {
 208          $this->resetAfterTest();
 209  
 210          $userprofilefields = $this->generate_userprofilefields();
 211  
 212          // Create test subject with user profile fields content.
 213          $user = $this->getDataGenerator()->create_user([
 214              'firstname' => 'Zebedee',
 215              'profile_field_checkbox' => true,
 216              'profile_field_datetime' => '2021-12-09',
 217              'profile_field_menu' => 'Cat',
 218              'profile_field_Social' => 12345,
 219              'profile_field_text' => 'Hello',
 220              'profile_field_textarea' => 'Goodbye',
 221          ]);
 222  
 223          /** @var core_reportbuilder_generator $generator */
 224          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 225          $report = $generator->create_report(['name' => 'Users', 'source' => users::class, 'default' => 0]);
 226  
 227          // Add user profile field columns to the report.
 228          $firstname = $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:firstname']);
 229          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_checkbox']);
 230          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_datetime']);
 231          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_menu']);
 232          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_Social']);
 233          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_text']);
 234          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:profilefield_textarea']);
 235  
 236          // Sort the report, Admin -> Zebedee for consistency.
 237          report::toggle_report_column_sorting($report->get('id'), $firstname->get('id'), true);
 238  
 239          $content = $this->get_custom_report_content($report->get('id'));
 240          $this->assertEquals([
 241              [
 242                  'c0_firstname' => 'Admin',
 243                  'c1_data' => '',
 244                  'c2_data' => 'Not set',
 245                  'c3_data' => '',
 246                  'c4_data' => '',
 247                  'c5_data' => '',
 248                  'c6_data' => '',
 249              ], [
 250                  'c0_firstname' => 'Zebedee',
 251                  'c1_data' => 'Yes',
 252                  'c2_data' => '9 December 2021',
 253                  'c3_data' => 'Cat',
 254                  'c4_data' => '12345',
 255                  'c5_data' => 'Hello',
 256                  'c6_data' => '<div class="no-overflow">Goodbye</div>',
 257              ],
 258          ], $content);
 259      }
 260  
 261      /**
 262       * Data provider for {@see test_custom_report_filter}
 263       *
 264       * @return array[]
 265       */
 266      public function custom_report_filter_provider(): array {
 267          return [
 268              'Filter by checkbox profile field' => ['user:profilefield_checkbox', [
 269                  'user:profilefield_checkbox_operator' => boolean_select::CHECKED,
 270              ], 'testuser'],
 271              'Filter by checkbox profile field (empty)' => ['user:profilefield_checkbox', [
 272                  'user:profilefield_checkbox_operator' => boolean_select::NOT_CHECKED,
 273              ], 'admin'],
 274              'Filter by datetime profile field' => ['user:profilefield_datetime', [
 275                  'user:profilefield_datetime_operator' => date::DATE_RANGE,
 276                  'user:profilefield_datetime_from' => 1622502000,
 277              ], 'testuser'],
 278              'Filter by datetime profile field (empty)' => ['user:profilefield_datetime', [
 279                  'user:profilefield_datetime_operator' => date::DATE_EMPTY,
 280              ], 'admin'],
 281              'Filter by menu profile field' => ['user:profilefield_menu', [
 282                  'user:profilefield_menu_operator' => select::EQUAL_TO,
 283                  'user:profilefield_menu_value' => 'Dog',
 284              ], 'testuser'],
 285              'Filter by menu profile field (empty)' => ['user:profilefield_menu', [
 286                  'user:profilefield_menu_operator' => select::NOT_EQUAL_TO,
 287                  'user:profilefield_menu_value' => 'Dog',
 288              ], 'admin'],
 289              'Filter by social profile field' => ['user:profilefield_Social', [
 290                  'user:profilefield_Social_operator' => text::IS_EQUAL_TO,
 291                  'user:profilefield_Social_value' => '12345',
 292              ], 'testuser'],
 293              'Filter by social profile field (empty)' => ['user:profilefield_Social', [
 294                  'user:profilefield_Social_operator' => text::IS_EMPTY,
 295              ], 'admin'],
 296              'Filter by text profile field' => ['user:profilefield_text', [
 297                  'user:profilefield_text_operator' => text::IS_EQUAL_TO,
 298                  'user:profilefield_text_value' => 'Hello',
 299              ], 'testuser'],
 300              'Filter by text profile field (empty)' => ['user:profilefield_text', [
 301                  'user:profilefield_text_operator' => text::IS_NOT_EQUAL_TO,
 302                  'user:profilefield_text_value' => 'Hello',
 303              ], 'admin'],
 304              'Filter by textarea profile field' => ['user:profilefield_textarea', [
 305                  'user:profilefield_textarea_operator' => text::IS_EQUAL_TO,
 306                  'user:profilefield_textarea_value' => 'Goodbye',
 307              ], 'testuser'],
 308              'Filter by textarea profile field (empty)' => ['user:profilefield_textarea', [
 309                  'user:profilefield_textarea_operator' => text::DOES_NOT_CONTAIN,
 310                  'user:profilefield_textarea_value' => 'Goodbye',
 311              ], 'admin'],
 312          ];
 313      }
 314  
 315      /**
 316       * Test filtering report by custom profile fields
 317       *
 318       * @param string $filtername
 319       * @param array $filtervalues
 320       * @param string $expectmatchuser
 321       *
 322       * @dataProvider custom_report_filter_provider
 323       */
 324      public function test_custom_report_filter(string $filtername, array $filtervalues, string $expectmatchuser): void {
 325          $this->resetAfterTest();
 326  
 327          $userprofilefields = $this->generate_userprofilefields();
 328  
 329          // Create test subject with user profile fields content.
 330          $user = $this->getDataGenerator()->create_user([
 331              'username' => 'testuser',
 332              'profile_field_checkbox' => true,
 333              'profile_field_datetime' => '2021-12-09',
 334              'profile_field_menu' => 'Dog',
 335              'profile_field_Social' => '12345',
 336              'profile_field_text' => 'Hello',
 337              'profile_field_textarea' => 'Goodbye',
 338          ]);
 339  
 340          /** @var core_reportbuilder_generator $generator */
 341          $generator = $this->getDataGenerator()->get_plugin_generator('core_reportbuilder');
 342  
 343          // Create report containing single column, and given filter.
 344          $report = $generator->create_report(['name' => 'Users', 'source' => users::class, 'default' => 0]);
 345          $generator->create_column(['reportid' => $report->get('id'), 'uniqueidentifier' => 'user:username']);
 346  
 347          // Add filter, set it's values.
 348          $generator->create_filter(['reportid' => $report->get('id'), 'uniqueidentifier' => $filtername]);
 349          user_filter_manager::set($report->get('id'), $filtervalues);
 350  
 351          $content = $this->get_custom_report_content($report->get('id'));
 352  
 353          $this->assertCount(1, $content);
 354          $this->assertEquals($expectmatchuser, reset($content[0]));
 355      }
 356  }