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.

Differences Between: [Versions 311 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 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   * List of deprecated mod_quiz functions.
  19   *
  20   * @package   mod_quiz
  21   * @copyright 2021 Shamim Rezaie <shamim@moodle.com>
  22   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  use mod_quiz\access_manager;
  26  use mod_quiz\quiz_settings;
  27  use mod_quiz\task\update_overdue_attempts;
  28  
  29  /**
  30   * @deprecated since Moodle 3.11
  31   */
  32  function quiz_get_completion_state() {
  33      $completionclass = \mod_quiz\completion\custom_completion::class;
  34      throw new coding_exception(__FUNCTION__ . "() has been removed, please use the '{$completionclass}' class instead");
  35  }
  36  
  37  /**
  38   * Retrieves tag information for the given list of quiz slot ids.
  39   * Currently the only slots that have tags are random question slots.
  40   *
  41   * Example:
  42   * If we have 3 slots with id 1, 2, and 3. The first slot has two tags, the second
  43   * has one tag, and the third has zero tags. The return structure will look like:
  44   * [
  45   *      1 => [
  46   *          quiz_slot_tags.id => { ...tag data... },
  47   *          quiz_slot_tags.id => { ...tag data... },
  48   *      ],
  49   *      2 => [
  50   *          quiz_slot_tags.id => { ...tag data... },
  51   *      ],
  52   *      3 => [],
  53   * ]
  54   *
  55   * @param int[] $slotids The list of id for the quiz slots.
  56   * @return array[] List of quiz_slot_tags records indexed by slot id.
  57   * @deprecated since Moodle 4.0
  58   * @todo Final deprecation on Moodle 4.4 MDL-72438
  59   */
  60  function quiz_retrieve_tags_for_slot_ids($slotids) {
  61      debugging('Method quiz_retrieve_tags_for_slot_ids() is deprecated, ' .
  62          'see filtercondition->tags from the question_set_reference table.', DEBUG_DEVELOPER);
  63      global $DB;
  64      if (empty($slotids)) {
  65          return [];
  66      }
  67  
  68      $slottags = $DB->get_records_list('quiz_slot_tags', 'slotid', $slotids);
  69      $tagsbyid = core_tag_tag::get_bulk(array_filter(array_column($slottags, 'tagid')), 'id, name');
  70      $tagsbyname = false; // It will be loaded later if required.
  71      $emptytagids = array_reduce($slotids, function($carry, $slotid) {
  72          $carry[$slotid] = [];
  73          return $carry;
  74      }, []);
  75  
  76      return array_reduce(
  77          $slottags,
  78          function($carry, $slottag) use ($slottags, $tagsbyid, $tagsbyname) {
  79              if (isset($tagsbyid[$slottag->tagid])) {
  80                  // Make sure that we're returning the most updated tag name.
  81                  $slottag->tagname = $tagsbyid[$slottag->tagid]->name;
  82              } else {
  83                  if ($tagsbyname === false) {
  84                      // We were hoping that this query could be avoided, but life
  85                      // showed its other side to us!
  86                      $tagcollid = core_tag_area::get_collection('core', 'question');
  87                      $tagsbyname = core_tag_tag::get_by_name_bulk(
  88                          $tagcollid,
  89                          array_column($slottags, 'tagname'),
  90                          'id, name'
  91                      );
  92                  }
  93                  if (isset($tagsbyname[$slottag->tagname])) {
  94                      // Make sure that we're returning the current tag id that matches
  95                      // the given tag name.
  96                      $slottag->tagid = $tagsbyname[$slottag->tagname]->id;
  97                  } else {
  98                      // The tag does not exist anymore (neither the tag id nor the tag name
  99                      // matches an existing tag).
 100                      // We still need to include this row in the result as some callers might
 101                      // be interested in these rows. An example is the editing forms that still
 102                      // need to display tag names even if they don't exist anymore.
 103                      $slottag->tagid = null;
 104                  }
 105              }
 106  
 107              $carry[$slottag->slotid][$slottag->id] = $slottag;
 108              return $carry;
 109          },
 110          $emptytagids
 111      );
 112  }
 113  
 114  /**
 115   * Verify that the question exists, and the user has permission to use it.
 116   *
 117   * @deprecated in 4.1 use mod_quiz\structure::has_use_capability(...) instead.
 118   *
 119   * @param stdClass $quiz the quiz settings.
 120   * @param int $slot which question in the quiz to test.
 121   * @return bool whether the user can use this question.
 122   */
 123  function quiz_has_question_use($quiz, $slot) {
 124      global $DB;
 125  
 126      debugging('Deprecated. Please use mod_quiz\structure::has_use_capability instead.');
 127  
 128      $sql = 'SELECT q.*
 129                FROM {quiz_slots} slot
 130                JOIN {question_references} qre ON qre.itemid = slot.id
 131                JOIN {question_bank_entries} qbe ON qbe.id = qre.questionbankentryid
 132                JOIN {question_versions} qve ON qve.questionbankentryid = qbe.id
 133                JOIN {question} q ON q.id = qve.questionid
 134               WHERE slot.quizid = ?
 135                 AND slot.slot = ?
 136                 AND qre.component = ?
 137                 AND qre.questionarea = ?';
 138  
 139      $question = $DB->get_record_sql($sql, [$quiz->id, $slot, 'mod_quiz', 'slot']);
 140  
 141      if (!$question) {
 142          return false;
 143      }
 144      return question_has_capability_on($question, 'use');
 145  }
 146  
 147  /**
 148   * @copyright 2012 the Open University
 149   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 150   * @deprecated since Moodle 4.2. Code moved to mod_quiz\task\update_overdue_attempts.
 151   * @todo MDL-76612 Final deprecation in Moodle 4.6
 152   */
 153  class mod_quiz_overdue_attempt_updater {
 154  
 155      /**
 156       * @deprecated since Moodle 4.2. Code moved to mod_quiz\task\update_overdue_attempts. that was.
 157       */
 158      public function update_overdue_attempts($timenow, $processto) {
 159          debugging('mod_quiz_overdue_attempt_updater has been deprecated. The code wsa moved to ' .
 160                  'mod_quiz\task\update_overdue_attempts.');
 161          return (new update_overdue_attempts())->update_all_overdue_attempts((int) $timenow, (int) $processto);
 162      }
 163  
 164      /**
 165       * @deprecated since Moodle 4.2. Code moved to mod_quiz\task\update_overdue_attempts.
 166       */
 167      public function get_list_of_overdue_attempts($processto) {
 168          debugging('mod_quiz_overdue_attempt_updater has been deprecated. The code wsa moved to ' .
 169                  'mod_quiz\task\update_overdue_attempts.');
 170          return (new update_overdue_attempts())->get_list_of_overdue_attempts((int) $processto);
 171      }
 172  }
 173  
 174  /**
 175   * Class for quiz exceptions. Just saves a couple of arguments on the
 176   * constructor for a moodle_exception.
 177   *
 178   * @copyright 2008 Tim Hunt
 179   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 180   * @since     Moodle 2.0
 181   * @deprecated since Moodle 4.2. Please just use moodle_exception.
 182   * @todo MDL-76612 Final deprecation in Moodle 4.6
 183   */
 184  class moodle_quiz_exception extends moodle_exception {
 185      /**
 186       * Constructor.
 187       *
 188       * @param quiz_settings $quizobj the quiz the error relates to.
 189       * @param string $errorcode The name of the string from error.php to print.
 190       * @param mixed $a Extra words and phrases that might be required in the error string.
 191       * @param string $link The url where the user will be prompted to continue.
 192       *      If no url is provided the user will be directed to the site index page.
 193       * @param string|null $debuginfo optional debugging information.
 194       * @deprecated since Moodle 4.2. Please just use moodle_exception.
 195       */
 196      public function __construct($quizobj, $errorcode, $a = null, $link = '', $debuginfo = null) {
 197          debugging('Class moodle_quiz_exception is deprecated. ' .
 198                  'Please use a standard moodle_exception instead.', DEBUG_DEVELOPER);
 199          if (!$link) {
 200              $link = $quizobj->view_url();
 201          }
 202          parent::__construct($errorcode, 'quiz', $link, $a, $debuginfo);
 203      }
 204  }
 205  
 206  /**
 207   * Update the sumgrades field of the quiz. This needs to be called whenever
 208   * the grading structure of the quiz is changed. For example if a question is
 209   * added or removed, or a question weight is changed.
 210   *
 211   * You should call {@see quiz_delete_previews()} before you call this function.
 212   *
 213   * @param stdClass $quiz a quiz.
 214   * @deprecated since Moodle 4.2. Please use grade_calculator::recompute_quiz_sumgrades.
 215   * @todo MDL-76612 Final deprecation in Moodle 4.6
 216   */
 217  function quiz_update_sumgrades($quiz) {
 218      debugging('quiz_update_sumgrades is deprecated. ' .
 219          'Please use a standard grade_calculator::recompute_quiz_sumgrades instead.', DEBUG_DEVELOPER);
 220      quiz_settings::create($quiz->id)->get_grade_calculator()->recompute_quiz_sumgrades();
 221  }
 222  
 223  /**
 224   * Update the sumgrades field of the attempts at a quiz.
 225   *
 226   * @param stdClass $quiz a quiz.
 227   * @deprecated since Moodle 4.2. Please use grade_calculator::recompute_all_attempt_sumgrades.
 228   * @todo MDL-76612 Final deprecation in Moodle 4.6
 229   */
 230  function quiz_update_all_attempt_sumgrades($quiz) {
 231      debugging('quiz_update_all_attempt_sumgrades is deprecated. ' .
 232          'Please use a standard grade_calculator::recompute_all_attempt_sumgrades instead.', DEBUG_DEVELOPER);
 233      quiz_settings::create($quiz->id)->get_grade_calculator()->recompute_all_attempt_sumgrades();
 234  }
 235  
 236  /**
 237   * Update the final grade at this quiz for all students.
 238   *
 239   * This function is equivalent to calling quiz_save_best_grade for all
 240   * users, but much more efficient.
 241   *
 242   * @param stdClass $quiz the quiz settings.
 243   * @deprecated since Moodle 4.2. Please use grade_calculator::recompute_all_final_grades.
 244   * @todo MDL-76612 Final deprecation in Moodle 4.6
 245   */
 246  function quiz_update_all_final_grades($quiz) {
 247      debugging('quiz_update_all_final_grades is deprecated. ' .
 248          'Please use a standard grade_calculator::recompute_all_final_grades instead.', DEBUG_DEVELOPER);
 249      quiz_settings::create($quiz->id)->get_grade_calculator()->recompute_all_final_grades();
 250  }
 251  
 252  /**
 253   * The quiz grade is the maximum that student's results are marked out of. When it
 254   * changes, the corresponding data in quiz_grades and quiz_feedback needs to be
 255   * rescaled. After calling this function, you probably need to call
 256   * quiz_update_all_attempt_sumgrades, grade_calculator::recompute_all_final_grades();
 257   * quiz_update_grades. (At least, that is what this comment has said for years, but
 258   * it seems to call recompute_all_final_grades itself.)
 259   *
 260   * @param float $newgrade the new maximum grade for the quiz.
 261   * @param stdClass $quiz the quiz we are updating. Passed by reference so its
 262   *      grade field can be updated too.
 263   * @return bool indicating success or failure.
 264   * @deprecated since Moodle 4.2. Please use grade_calculator::update_quiz_maximum_grade.
 265   * @todo MDL-76612 Final deprecation in Moodle 4.6
 266   */
 267  function quiz_set_grade($newgrade, $quiz) {
 268      debugging('quiz_set_grade is deprecated. ' .
 269          'Please use a standard grade_calculator::update_quiz_maximum_grade instead.', DEBUG_DEVELOPER);
 270      quiz_settings::create($quiz->id)->get_grade_calculator()->update_quiz_maximum_grade($newgrade);
 271      return true;
 272  }
 273  
 274  /**
 275   * Save the overall grade for a user at a quiz in the quiz_grades table
 276   *
 277   * @param stdClass $quiz The quiz for which the best grade is to be calculated and then saved.
 278   * @param int $userid The userid to calculate the grade for. Defaults to the current user.
 279   * @param array $attempts The attempts of this user. Useful if you are
 280   * looping through many users. Attempts can be fetched in one master query to
 281   * avoid repeated querying.
 282   * @return bool Indicates success or failure.
 283   * @deprecated since Moodle 4.2. Please use grade_calculator::update_quiz_maximum_grade.
 284   * @todo MDL-76612 Final deprecation in Moodle 4.6
 285   */
 286  function quiz_save_best_grade($quiz, $userid = null, $attempts = []) {
 287      debugging('quiz_save_best_grade is deprecated. ' .
 288          'Please use a standard grade_calculator::recompute_final_grade instead.', DEBUG_DEVELOPER);
 289      quiz_settings::create($quiz->id)->get_grade_calculator()->recompute_final_grade($userid, $attempts);
 290      return true;
 291  }
 292  
 293  /**
 294   * Calculate the overall grade for a quiz given a number of attempts by a particular user.
 295   *
 296   * @param stdClass $quiz    the quiz settings object.
 297   * @param array $attempts an array of all the user's attempts at this quiz in order.
 298   * @return float          the overall grade
 299   * @deprecated since Moodle 4.2. No direct replacement.
 300   * @todo MDL-76612 Final deprecation in Moodle 4.6
 301   */
 302  function quiz_calculate_best_grade($quiz, $attempts) {
 303      debugging('quiz_calculate_best_grade is deprecated with no direct replacement. It was only used ' .
 304          'in one place in the quiz code so this logic is now private to grade_calculator.', DEBUG_DEVELOPER);
 305  
 306      switch ($quiz->grademethod) {
 307  
 308          case QUIZ_ATTEMPTFIRST:
 309              $firstattempt = reset($attempts);
 310              return $firstattempt->sumgrades;
 311  
 312          case QUIZ_ATTEMPTLAST:
 313              $lastattempt = end($attempts);
 314              return $lastattempt->sumgrades;
 315  
 316          case QUIZ_GRADEAVERAGE:
 317              $sum = 0;
 318              $count = 0;
 319              foreach ($attempts as $attempt) {
 320                  if (!is_null($attempt->sumgrades)) {
 321                      $sum += $attempt->sumgrades;
 322                      $count++;
 323                  }
 324              }
 325              if ($count == 0) {
 326                  return null;
 327              }
 328              return $sum / $count;
 329  
 330          case QUIZ_GRADEHIGHEST:
 331          default:
 332              $max = null;
 333              foreach ($attempts as $attempt) {
 334                  if ($attempt->sumgrades > $max) {
 335                      $max = $attempt->sumgrades;
 336                  }
 337              }
 338              return $max;
 339      }
 340  }
 341  
 342  /**
 343   * Return the attempt with the best grade for a quiz
 344   *
 345   * Which attempt is the best depends on $quiz->grademethod. If the grade
 346   * method is GRADEAVERAGE then this function simply returns the last attempt.
 347   * @return stdClass         The attempt with the best grade
 348   * @param stdClass $quiz    The quiz for which the best grade is to be calculated
 349   * @param array $attempts An array of all the attempts of the user at the quiz
 350   * @deprecated since Moodle 4.2. No direct replacement.
 351   * @todo MDL-76612 Final deprecation in Moodle 4.6
 352   */
 353  function quiz_calculate_best_attempt($quiz, $attempts) {
 354      debugging('quiz_calculate_best_attempt is deprecated with no direct replacement. ' .
 355          'It was not used anywhere!', DEBUG_DEVELOPER);
 356  
 357      switch ($quiz->grademethod) {
 358  
 359          case QUIZ_ATTEMPTFIRST:
 360              foreach ($attempts as $attempt) {
 361                  return $attempt;
 362              }
 363              break;
 364  
 365          case QUIZ_GRADEAVERAGE: // We need to do something with it.
 366          case QUIZ_ATTEMPTLAST:
 367              foreach ($attempts as $attempt) {
 368                  $final = $attempt;
 369              }
 370              return $final;
 371  
 372          default:
 373          case QUIZ_GRADEHIGHEST:
 374              $max = -1;
 375              foreach ($attempts as $attempt) {
 376                  if ($attempt->sumgrades > $max) {
 377                      $max = $attempt->sumgrades;
 378                      $maxattempt = $attempt;
 379                  }
 380              }
 381              return $maxattempt;
 382      }
 383  }