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   * Generator for the gradingforum_rubric plugin.
  19   *
  20   * @package    gradingform_rubric
  21   * @category   test
  22   * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
  23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24   */
  25  
  26  defined('MOODLE_INTERNAL') || die();
  27  
  28  require_once (__DIR__ . '/rubric.php');
  29  require_once (__DIR__ . '/criterion.php');
  30  
  31  use tests\gradingform_rubric\generator\rubric;
  32  use tests\gradingform_rubric\generator\criterion;
  33  
  34  /**
  35   * Generator for the gradingforum_rubric plugintype.
  36   *
  37   * @package    gradingform_rubric
  38   * @category   test
  39   * @copyright  2019 Andrew Nicols <andrew@nicols.co.uk>
  40   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  41   */
  42  class gradingform_rubric_generator extends component_generator_base {
  43  
  44      /**
  45       * Create an instance of a rubric.
  46       *
  47       * @param context $context
  48       * @param string $component
  49       * @param string $area
  50       * @param string $name
  51       * @param string $description
  52       * @param array $criteria The list of criteria to add to the generated rubric
  53       * @return gradingform_rubric_controller
  54       */
  55      public function create_instance(
  56          context $context,
  57          string $component,
  58          string $area,
  59          string $name,
  60          string $description,
  61          array $criteria
  62      ): gradingform_rubric_controller {
  63          global $USER;
  64  
  65          if ($USER->id === 0) {
  66              throw new \coding_exception('Creation of a rubric must currently be run as a user.');
  67          }
  68  
  69          // Fetch the controller for this context/component/area.
  70          $generator = \testing_util::get_data_generator();
  71          $gradinggenerator = $generator->get_plugin_generator('core_grading');
  72          $controller = $gradinggenerator->create_instance($context, $component, $area, 'rubric');
  73  
  74          // Generate a definition for the supplied rubric.
  75          $rubric = $this->get_rubric($name, $description);
  76          foreach ($criteria as $name => $criterion) {
  77              $rubric->add_criteria($this->get_criterion($name, $criterion));
  78          }
  79  
  80          // Update the controller wih the rubric definition.
  81          $controller->update_definition($rubric->get_definition());
  82  
  83          return $controller;
  84      }
  85  
  86      /**
  87       * Get a new rubric for use with the rubric controller.
  88       *
  89       * Note: This is just a helper class used to build a new definition. It does not persist the data.
  90       *
  91       * @param string $name
  92       * @param string $description
  93       * @return rubric
  94       */
  95      protected function get_rubric(string $name, string $description): rubric {
  96          return new rubric($name, $description);
  97      }
  98  
  99      /**
 100       * Get a new rubric for use with a gradingform_rubric_generator_rubric.
 101       *
 102       * Note: This is just a helper class used to build a new definition. It does not persist the data.
 103       *
 104       * @param string $description
 105       * @param array $levels Set of levels in the form definition => score
 106       * @return gradingform_rubric_generator_criterion
 107       */
 108      protected function get_criterion(string $description, array $levels = []): criterion {
 109          return new criterion($description, $levels);
 110      }
 111  
 112      /**
 113       * Given a controller instance, fetch the level and criterion information for the specified values.
 114       *
 115       * @param gradingform_controller $controller
 116       * @param string $description The description to match the criterion on
 117       * @param float $score The value to match the level on
 118       * @return array
 119       */
 120      public function get_level_and_criterion_for_values(
 121          gradingform_controller $controller,
 122          string $description,
 123          float $score
 124      ): array {
 125          $definition = $controller->get_definition();
 126          $criteria = $definition->rubric_criteria;
 127  
 128          $criterion = $level = null;
 129  
 130          $criterion = array_reduce($criteria, function($carry, $criterion) use ($description) {
 131              if ($criterion['description'] === $description) {
 132                  $carry = $criterion;
 133              }
 134  
 135              return $carry;
 136          }, null);
 137  
 138          if ($criterion) {
 139              $criterion = (object) $criterion;
 140              $level = array_reduce($criterion->levels, function($carry, $level) use ($score) {
 141                  if ($level['score'] == $score) {
 142                      $carry = $level;
 143                  }
 144                  return $carry;
 145              });
 146              $level = $level ? (object) $level : null;
 147          }
 148  
 149          return [
 150              'criterion' => $criterion,
 151              'level' => $level,
 152          ];
 153      }
 154  
 155      /**
 156       * Get submitted form data for the supplied controller, itemid, and values.
 157       * The returned data is in the format used by rubric when handling form submission.
 158       *
 159       * @param gradingform_rubric_controller $controller
 160       * @param int $itemid
 161       * @param array $values A set of array values where the array key is the name of the criterion, and the value is an
 162       * array with the desired score, and any remark.
 163       */
 164      public function get_submitted_form_data(gradingform_rubric_controller $controller, int $itemid, array $values): array {
 165          $result = [
 166              'itemid' => $itemid,
 167              'criteria' => [],
 168          ];
 169          foreach ($values as $criterionname => ['score' => $score, 'remark' => $remark]) {
 170              [
 171                  'criterion' => $criterion,
 172                  'level' => $level,
 173              ] = $this->get_level_and_criterion_for_values($controller, $criterionname, $score);
 174              $result['criteria'][$criterion->id] = [
 175                  'levelid' => $level->id,
 176                  'remark' => $remark,
 177              ];
 178          }
 179  
 180          return $result;
 181      }
 182  
 183      /**
 184       * Generate a rubric controller with sample data required for testing of this class.
 185       *
 186       * @param context $context
 187       * @param string $component
 188       * @param string $area
 189       * @return gradingform_rubric_controller
 190       */
 191      public function get_test_rubric(context $context, string $component, string $area): gradingform_rubric_controller {
 192          $criteria = [
 193              'Spelling is important' => [
 194                  'Nothing but mistakes' => 0,
 195                  'Several mistakes' => 1,
 196                  'No mistakes' => 2,
 197              ],
 198              'Pictures' => [
 199                  'No pictures' => 0,
 200                  'One picture' => 1,
 201                  'More than one picture' => 2,
 202              ],
 203          ];
 204  
 205          return $this->create_instance($context, $component, $area, 'testrubric', 'Description text', $criteria);
 206      }
 207  
 208      /**
 209       * Fetch a set of sample data.
 210       *
 211       * @param gradingform_rubric_controller $controller
 212       * @param int $itemid
 213       * @param float $spellingscore
 214       * @param string $spellingremark
 215       * @param float $picturescore
 216       * @param string $pictureremark
 217       * @return array
 218       */
 219      public function get_test_form_data(
 220          gradingform_rubric_controller $controller,
 221          int $itemid,
 222          float $spellingscore,
 223          string $spellingremark,
 224          float $picturescore,
 225          string $pictureremark
 226      ): array {
 227          $generator = \testing_util::get_data_generator();
 228          $rubricgenerator = $generator->get_plugin_generator('gradingform_rubric');
 229          return $rubricgenerator->get_submitted_form_data($controller, $itemid, [
 230              'Spelling is important' => [
 231                  'score' => $spellingscore,
 232                  'remark' => $spellingremark,
 233              ],
 234              'Pictures' => [
 235                  'score' => $picturescore,
 236                  'remark' => $pictureremark,
 237              ],
 238          ]);
 239      }
 240  }