Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.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  namespace core_grades\form;
  18  
  19  defined('MOODLE_INTERNAL') || die;
  20  
  21  use context;
  22  use context_course;
  23  use core_form\dynamic_form;
  24  use grade_category;
  25  use grade_item;
  26  use grade_plugin_return;
  27  use grade_scale;
  28  use moodle_url;
  29  
  30  require_once($CFG->dirroot.'/grade/lib.php');
  31  
  32  /**
  33   * Prints the add item gradebook form
  34   *
  35   * @copyright 2023 Mathew May <mathew.solutions>
  36   * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
  37   * @package core_grades
  38   */
  39  class add_item extends dynamic_form {
  40  
  41      /** Grade plugin return tracking object.
  42       * @var object $gpr
  43       */
  44      public $gpr;
  45  
  46      /**
  47       * Helper function to grab the current grade item based on information within the form.
  48       *
  49       * @return array
  50       * @throws \moodle_exception
  51       */
  52      private function get_gradeitem(): array {
  53          $courseid = $this->optional_param('courseid', null, PARAM_INT);
  54          $id = $this->optional_param('itemid', null, PARAM_INT);
  55  
  56          if ($gradeitem = grade_item::fetch(['id' => $id, 'courseid' => $courseid])) {
  57              $item = $gradeitem->get_record_data();
  58              $parentcategory = $gradeitem->get_parent_category();
  59          } else {
  60              $gradeitem = new grade_item(['courseid' => $courseid, 'itemtype' => 'manual'], false);
  61              $item = $gradeitem->get_record_data();
  62              $parentcategory = grade_category::fetch_course_category($courseid);
  63          }
  64          $item->parentcategory = $parentcategory->id;
  65          $decimalpoints = $gradeitem->get_decimals();
  66  
  67          if ($item->hidden > 1) {
  68              $item->hiddenuntil = $item->hidden;
  69              $item->hidden = 0;
  70          } else {
  71              $item->hiddenuntil = 0;
  72          }
  73  
  74          $item->locked = !empty($item->locked);
  75  
  76          $item->grademax   = format_float($item->grademax, $decimalpoints);
  77          $item->grademin   = format_float($item->grademin, $decimalpoints);
  78  
  79          if ($parentcategory->aggregation == GRADE_AGGREGATE_SUM || $parentcategory->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN2) {
  80              $item->aggregationcoef = $item->aggregationcoef == 0 ? 0 : 1;
  81          } else {
  82              $item->aggregationcoef = format_float($item->aggregationcoef, 4);
  83          }
  84          if ($parentcategory->aggregation == GRADE_AGGREGATE_SUM) {
  85              $item->aggregationcoef2 = format_float($item->aggregationcoef2 * 100.0);
  86          }
  87          $item->cancontrolvisibility = $gradeitem->can_control_visibility();
  88          return [
  89              'gradeitem' => $gradeitem,
  90              'item' => $item
  91          ];
  92      }
  93  
  94      /**
  95       * Form definition
  96       *
  97       * @return void
  98       * @throws \coding_exception
  99       * @throws \dml_exception
 100       * @throws \moodle_exception
 101       */
 102      protected function definition() {
 103          global $CFG;
 104          $courseid = $this->optional_param('courseid', null, PARAM_INT);
 105          $id = $this->optional_param('itemid', 0, PARAM_INT);
 106          $gprplugin = $this->optional_param('gpr_plugin', '', PARAM_TEXT);
 107  
 108          if ($gprplugin && ($gprplugin !== 'tree')) {
 109              $this->gpr = new grade_plugin_return(['type' => 'report', 'plugin' => $gprplugin, 'courseid' => $courseid]);
 110          } else {
 111              $this->gpr = new grade_plugin_return(['type' => 'edit', 'plugin' => 'tree', 'courseid' => $courseid]);
 112          }
 113  
 114          $mform =& $this->_form;
 115  
 116          $local = $this->get_gradeitem();
 117          $gradeitem = $local['gradeitem'];
 118          $item = $local['item'];
 119  
 120          // Hidden elements.
 121          $mform->addElement('hidden', 'id', 0);
 122          $mform->setType('id', PARAM_INT);
 123          $mform->addElement('hidden', 'courseid', $courseid);
 124          $mform->setType('courseid', PARAM_INT);
 125          $mform->addElement('hidden', 'itemid', $id);
 126          $mform->setType('itemid', PARAM_INT);
 127          $mform->addElement('hidden', 'itemtype', 'manual'); // All new items are manual only.
 128          $mform->setType('itemtype', PARAM_ALPHA);
 129  
 130          // Visible elements.
 131          $mform->addElement('text', 'itemname', get_string('itemname', 'grades'));
 132          $mform->setType('itemname', PARAM_TEXT);
 133  
 134          if (!empty($item->id)) {
 135              // If grades exist set a message so the user knows why they can not alter the grade type or scale.
 136              // We could never change the grade type for external items, so only need to show this for manual grade items.
 137              if ($gradeitem->has_grades() && !$gradeitem->is_external_item()) {
 138                  // Set a message so the user knows why they can not alter the grade type or scale.
 139                  if ($gradeitem->gradetype == GRADE_TYPE_SCALE) {
 140                      $gradesexistmsg = get_string('modgradecantchangegradetyporscalemsg', 'grades');
 141                  } else {
 142                      $gradesexistmsg = get_string('modgradecantchangegradetypemsg', 'grades');
 143                  }
 144  
 145                  $gradesexisthtml = '<div class=\'alert\'>' . $gradesexistmsg . '</div>';
 146                  $mform->addElement('static', 'gradesexistmsg', '', $gradesexisthtml);
 147              }
 148          }
 149  
 150          // Manual grade items cannot have grade type GRADE_TYPE_NONE.
 151          $mform->addElement('select', 'gradetype', get_string('gradetype', 'grades'), [
 152              GRADE_TYPE_VALUE => get_string('typevalue', 'grades'),
 153              GRADE_TYPE_SCALE => get_string('typescale', 'grades'),
 154              GRADE_TYPE_TEXT => get_string('typetext', 'grades')
 155          ]);
 156          $mform->addHelpButton('gradetype', 'gradetype', 'grades');
 157          $mform->setDefault('gradetype', GRADE_TYPE_VALUE);
 158  
 159          $options = [0 => get_string('usenoscale', 'grades')];
 160          if ($scales = grade_scale::fetch_all_local($courseid)) {
 161              foreach ($scales as $scale) {
 162                  $options[$scale->id] = $scale->get_name();
 163              }
 164          }
 165          if ($scales = grade_scale::fetch_all_global()) {
 166              foreach ($scales as $scale) {
 167                  $options[$scale->id] = $scale->get_name();
 168              }
 169          }
 170          $mform->addElement('select', 'scaleid', get_string('scale'), $options);
 171          $mform->addHelpButton('scaleid', 'typescale', 'grades');
 172          $mform->hideIf('scaleid', 'gradetype', 'noteq', GRADE_TYPE_SCALE);
 173  
 174          $mform->addElement('select', 'rescalegrades', get_string('modgraderescalegrades', 'grades'), [
 175              '' => get_string('choose'),
 176              'no' => get_string('no'),
 177              'yes' => get_string('yes')
 178          ]);
 179          $mform->addHelpButton('rescalegrades', 'modgraderescalegrades', 'grades');
 180          $mform->hideIf('rescalegrades', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
 181  
 182          $mform->addElement('float', 'grademax', get_string('grademax', 'grades'));
 183          $mform->addHelpButton('grademax', 'grademax', 'grades');
 184          $mform->hideIf('grademax', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
 185  
 186          if (get_config('moodle', 'grade_report_showmin')) {
 187              $mform->addElement('float', 'grademin', get_string('grademin', 'grades'));
 188              $mform->addHelpButton('grademin', 'grademin', 'grades');
 189              $mform->hideIf('grademin', 'gradetype', 'noteq', GRADE_TYPE_VALUE);
 190          }
 191  
 192          // Hiding.
 193          if ($item->cancontrolvisibility) {
 194              $mform->addElement('advcheckbox', 'hidden', get_string('hidden', 'grades'), '', [], [0, 1]);
 195              $mform->hideIf('hidden', 'hiddenuntil[enabled]', 'checked');
 196          } else {
 197              $mform->addElement('static', 'hidden', get_string('hidden', 'grades'),
 198                  get_string('componentcontrolsvisibility', 'grades'));
 199              // Unset hidden to avoid data override.
 200              unset($item->hidden);
 201          }
 202          $mform->addHelpButton('hidden', 'hidden', 'grades');
 203  
 204          // Locking.
 205          $mform->addElement('advcheckbox', 'locked', get_string('locked', 'grades'));
 206          $mform->addHelpButton('locked', 'locked', 'grades');
 207  
 208          // Weight overrides.
 209          $mform->addElement('advcheckbox', 'weightoverride', get_string('adjustedweight', 'grades'));
 210          $mform->addHelpButton('weightoverride', 'weightoverride', 'grades');
 211          $mform->hideIf('weightoverride', 'gradetype', 'eq', GRADE_TYPE_NONE);
 212          $mform->hideIf('weightoverride', 'gradetype', 'eq', GRADE_TYPE_TEXT);
 213  
 214          // Parent category related settings.
 215          $mform->addElement('float', 'aggregationcoef2', get_string('weight', 'grades'));
 216          $mform->addHelpButton('aggregationcoef2', 'weight', 'grades');
 217          $mform->hideIf('aggregationcoef2', 'weightoverride');
 218          $mform->hideIf('aggregationcoef2', 'gradetype', 'eq', GRADE_TYPE_NONE);
 219          $mform->hideIf('aggregationcoef2', 'gradetype', 'eq', GRADE_TYPE_TEXT);
 220  
 221          $options = [];
 222          $categories = grade_category::fetch_all(['courseid' => $courseid]);
 223  
 224          foreach ($categories as $cat) {
 225              $cat->apply_forced_settings();
 226              $options[$cat->id] = $cat->get_name();
 227          }
 228  
 229          if (count($categories) > 1) {
 230              $mform->addElement('select', 'parentcategory', get_string('gradecategory', 'grades'), $options);
 231          }
 232  
 233          $parentcategory = $gradeitem->get_parent_category();
 234          if (!$parentcategory) {
 235              // If we do not have an id, we are creating a new grade item.
 236  
 237              // Assign the course category to this grade item.
 238              $parentcategory = grade_category::fetch_course_category($courseid);
 239              $gradeitem->parent_category = $parentcategory;
 240          }
 241  
 242          if ($gradeitem->is_external_item()) {
 243              // Following items are set up from modules and should not be overrided by user.
 244              if ($mform->elementExists('grademin')) {
 245                  // The site setting grade_report_showmin may have prevented grademin being added to the form.
 246                  $mform->hardFreeze('grademin');
 247              }
 248              $mform->hardFreeze('itemname,gradetype,grademax,scaleid');
 249  
 250              // For external items we can not change the grade type, even if no grades exist, so if it is set to
 251              // scale, then remove the grademax and grademin fields from the form - no point displaying them.
 252              if ($gradeitem->gradetype == GRADE_TYPE_SCALE) {
 253                  $mform->removeElement('grademax');
 254                  if ($mform->elementExists('grademin')) {
 255                      $mform->removeElement('grademin');
 256                  }
 257              } else { // Not using scale, so remove it.
 258                  $mform->removeElement('scaleid');
 259              }
 260  
 261              // Always remove the rescale grades element if it's an external item.
 262              $mform->removeElement('rescalegrades');
 263          } else if ($gradeitem->has_grades()) {
 264              // Can't change the grade type or the scale if there are grades.
 265              $mform->hardFreeze('gradetype, scaleid');
 266  
 267              // If we are using scales then remove the unnecessary rescale and grade fields.
 268              if ($gradeitem->gradetype == GRADE_TYPE_SCALE) {
 269                  $mform->removeElement('rescalegrades');
 270                  $mform->removeElement('grademax');
 271                  if ($mform->elementExists('grademin')) {
 272                      $mform->removeElement('grademin');
 273                  }
 274              } else { // Remove the scale field.
 275                  $mform->removeElement('scaleid');
 276                  // Set the maximum grade to disabled unless a grade is chosen.
 277                  $mform->hideIf('grademax', 'rescalegrades', 'eq', '');
 278              }
 279          } else {
 280              // Remove rescale element if there are no grades.
 281              $mform->removeElement('rescalegrades');
 282          }
 283  
 284          // If we wanted to change parent of existing item - we would have to verify there are no circular references in parents!!!
 285          if ($id > -1 && $mform->elementExists('parentcategory')) {
 286              $mform->hardFreeze('parentcategory');
 287          }
 288  
 289          $parentcategory->apply_forced_settings();
 290  
 291          if (!$parentcategory->is_aggregationcoef_used()) {
 292              if ($mform->elementExists('aggregationcoef')) {
 293                  $mform->removeElement('aggregationcoef');
 294              }
 295  
 296          } else {
 297              $coefstring = $gradeitem->get_coefstring();
 298  
 299              if ($coefstring !== '') {
 300                  if ($coefstring == 'aggregationcoefextrasum' || $coefstring == 'aggregationcoefextraweightsum') {
 301                      // The advcheckbox is not compatible with disabledIf!
 302                      $coefstring = 'aggregationcoefextrasum';
 303                      $element =& $mform->createElement('checkbox', 'aggregationcoef', get_string($coefstring, 'grades'));
 304                  } else {
 305                      $element =& $mform->createElement('text', 'aggregationcoef', get_string($coefstring, 'grades'));
 306                      $mform->setType('aggregationcoef', PARAM_FLOAT);
 307                  }
 308                  if ($mform->elementExists('parentcategory')) {
 309                      $mform->insertElementBefore($element, 'parentcategory');
 310                  } else {
 311                      $mform->insertElementBefore($element, 'aggregationcoef2');
 312                  }
 313                  $mform->addHelpButton('aggregationcoef', $coefstring, 'grades');
 314              }
 315              $mform->hideIf('aggregationcoef', 'gradetype', 'eq', GRADE_TYPE_NONE);
 316              $mform->hideIf('aggregationcoef', 'gradetype', 'eq', GRADE_TYPE_TEXT);
 317              $mform->hideIf('aggregationcoef', 'parentcategory', 'eq', $parentcategory->id);
 318          }
 319  
 320          // Remove fields used by natural weighting if the parent category is not using natural weighting.
 321          // Or if the item is a scale and scales are not used in aggregation.
 322          if ($parentcategory->aggregation != GRADE_AGGREGATE_SUM
 323              || (empty($CFG->grade_includescalesinaggregation) && $gradeitem->gradetype == GRADE_TYPE_SCALE)) {
 324              if ($mform->elementExists('weightoverride')) {
 325                  $mform->removeElement('weightoverride');
 326              }
 327              if ($mform->elementExists('aggregationcoef2')) {
 328                  $mform->removeElement('aggregationcoef2');
 329              }
 330          }
 331  
 332          if ($category = $gradeitem->get_item_category()) {
 333              if ($category->aggregation == GRADE_AGGREGATE_SUM) {
 334                  if ($mform->elementExists('gradetype')) {
 335                      $mform->hardFreeze('gradetype');
 336                  }
 337                  if ($mform->elementExists('grademin')) {
 338                      $mform->hardFreeze('grademin');
 339                  }
 340                  if ($mform->elementExists('grademax')) {
 341                      $mform->hardFreeze('grademax');
 342                  }
 343                  if ($mform->elementExists('scaleid')) {
 344                      $mform->removeElement('scaleid');
 345                  }
 346              }
 347          }
 348  
 349          $url = new moodle_url('/grade/edit/tree/item.php', ['id' => $id, 'courseid' => $courseid]);
 350          $url = $this->gpr->add_url_params($url);
 351          $url = '<a class="showadvancedform" href="' . $url . '">' . get_string('showmore', 'form') .'</a>';
 352          $mform->addElement('static', 'advancedform', $url);
 353  
 354          // Add return tracking info.
 355          $this->gpr->add_mform_elements($mform);
 356  
 357          $this->set_data($item);
 358      }
 359  
 360      /**
 361       * Return form context
 362       *
 363       * @return context
 364       */
 365      protected function get_context_for_dynamic_submission(): context {
 366          $courseid = $this->optional_param('courseid', null, PARAM_INT);
 367          return context_course::instance($courseid);
 368      }
 369  
 370      /**
 371       * Check if current user has access to this form, otherwise throw exception
 372       *
 373       * @return void
 374       * @throws \required_capability_exception
 375       */
 376      protected function check_access_for_dynamic_submission(): void {
 377          $courseid = $this->optional_param('courseid', null, PARAM_INT);
 378          require_capability('moodle/grade:manage', context_course::instance($courseid));
 379      }
 380  
 381      /**
 382       * Load in existing data as form defaults
 383       *
 384       * @return void
 385       */
 386      public function set_data_for_dynamic_submission(): void {
 387          $this->set_data((object)[
 388              'courseid' => $this->optional_param('courseid', null, PARAM_INT),
 389              'itemid' => $this->optional_param('itemid', null, PARAM_INT)
 390          ]);
 391      }
 392  
 393      /**
 394       * Returns url to set in $PAGE->set_url() when form is being rendered or submitted via AJAX
 395       *
 396       * @return moodle_url
 397       * @throws \moodle_exception
 398       */
 399      protected function get_page_url_for_dynamic_submission(): moodle_url {
 400          $params = [
 401              'id' => $this->optional_param('courseid', null, PARAM_INT),
 402              'itemid' => $this->optional_param('itemid', null, PARAM_INT),
 403          ];
 404          return new moodle_url('/grade/edit/tree/index.php', $params);
 405      }
 406  
 407      /**
 408       * Process the form submission, used if form was submitted via AJAX
 409       *
 410       * @return array
 411       * @throws \moodle_exception
 412       */
 413      public function process_dynamic_submission() {
 414          $data = $this->get_data();
 415  
 416          $url = $this->gpr->get_return_url('index.php?id=' . $data->courseid);
 417          $local = $this->get_gradeitem();
 418          $gradeitem = $local['gradeitem'];
 419          $item = $local['item'];
 420          $parentcategory = grade_category::fetch_course_category($data->courseid);
 421  
 422          // Form submission handling.
 423  
 424          // This is a new item, and the category chosen is different than the default category.
 425          if (empty($gradeitem->id) && isset($data->parentcategory) && $parentcategory->id != $data->parentcategory) {
 426              $parentcategory = grade_category::fetch(['id' => $data->parentcategory]);
 427          }
 428  
 429          // If unset, give the aggregation values a default based on parent aggregation method.
 430          $defaults = grade_category::get_default_aggregation_coefficient_values($parentcategory->aggregation);
 431          if (!isset($data->aggregationcoef) || $data->aggregationcoef == '') {
 432              $data->aggregationcoef = $defaults['aggregationcoef'];
 433          }
 434          if (!isset($data->weightoverride)) {
 435              $data->weightoverride = $defaults['weightoverride'];
 436          }
 437  
 438          if (!isset($data->gradepass) || $data->gradepass == '') {
 439              $data->gradepass = 0;
 440          }
 441  
 442          if (!isset($data->grademin) || $data->grademin == '') {
 443              $data->grademin = 0;
 444          }
 445  
 446          $hide = empty($data->hiddenuntil) ? 0 : $data->hiddenuntil;
 447          if (!$hide) {
 448              $hide = empty($data->hidden) ? 0 : $data->hidden;
 449          }
 450  
 451          $locked   = empty($data->locked) ? 0 : $data->locked;
 452          $locktime = empty($data->locktime) ? 0 : $data->locktime;
 453  
 454          $convert = ['grademax', 'grademin', 'aggregationcoef', 'aggregationcoef2'];
 455          foreach ($convert as $param) {
 456              if (property_exists($data, $param)) {
 457                  $data->$param = unformat_float($data->$param);
 458              }
 459          }
 460          if (isset($data->aggregationcoef2) && $parentcategory->aggregation == GRADE_AGGREGATE_SUM) {
 461              $data->aggregationcoef2 = $data->aggregationcoef2 / 100.0;
 462          } else {
 463              $data->aggregationcoef2 = $defaults['aggregationcoef2'];
 464          }
 465  
 466          $oldmin = $gradeitem->grademin;
 467          $oldmax = $gradeitem->grademax;
 468          grade_item::set_properties($gradeitem, $data);
 469          $gradeitem->outcomeid = null;
 470  
 471          // Handle null decimals value.
 472          if (!property_exists($data, 'decimals') || $data->decimals < 0) {
 473              $gradeitem->decimals = null;
 474          }
 475  
 476          if (empty($gradeitem->id)) {
 477              $gradeitem->itemtype = 'manual'; // All new items to be manual only.
 478              $gradeitem->insert();
 479  
 480              // Set parent if needed.
 481              if (isset($data->parentcategory)) {
 482                  $gradeitem->set_parent($data->parentcategory, false);
 483              }
 484  
 485          } else {
 486              $gradeitem->update();
 487  
 488              if (!empty($data->rescalegrades) && $data->rescalegrades == 'yes') {
 489                  $newmin = $gradeitem->grademin;
 490                  $newmax = $gradeitem->grademax;
 491                  $gradeitem->rescale_grades_keep_percentage($oldmin, $oldmax, $newmin, $newmax, 'gradebook');
 492              }
 493          }
 494  
 495          if ($item->cancontrolvisibility) {
 496              // Update hiding flag.
 497              $gradeitem->set_hidden($hide, true);
 498          }
 499  
 500          $gradeitem->set_locktime($locktime); // Locktime first - it might be removed when unlocking.
 501          $gradeitem->set_locked($locked);
 502          return [
 503              'result' => true,
 504              'url' => $url,
 505              'errors' => [],
 506          ];
 507      }
 508  
 509      /**
 510       * Form validation.
 511       *
 512       * @param array $data array of ("fieldname"=>value) of submitted data
 513       * @param array $files array of uploaded files "element_name"=>tmp_file_path
 514       * @return array of "element_name"=>"error_description" if there are errors,
 515       *         or an empty array if everything is OK (true allowed for backwards compatibility too).
 516       */
 517      public function validation($data, $files): array {
 518          $errors = [];
 519          $local = $this->get_gradeitem();
 520          $gradeitem = $local['gradeitem'];
 521  
 522          if (isset($data['gradetype']) && $data['gradetype'] == GRADE_TYPE_SCALE) {
 523              if (empty($data['scaleid'])) {
 524                  $errors['scaleid'] = get_string('missingscale', 'grades');
 525              }
 526          }
 527  
 528          // We need to make all the validations related with grademax and grademin
 529          // with them being correct floats, keeping the originals unmodified for
 530          // later validations / showing the form back...
 531          // TODO: Note that once MDL-73994 is fixed we'll have to re-visit this and
 532          // adapt the code below to the new values arriving here, without forgetting
 533          // the special case of empties and nulls.
 534          $grademax = isset($data['grademax']) ? unformat_float($data['grademax']) : null;
 535          $grademin = isset($data['grademin']) ? unformat_float($data['grademin']) : null;
 536  
 537          if (!is_null($grademin) && !is_null($grademax)) {
 538              if ($grademax == $grademin || $grademax < $grademin) {
 539                  $errors['grademin'] = get_string('incorrectminmax', 'grades');
 540                  $errors['grademax'] = get_string('incorrectminmax', 'grades');
 541              }
 542          }
 543  
 544          // We do not want the user to be able to change the grade type or scale for this item if grades exist.
 545          if ($gradeitem && $gradeitem->has_grades()) {
 546              // Check that grade type is set - should never not be set unless form has been modified.
 547              if (!isset($data['gradetype'])) {
 548                  $errors['gradetype'] = get_string('modgradecantchangegradetype', 'grades');
 549              } else if ($data['gradetype'] !== $gradeitem->gradetype) { // Check if we are changing the grade type.
 550                  $errors['gradetype'] = get_string('modgradecantchangegradetype', 'grades');
 551              } else if ($data['gradetype'] == GRADE_TYPE_SCALE) {
 552                  // Check if we are changing the scale - can't do this when grades exist.
 553                  if (isset($data['scaleid']) && ($data['scaleid'] !== $gradeitem->scaleid)) {
 554                      $errors['scaleid'] = get_string('modgradecantchangescale', 'grades');
 555                  }
 556              }
 557          }
 558          if ($gradeitem) {
 559              if ($gradeitem->gradetype == GRADE_TYPE_VALUE) {
 560                  if ((((bool) get_config('moodle', 'grade_report_showmin')) &&
 561                          grade_floats_different($grademin, $gradeitem->grademin)) ||
 562                      grade_floats_different($grademax, $gradeitem->grademax)) {
 563                      if ($gradeitem->has_grades() && empty($data['rescalegrades'])) {
 564                          $errors['rescalegrades'] = get_string('mustchooserescaleyesorno', 'grades');
 565                      }
 566                  }
 567              }
 568          }
 569          return $errors;
 570      }
 571  }