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 310 and 401] [Versions 39 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  namespace core_calendar;
  18  
  19  use core_calendar\local\event\factories\event_factory;
  20  use core_calendar\local\event\entities\event_interface;
  21  
  22  defined('MOODLE_INTERNAL') || die();
  23  
  24  global $CFG;
  25  require_once($CFG->dirroot . '/calendar/lib.php');
  26  
  27  /**
  28   * Event factory test.
  29   *
  30   * @package core_calendar
  31   * @copyright 2017 Cameron Ball <cameron@cameron1729.xyz>
  32   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33   */
  34  class event_factory_test extends \advanced_testcase {
  35      /**
  36       * Test event class getters.
  37       *
  38       * @dataProvider create_instance_testcases()
  39       * @param \stdClass $dbrow Row from the event table.
  40       * @param callable  $actioncallbackapplier     Action callback applier.
  41       * @param callable  $visibilitycallbackapplier Visibility callback applier.
  42       * @param callable  $bailoutcheck              Early bail out check function.
  43       * @param string    $expectedclass             Class the factory is expected to produce.
  44       * @param mixed     $expectedattributevalue    Expected value of the modified attribute.
  45       */
  46      public function test_create_instance(
  47          $dbrow,
  48          callable $actioncallbackapplier,
  49          callable $visibilitycallbackapplier,
  50          callable $bailoutcheck,
  51          $expectedclass,
  52          $expectedattributevalue
  53      ) {
  54          $this->resetAfterTest(true);
  55          $this->setAdminUser();
  56          $event = $this->create_event();
  57          $coursecache = [];
  58          $modulecache = [];
  59          $factory = new event_factory(
  60              $actioncallbackapplier,
  61              $visibilitycallbackapplier,
  62              $bailoutcheck,
  63              $coursecache,
  64              $modulecache
  65          );
  66          $dbrow->id = $event->id;
  67          $instance = $factory->create_instance($dbrow);
  68  
  69          if ($expectedclass) {
  70              $this->assertInstanceOf($expectedclass, $instance);
  71          }
  72  
  73          if (is_null($expectedclass)) {
  74              $this->assertNull($instance);
  75          }
  76  
  77          if ($expectedattributevalue) {
  78              $this->assertEquals($instance->testattribute, $expectedattributevalue);
  79          }
  80      }
  81  
  82      /**
  83       * Test invalid callback exception.
  84       */
  85      public function test_invalid_action_callback() {
  86          $this->resetAfterTest(true);
  87          $this->setAdminUser();
  88          $event = $this->create_event();
  89          $coursecache = [];
  90          $modulecache = [];
  91          $factory = new event_factory(
  92              function () {
  93                  return 'hello';
  94              },
  95              function () {
  96                  return true;
  97              },
  98              function () {
  99                  return false;
 100              },
 101              $coursecache,
 102              $modulecache
 103          );
 104  
 105          $this->expectException('\core_calendar\local\event\exceptions\invalid_callback_exception');
 106          $factory->create_instance(
 107              (object)[
 108                  'id' => $event->id,
 109                  'name' => 'test',
 110                  'description' => 'Test description',
 111                  'format' => 2,
 112                  'categoryid' => 0,
 113                  'courseid' => 1,
 114                  'groupid' => 1,
 115                  'userid' => 1,
 116                  'repeatid' => 0,
 117                  'modulename' => 'assign',
 118                  'instance' => 1,
 119                  'eventtype' => 'due',
 120                  'type' => CALENDAR_EVENT_TYPE_ACTION,
 121                  'timestart' => 123456789,
 122                  'timeduration' => 12,
 123                  'timemodified' => 123456789,
 124                  'timesort' => 123456789,
 125                  'visible' => 1,
 126                  'subscriptionid' => 1,
 127                  'location' => 'Test location',
 128              ]
 129          );
 130      }
 131  
 132      /**
 133       * Test invalid callback exception.
 134       */
 135      public function test_invalid_visibility_callback() {
 136          $this->resetAfterTest(true);
 137          $this->setAdminUser();
 138          $event = $this->create_event();
 139          $coursecache = [];
 140          $modulecache = [];
 141          $factory = new event_factory(
 142              function ($event) {
 143                  return $event;
 144              },
 145              function () {
 146                  return 'asdf';
 147              },
 148              function () {
 149                  return false;
 150              },
 151              $coursecache,
 152              $modulecache
 153          );
 154  
 155          $this->expectException('\core_calendar\local\event\exceptions\invalid_callback_exception');
 156          $factory->create_instance(
 157              (object)[
 158                  'id' => $event->id,
 159                  'name' => 'test',
 160                  'description' => 'Test description',
 161                  'format' => 2,
 162                  'categoryid' => 0,
 163                  'courseid' => 1,
 164                  'groupid' => 1,
 165                  'userid' => 1,
 166                  'repeatid' => 0,
 167                  'modulename' => 'assign',
 168                  'instance' => 1,
 169                  'eventtype' => 'due',
 170                  'type' => CALENDAR_EVENT_TYPE_ACTION,
 171                  'timestart' => 123456789,
 172                  'timeduration' => 12,
 173                  'timemodified' => 123456789,
 174                  'timesort' => 123456789,
 175                  'visible' => 1,
 176                  'subscriptionid' => 1,
 177                  'location' => 'Test location',
 178              ]
 179          );
 180      }
 181  
 182      /**
 183       * Test invalid callback exception.
 184       */
 185      public function test_invalid_bail_callback() {
 186          $this->resetAfterTest(true);
 187          $this->setAdminUser();
 188          $event = $this->create_event();
 189          $coursecache = [];
 190          $modulecache = [];
 191          $factory = new event_factory(
 192              function ($event) {
 193                  return $event;
 194              },
 195              function () {
 196                  return true;
 197              },
 198              function () {
 199                  return 'asdf';
 200              },
 201              $coursecache,
 202              $modulecache
 203          );
 204  
 205          $this->expectException('\core_calendar\local\event\exceptions\invalid_callback_exception');
 206          $factory->create_instance(
 207              (object)[
 208                  'id' => $event->id,
 209                  'name' => 'test',
 210                  'description' => 'Test description',
 211                  'format' => 2,
 212                  'categoryid' => 0,
 213                  'courseid' => 1,
 214                  'groupid' => 1,
 215                  'userid' => 1,
 216                  'repeatid' => 0,
 217                  'modulename' => 'assign',
 218                  'instance' => 1,
 219                  'eventtype' => 'due',
 220                  'type' => CALENDAR_EVENT_TYPE_ACTION,
 221                  'timestart' => 123456789,
 222                  'timeduration' => 12,
 223                  'timemodified' => 123456789,
 224                  'timesort' => 123456789,
 225                  'visible' => 1,
 226                  'subscriptionid' => 1,
 227                  'location' => 'Test location',
 228              ]
 229          );
 230      }
 231  
 232      /**
 233       * Test the factory's course cache.
 234       */
 235      public function test_course_cache() {
 236          $this->resetAfterTest(true);
 237          $this->setAdminUser();
 238          $course = self::getDataGenerator()->create_course();
 239          $event = $this->create_event(['courseid' => $course->id]);
 240          $coursecache = [];
 241          $modulecache = [];
 242          $factory = new event_factory(
 243              function ($event) {
 244                  return $event;
 245              },
 246              function () {
 247                  return true;
 248              },
 249              function () {
 250                  return false;
 251              },
 252              $coursecache,
 253              $modulecache
 254          );
 255  
 256          $instance = $factory->create_instance(
 257              (object)[
 258                  'id' => $event->id,
 259                  'name' => 'test',
 260                  'description' => 'Test description',
 261                  'format' => 2,
 262                  'categoryid' => 0,
 263                  'courseid' => $course->id,
 264                  'groupid' => 1,
 265                  'userid' => 1,
 266                  'repeatid' => 0,
 267                  'modulename' => 'assign',
 268                  'instance' => 1,
 269                  'eventtype' => 'due',
 270                  'type' => CALENDAR_EVENT_TYPE_ACTION,
 271                  'timestart' => 123456789,
 272                  'timeduration' => 12,
 273                  'timemodified' => 123456789,
 274                  'timesort' => 123456789,
 275                  'visible' => 1,
 276                  'subscriptionid' => 1,
 277                  'location' => 'Test location',
 278              ]
 279          );
 280  
 281          $instance->get_course()->get('fullname');
 282          $this->assertArrayHasKey($course->id, $coursecache);
 283      }
 284  
 285      /**
 286       * Test the factory's module cache.
 287       */
 288      public function test_module_cache() {
 289          $this->resetAfterTest(true);
 290          $this->setAdminUser();
 291          $course = self::getDataGenerator()->create_course();
 292          $event = $this->create_event(['courseid' => $course->id]);
 293          $plugingenerator = $this->getDataGenerator()->get_plugin_generator('mod_assign');
 294          $assigninstance = $plugingenerator->create_instance(['course' => $course->id]);
 295  
 296          $coursecache = [];
 297          $modulecache = [];
 298          $factory = new event_factory(
 299              function ($event) {
 300                  return $event;
 301              },
 302              function () {
 303                  return true;
 304              },
 305              function () {
 306                  return false;
 307              },
 308              $coursecache,
 309              $modulecache
 310          );
 311  
 312          $instance = $factory->create_instance(
 313              (object)[
 314                  'id' => $event->id,
 315                  'name' => 'test',
 316                  'description' => 'Test description',
 317                  'format' => 2,
 318                  'categoryid' => 0,
 319                  'courseid' => 0,
 320                  'groupid' => 1,
 321                  'userid' => 1,
 322                  'repeatid' => 0,
 323                  'modulename' => 'assign',
 324                  'instance' => $assigninstance->id,
 325                  'eventtype' => 'due',
 326                  'type' => CALENDAR_EVENT_TYPE_ACTION,
 327                  'timestart' => 123456789,
 328                  'timeduration' => 12,
 329                  'timemodified' => 123456789,
 330                  'timesort' => 123456789,
 331                  'visible' => 1,
 332                  'subscriptionid' => 1,
 333                  'location' => 'Test location',
 334              ]
 335          );
 336  
 337          $instance->get_course_module()->get('course');
 338          $this->assertArrayHasKey('assign' . '_' . $assigninstance->id, $modulecache);
 339      }
 340  
 341      /**
 342       * Testcases for the create instance test.
 343       *
 344       * @return array Array of testcases.
 345       */
 346      public function create_instance_testcases() {
 347          return [
 348              'Sample event record with event exposed' => [
 349                  'dbrow' => (object)[
 350                      'name' => 'Test event',
 351                      'description' => 'Hello',
 352                      'format' => 1,
 353                      'categoryid' => 0,
 354                      'courseid' => 1,
 355                      'groupid' => 1,
 356                      'userid' => 1,
 357                      'repeatid' => 0,
 358                      'modulename' => 'Test module',
 359                      'instance' => 1,
 360                      'eventtype' => 'Due',
 361                      'type' => CALENDAR_EVENT_TYPE_ACTION,
 362                      'timestart' => 123456789,
 363                      'timeduration' => 123456789,
 364                      'timemodified' => 123456789,
 365                      'timesort' => 123456789,
 366                      'visible' => true,
 367                      'subscriptionid' => 1,
 368                      'location' => 'Test location',
 369                  ],
 370                  'actioncallbackapplier' => function(event_interface $event) {
 371                      $event->testattribute = 'Hello';
 372                      return $event;
 373                  },
 374                  'visibilitycallbackapplier' => function(event_interface $event) {
 375                      return true;
 376                  },
 377                  'bailoutcheck' => function() {
 378                      return false;
 379                  },
 380                  event_interface::class,
 381                  'Hello'
 382              ],
 383              'Sample event record with event hidden' => [
 384                  'dbrow' => (object)[
 385                      'name' => 'Test event',
 386                      'description' => 'Hello',
 387                      'format' => 1,
 388                      'categoryid' => 0,
 389                      'courseid' => 1,
 390                      'groupid' => 1,
 391                      'userid' => 1,
 392                      'repeatid' => 0,
 393                      'modulename' => 'Test module',
 394                      'instance' => 1,
 395                      'eventtype' => 'Due',
 396                      'type' => CALENDAR_EVENT_TYPE_ACTION,
 397                      'timestart' => 123456789,
 398                      'timeduration' => 123456789,
 399                      'timemodified' => 123456789,
 400                      'timesort' => 123456789,
 401                      'visible' => true,
 402                      'subscriptionid' => 1,
 403                      'location' => 'Test location',
 404                  ],
 405                  'actioncallbackapplier' => function(event_interface $event) {
 406                      $event->testattribute = 'Hello';
 407                      return $event;
 408                  },
 409                  'visibilitycallbackapplier' => function(event_interface $event) {
 410                      return false;
 411                  },
 412                  'bailoutcheck' => function() {
 413                      return false;
 414                  },
 415                  null,
 416                  null
 417              ],
 418              'Sample event record with early bail' => [
 419                  'dbrow' => (object)[
 420                      'name' => 'Test event',
 421                      'description' => 'Hello',
 422                      'format' => 1,
 423                      'categoryid' => 0,
 424                      'courseid' => 1,
 425                      'groupid' => 1,
 426                      'userid' => 1,
 427                      'repeatid' => 0,
 428                      'modulename' => 'Test module',
 429                      'instance' => 1,
 430                      'eventtype' => 'Due',
 431                      'type' => CALENDAR_EVENT_TYPE_ACTION,
 432                      'timestart' => 123456789,
 433                      'timeduration' => 123456789,
 434                      'timemodified' => 123456789,
 435                      'timesort' => 123456789,
 436                      'visible' => true,
 437                      'subscriptionid' => 1,
 438                      'location' => 'Test location',
 439                  ],
 440                  'actioncallbackapplier' => function(event_interface $event) {
 441                      $event->testattribute = 'Hello';
 442                      return $event;
 443                  },
 444                  'visibilitycallbackapplier' => function(event_interface $event) {
 445                      return true;
 446                  },
 447                  'bailoutcheck' => function() {
 448                      return true;
 449                  },
 450                  null,
 451                  null
 452              ]
 453          ];
 454      }
 455  
 456      /**
 457       * Helper function to create calendar events using the old code.
 458       *
 459       * @param array $properties A list of calendar event properties to set
 460       * @return calendar_event
 461       */
 462      protected function create_event($properties = []) {
 463          $record = new \stdClass();
 464          $record->name = 'event name';
 465          $record->eventtype = 'site';
 466          $record->timestart = time();
 467          $record->timeduration = 0;
 468          $record->timesort = 0;
 469          $record->type = 1;
 470          $record->courseid = 0;
 471          $record->categoryid = 0;
 472  
 473          foreach ($properties as $name => $value) {
 474              $record->$name = $value;
 475          }
 476  
 477          $event = new \calendar_event($record);
 478          return $event->create($record, false);
 479      }
 480  }