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 311 and 401] [Versions 400 and 401] [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  /**
  18   * Events tests.
  19   *
  20   * @package mod_data
  21   * @category test
  22   * @copyright 2014 Mark Nelson <markn@moodle.com>
  23   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  namespace mod_data\event;
  27  
  28  use mod_data\local\importer\preset_existing_importer;
  29  use mod_data\manager;
  30  use mod_data\preset;
  31  
  32  class events_test extends \advanced_testcase {
  33  
  34      /**
  35       * Test set up.
  36       *
  37       * This is executed before running any test in this file.
  38       */
  39      public function setUp(): void {
  40          $this->resetAfterTest();
  41      }
  42  
  43      /**
  44       * Test the field created event.
  45       */
  46      public function test_field_created() {
  47          $this->setAdminUser();
  48  
  49          // Create a course we are going to add a data module to.
  50          $course = $this->getDataGenerator()->create_course();
  51  
  52          // The generator used to create a data module.
  53          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
  54  
  55          // Create a data module.
  56          $data = $generator->create_instance(array('course' => $course->id));
  57  
  58          // Now we want to create a field.
  59          $field = data_get_field_new('text', $data);
  60          $fielddata = new \stdClass();
  61          $fielddata->name = 'Test';
  62          $fielddata->description = 'Test description';
  63          $field->define_field($fielddata);
  64  
  65          // Trigger and capture the event for creating a field.
  66          $sink = $this->redirectEvents();
  67          $field->insert_field();
  68          $events = $sink->get_events();
  69          $event = reset($events);
  70  
  71          // Check that the event data is valid.
  72          $this->assertInstanceOf('\mod_data\event\field_created', $event);
  73          $this->assertEquals(\context_module::instance($data->cmid), $event->get_context());
  74          $expected = array($course->id, 'data', 'fields add', 'field.php?d=' . $data->id . '&amp;mode=display&amp;fid=' .
  75              $field->field->id, $field->field->id, $data->cmid);
  76          $this->assertEventLegacyLogData($expected, $event);
  77          $this->assertEventContextNotUsed($event);
  78          $url = new \moodle_url('/mod/data/field.php', array('d' => $data->id));
  79          $this->assertEquals($url, $event->get_url());
  80      }
  81  
  82      /**
  83       * Test the field updated event.
  84       */
  85      public function test_field_updated() {
  86          $this->setAdminUser();
  87  
  88          // Create a course we are going to add a data module to.
  89          $course = $this->getDataGenerator()->create_course();
  90  
  91          // The generator used to create a data module.
  92          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
  93  
  94          // Create a data module.
  95          $data = $generator->create_instance(array('course' => $course->id));
  96  
  97          // Now we want to create a field.
  98          $field = data_get_field_new('text', $data);
  99          $fielddata = new \stdClass();
 100          $fielddata->name = 'Test';
 101          $fielddata->description = 'Test description';
 102          $field->define_field($fielddata);
 103          $field->insert_field();
 104  
 105          // Trigger and capture the event for updating the field.
 106          $sink = $this->redirectEvents();
 107          $field->update_field();
 108          $events = $sink->get_events();
 109          $event = reset($events);
 110  
 111          // Check that the event data is valid.
 112          $this->assertInstanceOf('\mod_data\event\field_updated', $event);
 113          $this->assertEquals(\context_module::instance($data->cmid), $event->get_context());
 114          $expected = array($course->id, 'data', 'fields update', 'field.php?d=' . $data->id . '&amp;mode=display&amp;fid=' .
 115              $field->field->id, $field->field->id, $data->cmid);
 116          $this->assertEventLegacyLogData($expected, $event);
 117          $this->assertEventContextNotUsed($event);
 118          $url = new \moodle_url('/mod/data/field.php', array('d' => $data->id));
 119          $this->assertEquals($url, $event->get_url());
 120      }
 121  
 122      /**
 123       * Test the field deleted event.
 124       */
 125      public function test_field_deleted() {
 126          $this->setAdminUser();
 127  
 128          // Create a course we are going to add a data module to.
 129          $course = $this->getDataGenerator()->create_course();
 130  
 131          // The generator used to create a data module.
 132          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 133  
 134          // Create a data module.
 135          $data = $generator->create_instance(array('course' => $course->id));
 136  
 137          // Now we want to create a field.
 138          $field = data_get_field_new('text', $data);
 139          $fielddata = new \stdClass();
 140          $fielddata->name = 'Test';
 141          $fielddata->description = 'Test description';
 142          $field->define_field($fielddata);
 143          $field->insert_field();
 144  
 145          // Trigger and capture the event for deleting the field.
 146          $sink = $this->redirectEvents();
 147          $field->delete_field();
 148          $events = $sink->get_events();
 149          $event = reset($events);
 150  
 151          // Check that the event data is valid.
 152          $this->assertInstanceOf('\mod_data\event\field_deleted', $event);
 153          $this->assertEquals(\context_module::instance($data->cmid), $event->get_context());
 154          $expected = array($course->id, 'data', 'fields delete', 'field.php?d=' . $data->id, $field->field->name, $data->cmid);
 155          $this->assertEventLegacyLogData($expected, $event);
 156          $this->assertEventContextNotUsed($event);
 157          $url = new \moodle_url('/mod/data/field.php', array('d' => $data->id));
 158          $this->assertEquals($url, $event->get_url());
 159      }
 160  
 161      /**
 162       * Test the record created event.
 163       */
 164      public function test_record_created() {
 165          // Create a course we are going to add a data module to.
 166          $course = $this->getDataGenerator()->create_course();
 167  
 168          // The generator used to create a data module.
 169          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 170  
 171          // Create a data module.
 172          $data = $generator->create_instance(array('course' => $course->id));
 173  
 174          // Trigger and capture the event for creating the record.
 175          $sink = $this->redirectEvents();
 176          $recordid = data_add_record($data);
 177          $events = $sink->get_events();
 178          $event = reset($events);
 179  
 180          // Check that the event data is valid.
 181          $this->assertInstanceOf('\mod_data\event\record_created', $event);
 182          $this->assertEquals(\context_module::instance($data->cmid), $event->get_context());
 183          $expected = array($course->id, 'data', 'add', 'view.php?d=' . $data->id . '&amp;rid=' . $recordid,
 184              $data->id, $data->cmid);
 185          $this->assertEventLegacyLogData($expected, $event);
 186          $this->assertEventContextNotUsed($event);
 187          $url = new \moodle_url('/mod/data/view.php', array('d' => $data->id, 'rid' => $recordid));
 188          $this->assertEquals($url, $event->get_url());
 189      }
 190  
 191      /**
 192       * Test the record updated event.
 193       *
 194       * There is no external API for updating a record, so the unit test will simply create
 195       * and trigger the event and ensure the legacy log data is returned as expected.
 196       */
 197      public function test_record_updated() {
 198          // Create a course we are going to add a data module to.
 199          $course = $this->getDataGenerator()->create_course();
 200  
 201          // The generator used to create a data module.
 202          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 203  
 204          // Create a data module.
 205          $data = $generator->create_instance(array('course' => $course->id));
 206  
 207          // Trigger an event for updating this record.
 208          $event = \mod_data\event\record_updated::create(array(
 209              'objectid' => 1,
 210              'context' => \context_module::instance($data->cmid),
 211              'courseid' => $course->id,
 212              'other' => array(
 213                  'dataid' => $data->id
 214              )
 215          ));
 216  
 217          // Trigger and capture the event for updating the data record.
 218          $sink = $this->redirectEvents();
 219          $event->trigger();
 220          $events = $sink->get_events();
 221          $event = reset($events);
 222  
 223          // Check that the event data is valid.
 224          $this->assertInstanceOf('\mod_data\event\record_updated', $event);
 225          $this->assertEquals(\context_module::instance($data->cmid), $event->get_context());
 226          $expected = array($course->id, 'data', 'update', 'view.php?d=' . $data->id . '&amp;rid=1', $data->id, $data->cmid);
 227          $this->assertEventLegacyLogData($expected, $event);
 228          $this->assertEventContextNotUsed($event);
 229          $url = new \moodle_url('/mod/data/view.php', array('d' => $data->id, 'rid' => $event->objectid));
 230          $this->assertEquals($url, $event->get_url());
 231      }
 232  
 233      /**
 234       * Test the record deleted event.
 235       */
 236      public function test_record_deleted() {
 237          global $DB;
 238  
 239          // Create a course we are going to add a data module to.
 240          $course = $this->getDataGenerator()->create_course();
 241  
 242          // The generator used to create a data module.
 243          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 244  
 245          // Create a data module.
 246          $data = $generator->create_instance(array('course' => $course->id));
 247  
 248          // Now we want to create a field.
 249          $field = data_get_field_new('text', $data);
 250          $fielddata = new \stdClass();
 251          $fielddata->name = 'Test';
 252          $fielddata->description = 'Test description';
 253          $field->define_field($fielddata);
 254          $field->insert_field();
 255  
 256          // Create data record.
 257          $datarecords = new \stdClass();
 258          $datarecords->userid = '2';
 259          $datarecords->dataid = $data->id;
 260          $datarecords->id = $DB->insert_record('data_records', $datarecords);
 261  
 262          // Create data content.
 263          $datacontent = new \stdClass();
 264          $datacontent->fieldid = $field->field->id;
 265          $datacontent->recordid = $datarecords->id;
 266          $datacontent->id = $DB->insert_record('data_content', $datacontent);
 267  
 268          // Trigger and capture the event for deleting the data record.
 269          $sink = $this->redirectEvents();
 270          data_delete_record($datarecords->id, $data, $course->id, $data->cmid);
 271          $events = $sink->get_events();
 272          $event = reset($events);
 273  
 274          // Check that the event data is valid.
 275          $this->assertInstanceOf('\mod_data\event\record_deleted', $event);
 276          $this->assertEquals(\context_module::instance($data->cmid), $event->get_context());
 277          $expected = array($course->id, 'data', 'record delete', 'view.php?id=' . $data->cmid, $data->id, $data->cmid);
 278          $this->assertEventLegacyLogData($expected, $event);
 279          $this->assertEventContextNotUsed($event);
 280          $url = new \moodle_url('/mod/data/view.php', array('d' => $data->id));
 281          $this->assertEquals($url, $event->get_url());
 282      }
 283  
 284      /**
 285       * Test the template viewed event.
 286       *
 287       * There is no external API for viewing templates, so the unit test will simply create
 288       * and trigger the event and ensure the legacy log data is returned as expected.
 289       */
 290      public function test_template_viewed() {
 291          // Create a course we are going to add a data module to.
 292          $course = $this->getDataGenerator()->create_course();
 293  
 294          // The generator used to create a data module.
 295          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 296  
 297          // Create a data module.
 298          $data = $generator->create_instance(array('course' => $course->id));
 299  
 300          // Trigger an event for updating this record.
 301          $event = \mod_data\event\template_viewed::create(array(
 302              'context' => \context_module::instance($data->cmid),
 303              'courseid' => $course->id,
 304              'other' => array(
 305                  'dataid' => $data->id
 306              )
 307          ));
 308  
 309          // Trigger and capture the event for updating the data record.
 310          $sink = $this->redirectEvents();
 311          $event->trigger();
 312          $events = $sink->get_events();
 313          $event = reset($events);
 314  
 315          // Check that the event data is valid.
 316          $this->assertInstanceOf('\mod_data\event\template_viewed', $event);
 317          $this->assertEquals(\context_module::instance($data->cmid), $event->get_context());
 318          $expected = array($course->id, 'data', 'templates view', 'templates.php?id=' . $data->cmid . '&amp;d=' .
 319              $data->id, $data->id, $data->cmid);
 320          $this->assertEventLegacyLogData($expected, $event);
 321          $this->assertEventContextNotUsed($event);
 322          $url = new \moodle_url('/mod/data/templates.php', array('d' => $data->id));
 323          $this->assertEquals($url, $event->get_url());
 324      }
 325  
 326      /**
 327       * Test the template updated event.
 328       *
 329       * There is no external API for updating a template, so the unit test will simply create
 330       * and trigger the event and ensure the legacy log data is returned as expected.
 331       */
 332      public function test_template_updated() {
 333          // Create a course we are going to add a data module to.
 334          $course = $this->getDataGenerator()->create_course();
 335  
 336          // The generator used to create a data module.
 337          $generator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 338  
 339          // Create a data module.
 340          $data = $generator->create_instance(array('course' => $course->id));
 341  
 342          // Trigger an event for updating this record.
 343          $event = \mod_data\event\template_updated::create(array(
 344              'context' => \context_module::instance($data->cmid),
 345              'courseid' => $course->id,
 346              'other' => array(
 347                  'dataid' => $data->id,
 348              )
 349          ));
 350  
 351          // Trigger and capture the event for updating the data record.
 352          $sink = $this->redirectEvents();
 353          $event->trigger();
 354          $events = $sink->get_events();
 355          $event = reset($events);
 356  
 357          // Check that the event data is valid.
 358          $this->assertInstanceOf('\mod_data\event\template_updated', $event);
 359          $this->assertEquals(\context_module::instance($data->cmid), $event->get_context());
 360          $expected = array($course->id, 'data', 'templates saved', 'templates.php?id=' . $data->cmid . '&amp;d=' .
 361              $data->id, $data->id, $data->cmid);
 362          $this->assertEventLegacyLogData($expected, $event);
 363          $this->assertEventContextNotUsed($event);
 364          $url = new \moodle_url('/mod/data/templates.php', array('d' => $data->id));
 365          $this->assertEquals($url, $event->get_url());
 366      }
 367  
 368      /**
 369       * Data provider for build providers for test_needs_mapping and test_set_affected_fields.
 370       *
 371       * @return array[]
 372       */
 373      public function preset_importer_provider(): array {
 374          // Image gallery preset is: ['title' => 'text', 'description' => 'textarea', 'image' => 'picture'];
 375  
 376          $titlefield = new \stdClass();
 377          $titlefield->name = 'title';
 378          $titlefield->type = 'text';
 379  
 380          $descfield = new \stdClass();
 381          $descfield->name = 'description';
 382          $descfield->type = 'textarea';
 383  
 384          $imagefield = new \stdClass();
 385          $imagefield->name = 'image';
 386          $imagefield->type = 'picture';
 387  
 388          $difffield = new \stdClass();
 389          $difffield->name = 'title';
 390          $difffield->type = 'textarea';
 391  
 392          $newfield = new \stdClass();
 393          $newfield->name = 'number';
 394          $newfield->type = 'number';
 395  
 396          return [
 397              'Empty database / Importer with fields' => [
 398                  'currentfields' => [],
 399                  'newfields' => [$titlefield, $descfield, $imagefield],
 400                  'expected' => ['field_created' => 3],
 401              ],
 402              'Database with fields / Empty importer' => [
 403                  'currentfields' => [$titlefield, $descfield, $imagefield],
 404                  'newfields' => [],
 405                  'expected' => ['field_deleted' => 3],
 406              ],
 407              'Fields to create' => [
 408                  'currentfields' => [$titlefield, $descfield],
 409                  'newfields' => [$titlefield, $descfield, $imagefield],
 410                  'expected' => ['field_updated' => 2, 'field_created' => 1],
 411              ],
 412              'Fields to remove' => [
 413                  'currentfields' => [$titlefield, $descfield, $imagefield, $difffield],
 414                  'newfields' => [$titlefield, $descfield, $imagefield],
 415                  'expected' => ['field_updated' => 2, 'field_deleted' => 1],
 416              ],
 417              'Fields to update' => [
 418                  'currentfields' => [$difffield, $descfield, $imagefield],
 419                  'newfields' => [$titlefield, $descfield, $imagefield],
 420                  'expected' => ['field_updated' => 1, 'field_created' => 1, 'field_deleted' => 1],
 421              ],
 422              'Fields to create, remove and update' => [
 423                  'currentfields' => [$titlefield, $descfield, $imagefield, $difffield],
 424                  'newfields' => [$titlefield, $descfield, $newfield],
 425                  'expected' => ['field_updated' => 2, 'field_created' => 1, 'field_deleted' => 2],
 426              ],
 427          ];
 428      }
 429      /**
 430       * Test for needs_mapping method.
 431       *
 432       * @dataProvider preset_importer_provider
 433       *
 434       * @param array $currentfields Fields of the current activity.
 435       * @param array $newfields Fields to be imported.
 436       * @param array $expected Expected events.
 437       */
 438      public function test_importing_events(
 439          array $currentfields,
 440          array $newfields,
 441          array $expected
 442      ) {
 443  
 444          global $USER;
 445  
 446          $this->resetAfterTest();
 447          $this->setAdminUser();
 448          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_data');
 449  
 450          // Create a course and a database activity.
 451          $course = $this->getDataGenerator()->create_course();
 452          $activity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 453          // Add current fields to the activity.
 454          foreach ($currentfields as $field) {
 455              $plugingenerator->create_field($field, $activity);
 456          }
 457          $manager = manager::create_from_instance($activity);
 458  
 459          $presetactivity = $this->getDataGenerator()->create_module(manager::MODULE, ['course' => $course]);
 460          // Add current fields to the activity.
 461          foreach ($newfields as $field) {
 462              $plugingenerator->create_field($field, $presetactivity);
 463          }
 464  
 465          $record = (object) [
 466              'name' => 'Testing preset name',
 467              'description' => 'Testing preset description',
 468          ];
 469          $saved = $plugingenerator->create_preset($presetactivity, $record);
 470          $savedimporter = new preset_existing_importer($manager, $USER->id . '/Testing preset name');
 471  
 472          // Trigger and capture the event for deleting the field.
 473          $sink = $this->redirectEvents();
 474          $savedimporter->import(false);
 475          $events = $sink->get_events();
 476  
 477          foreach ($expected as $triggeredevent => $count) {
 478              for ($i = 0; $i < $count; $i++) {
 479                  $event = array_shift($events);
 480  
 481                  // Check that the event data is valid.
 482                  $this->assertInstanceOf('\mod_data\event\\'.$triggeredevent, $event);
 483                  $this->assertEquals(\context_module::instance($activity->cmid), $event->get_context());
 484                  $this->assertEventContextNotUsed($event);
 485                  $url = new \moodle_url('/mod/data/field.php', ['d' => $activity->id]);
 486                  $this->assertEquals($url, $event->get_url());
 487              }
 488          }
 489      }
 490  }