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.
   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   * Repository data generator
  19   *
  20   * @package    repository
  21   * @category   test
  22   * @copyright  2013 Frédéric Massart
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  /**
  29   * Repository data generator class
  30   *
  31   * @package    core
  32   * @category   test
  33   * @copyright  2013 Frédéric Massart
  34   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  35   * @since      Moodle 2.5.1
  36   */
  37  class testing_repository_generator extends component_generator_base {
  38  
  39      /**
  40       * Number of instances created
  41       * @var int
  42       */
  43      protected $instancecount = 0;
  44  
  45      /**
  46       * To be called from data reset code only,
  47       * do not use in tests.
  48       * @return void
  49       */
  50      public function reset() {
  51          $this->instancecount = 0;
  52      }
  53  
  54      /**
  55       * Returns repository type name
  56       *
  57       * @return string name of the type of repository
  58       * @throws coding_exception if class invalid
  59       */
  60      public function get_typename() {
  61          $matches = null;
  62          if (!preg_match('/^repository_([a-z0-9_]+)_generator$/', get_class($this), $matches)) {
  63              throw new coding_exception('Invalid repository generator class name: '.get_class($this));
  64          }
  65          if (empty($matches[1])) {
  66              throw new coding_exception('Invalid repository generator class name: '.get_class($this));
  67          }
  68          return $matches[1];
  69      }
  70  
  71      /**
  72       * Fill in record defaults.
  73       *
  74       * @param array $record
  75       * @return array
  76       */
  77      protected function prepare_record(array $record) {
  78          if (!isset($record['name'])) {
  79              $record['name'] = $this->get_typename() . ' ' . $this->instancecount;
  80          }
  81          if (!isset($record['contextid'])) {
  82              $record['contextid'] = context_system::instance()->id;
  83          }
  84          return $record;
  85      }
  86  
  87      /**
  88       * Fill in type record defaults.
  89       *
  90       * @param array $record
  91       * @return array
  92       */
  93      protected function prepare_type_record(array $record) {
  94          if (!isset($record['pluginname'])) {
  95              $record['pluginname'] = '';
  96          }
  97          if (!isset($record['enableuserinstances'])) {
  98              $record['enableuserinstances'] = 1;
  99          }
 100          if (!isset($record['enablecourseinstances'])) {
 101              $record['enablecourseinstances'] = 1;
 102          }
 103          return $record;
 104      }
 105  
 106      /**
 107       * Create a test repository instance.
 108       *
 109       * @param array|stdClass $record
 110       * @param array $options
 111       * @return stdClass repository instance record
 112       */
 113      public function create_instance($record = null, array $options = null) {
 114          global $CFG, $DB, $PAGE;
 115          require_once($CFG->dirroot . '/repository/lib.php');
 116  
 117          $this->instancecount++;
 118          $record = (array) $record;
 119  
 120          // Creating a repository is a back end operation, which should not cause any output to happen.
 121          // This will allow us to check that the theme was not initialised while creating the repository instance.
 122          $outputstartedbefore = $PAGE->get_where_theme_was_initialised();
 123  
 124          $typeid = $DB->get_field('repository', 'id', array('type' => $this->get_typename()), MUST_EXIST);
 125          $instanceoptions = repository::static_function($this->get_typename(), 'get_instance_option_names');
 126  
 127          if (empty($instanceoptions)) {
 128              // There can only be one instance of this repository, and it should have been created along with the type.
 129              $id = $DB->get_field('repository_instances', 'id', array('typeid' => $typeid), MUST_EXIST);
 130          } else {
 131              // Create the new instance, but first make sure all the required parameters are set.
 132              $record = $this->prepare_record($record);
 133  
 134              if (empty($record['contextid'])) {
 135                  throw new coding_exception('contextid must be present in testing_repository_generator::create_instance() $record');
 136              }
 137  
 138              foreach ($instanceoptions as $option) {
 139                  if (!isset($record[$option])) {
 140                      throw new coding_exception("$option must be present in testing_repository_generator::create_instance() \$record");
 141                  }
 142              }
 143  
 144              $context = context::instance_by_id($record['contextid']);
 145              unset($record['contextid']);
 146              if (!in_array($context->contextlevel, array(CONTEXT_SYSTEM, CONTEXT_COURSE, CONTEXT_USER))) {
 147                  throw new coding_exception('Wrong contextid passed in testing_repository_generator::create_instance() $record');
 148              }
 149  
 150              $id = repository::static_function($this->get_typename(), 'create', $this->get_typename(), 0, $context, $record);
 151          }
 152  
 153          // If the theme was initialised while creating the repository instance, something somewhere called an output
 154          // function. Rather than leaving this as a hard-to-debug situation, let's make it fail with a clear error.
 155          $outputstartedafter = $PAGE->get_where_theme_was_initialised();
 156  
 157          if ($outputstartedbefore === null && $outputstartedafter !== null) {
 158              throw new coding_exception('Creating a repository_' . $this->get_typename() . ' initialised the theme and output!',
 159                  'This should not happen. Creating a repository should be a pure back-end operation. Unnecessarily initialising ' .
 160                  'the output mechanism at the wrong time can cause subtle bugs and is a significant performance hit. There is ' .
 161                  'likely a call to an output function that caused it:' . PHP_EOL . PHP_EOL .
 162                  format_backtrace($outputstartedafter, true));
 163          }
 164  
 165          return $DB->get_record('repository_instances', array('id' => $id), '*', MUST_EXIST);
 166      }
 167  
 168      /**
 169       * Create the type of repository.
 170       *
 171       * @param stdClass|array $record data to use to set up the type
 172       * @param array $options options for the set up of the type
 173       *
 174       * @return stdClass repository type record
 175       */
 176      public function create_type($record = null, array $options = null) {
 177          global $CFG, $DB;
 178          require_once($CFG->dirroot . '/repository/lib.php');
 179  
 180          $record = (array) $record;
 181          $type = $this->get_typename();
 182  
 183          $typeoptions = repository::static_function($type, 'get_type_option_names');
 184          $instanceoptions = repository::static_function($type, 'get_instance_option_names');
 185  
 186          // The type allow for user and course instances.
 187          if (!empty($instanceoptions)) {
 188              $typeoptions[] = 'enableuserinstances';
 189              $typeoptions[] = 'enablecourseinstances';
 190          }
 191  
 192          // Make sure all the parameters are set.
 193          $record = $this->prepare_type_record($record);
 194          foreach ($typeoptions as $option) {
 195              if (!isset($record[$option])) {
 196                  throw new coding_exception("$option must be present in testing::create_repository_type() for $type");
 197              }
 198          }
 199  
 200          // Limit to allowed options.
 201          $record = array_intersect_key($record, array_flip($typeoptions));
 202  
 203          // Create the type.
 204          $plugintype = new repository_type($type, $record);
 205          $plugintype->create(false);
 206  
 207          return $DB->get_record('repository', array('type' => $type));
 208      }
 209  }