Differences Between: [Versions 311 and 402] [Versions 400 and 402] [Versions 401 and 402] [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 * Internal function used in quiz_get_completion_state. Check passing grade (or no attempts left) requirement for completion. 31 * 32 * @deprecated since Moodle 3.11 33 * @todo MDL-71196 Final deprecation in Moodle 4.3 34 * @see \mod_quiz\completion\custom_completion 35 * @param stdClass $course 36 * @param cm_info|stdClass $cm 37 * @param int $userid 38 * @param stdClass $quiz 39 * @return bool True if the passing grade (or no attempts left) requirement is disabled or met. 40 * @throws coding_exception 41 */ 42 function quiz_completion_check_passing_grade_or_all_attempts($course, $cm, $userid, $quiz) { 43 global $CFG; 44 45 debugging('quiz_completion_check_passing_grade_or_all_attempts has been deprecated.', DEBUG_DEVELOPER); 46 47 if (!$cm->completionpassgrade) { 48 return true; 49 } 50 51 // Check for passing grade. 52 require_once($CFG->libdir . '/gradelib.php'); 53 $item = grade_item::fetch(['courseid' => $course->id, 'itemtype' => 'mod', 54 'itemmodule' => 'quiz', 'iteminstance' => $cm->instance, 'outcomeid' => null]); 55 if ($item) { 56 $grades = grade_grade::fetch_users_grades($item, [$userid], false); 57 if (!empty($grades[$userid]) && $grades[$userid]->is_passed($item)) { 58 return true; 59 } 60 } 61 62 // If a passing grade is required and exhausting all available attempts is not accepted for completion, 63 // then this quiz is not complete. 64 if (!$quiz->completionattemptsexhausted) { 65 return false; 66 } 67 68 // Check if all attempts are used up. 69 $attempts = quiz_get_user_attempts($quiz->id, $userid, 'finished', true); 70 if (!$attempts) { 71 return false; 72 } 73 $lastfinishedattempt = end($attempts); 74 $context = context_module::instance($cm->id); 75 $quizobj = quiz_settings::create($quiz->id, $userid); 76 $accessmanager = new access_manager($quizobj, time(), 77 has_capability('mod/quiz:ignoretimelimits', $context, $userid, false)); 78 79 return $accessmanager->is_finished(count($attempts), $lastfinishedattempt); 80 } 81 82 /** 83 * Internal function used in quiz_get_completion_state. Check minimum attempts requirement for completion. 84 * 85 * @deprecated since Moodle 3.11 86 * @todo MDL-71196 Final deprecation in Moodle 4.3 87 * @see \mod_quiz\completion\custom_completion 88 * @param int $userid 89 * @param stdClass $quiz 90 * @return bool True if minimum attempts requirement is disabled or met. 91 */ 92 function quiz_completion_check_min_attempts($userid, $quiz) { 93 94 debugging('quiz_completion_check_min_attempts has been deprecated.', DEBUG_DEVELOPER); 95 96 if (empty($quiz->completionminattempts)) { 97 return true; 98 } 99 100 // Check if the user has done enough attempts. 101 $attempts = quiz_get_user_attempts($quiz->id, $userid, 'finished', true); 102 return $quiz->completionminattempts <= count($attempts); 103 } 104 105 /** 106 * Obtains the automatic completion state for this quiz on any conditions 107 * in quiz settings, such as if all attempts are used or a certain grade is achieved. 108 * 109 * @deprecated since Moodle 3.11 110 * @todo MDL-71196 Final deprecation in Moodle 4.3 111 * @see \mod_quiz\completion\custom_completion 112 * @param stdClass $course Course 113 * @param cm_info|stdClass $cm Course-module 114 * @param int $userid User ID 115 * @param bool $type Type of comparison (or/and; can be used as return value if no conditions) 116 * @return bool True if completed, false if not. (If no conditions, then return 117 * value depends on comparison type) 118 */ 119 function quiz_get_completion_state($course, $cm, $userid, $type) { 120 global $DB; 121 122 // No need to call debugging here. Deprecation debugging notice already being called in \completion_info::internal_get_state(). 123 124 $quiz = $DB->get_record('quiz', ['id' => $cm->instance], '*', MUST_EXIST); 125 if (!$quiz->completionattemptsexhausted && !$cm->completionpassgrade && !$quiz->completionminattempts) { 126 return $type; 127 } 128 129 if (!quiz_completion_check_passing_grade_or_all_attempts($course, $cm, $userid, $quiz)) { 130 return false; 131 } 132 133 if (!quiz_completion_check_min_attempts($userid, $quiz)) { 134 return false; 135 } 136 137 return true; 138 } 139 140 /** 141 * Retrieves tag information for the given list of quiz slot ids. 142 * Currently the only slots that have tags are random question slots. 143 * 144 * Example: 145 * If we have 3 slots with id 1, 2, and 3. The first slot has two tags, the second 146 * has one tag, and the third has zero tags. The return structure will look like: 147 * [ 148 * 1 => [ 149 * quiz_slot_tags.id => { ...tag data... }, 150 * quiz_slot_tags.id => { ...tag data... }, 151 * ], 152 * 2 => [ 153 * quiz_slot_tags.id => { ...tag data... }, 154 * ], 155 * 3 => [], 156 * ] 157 * 158 * @param int[] $slotids The list of id for the quiz slots. 159 * @return array[] List of quiz_slot_tags records indexed by slot id. 160 * @deprecated since Moodle 4.0 161 * @todo Final deprecation on Moodle 4.4 MDL-72438 162 */ 163 function quiz_retrieve_tags_for_slot_ids($slotids) { 164 debugging('Method quiz_retrieve_tags_for_slot_ids() is deprecated, ' . 165 'see filtercondition->tags from the question_set_reference table.', DEBUG_DEVELOPER); 166 global $DB; 167 if (empty($slotids)) { 168 return []; 169 } 170 171 $slottags = $DB->get_records_list('quiz_slot_tags', 'slotid', $slotids); 172 $tagsbyid = core_tag_tag::get_bulk(array_filter(array_column($slottags, 'tagid')), 'id, name'); 173 $tagsbyname = false; // It will be loaded later if required. 174 $emptytagids = array_reduce($slotids, function($carry, $slotid) { 175 $carry[$slotid] = []; 176 return $carry; 177 }, []); 178 179 return array_reduce( 180 $slottags, 181 function($carry, $slottag) use ($slottags, $tagsbyid, $tagsbyname) { 182 if (isset($tagsbyid[$slottag->tagid])) { 183 // Make sure that we're returning the most updated tag name. 184 $slottag->tagname = $tagsbyid[$slottag->tagid]->name; 185 } else { 186 if ($tagsbyname === false) { 187 // We were hoping that this query could be avoided, but life 188 // showed its other side to us! 189 $tagcollid = core_tag_area::get_collection('core', 'question'); 190 $tagsbyname = core_tag_tag::get_by_name_bulk( 191 $tagcollid, 192 array_column($slottags, 'tagname'), 193 'id, name' 194 ); 195 } 196 if (isset($tagsbyname[$slottag->tagname])) { 197 // Make sure that we're returning the current tag id that matches 198 // the given tag name. 199 $slottag->tagid = $tagsbyname[$slottag->tagname]->id; 200 } else { 201 // The tag does not exist anymore (neither the tag id nor the tag name 202 // matches an existing tag). 203 // We still need to include this row in the result as some callers might 204 // be interested in these rows. An example is the editing forms that still 205 // need to display tag names even if they don't exist anymore. 206 $slottag->tagid = null; 207 } 208 } 209 210 $carry[$slottag->slotid][$slottag->id] = $slottag; 211 return $carry; 212 }, 213 $emptytagids 214 ); 215 } 216 217 /** 218 * Verify that the question exists, and the user has permission to use it. 219 * 220 * @deprecated in 4.1 use mod_quiz\structure::has_use_capability(...) instead. 221 * 222 * @param stdClass $quiz the quiz settings. 223 * @param int $slot which question in the quiz to test. 224 * @return bool whether the user can use this question. 225 */ 226 function quiz_has_question_use($quiz, $slot) { 227 global $DB; 228 229 debugging('Deprecated. Please use mod_quiz\structure::has_use_capability instead.'); 230 231 $sql = 'SELECT q.* 232 FROM {quiz_slots} slot 233 JOIN {question_references} qre ON qre.itemid = slot.id 234 JOIN {question_bank_entries} qbe ON qbe.id = qre.questionbankentryid 235 JOIN {question_versions} qve ON qve.questionbankentryid = qbe.id 236 JOIN {question} q ON q.id = qve.questionid 237 WHERE slot.quizid = ? 238 AND slot.slot = ? 239 AND qre.component = ? 240 AND qre.questionarea = ?'; 241 242 $question = $DB->get_record_sql($sql, [$quiz->id, $slot, 'mod_quiz', 'slot']); 243 244 if (!$question) { 245 return false; 246 } 247 return question_has_capability_on($question, 'use'); 248 } 249 250 /** 251 * @copyright 2012 the Open University 252 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 253 * @deprecated since Moodle 4.2. Code moved to mod_quiz\task\update_overdue_attempts. 254 * @todo MDL-76612 Final deprecation in Moodle 4.6 255 */ 256 class mod_quiz_overdue_attempt_updater { 257 258 /** 259 * @deprecated since Moodle 4.2. Code moved to mod_quiz\task\update_overdue_attempts. that was. 260 */ 261 public function update_overdue_attempts($timenow, $processto) { 262 debugging('mod_quiz_overdue_attempt_updater has been deprecated. The code wsa moved to ' . 263 'mod_quiz\task\update_overdue_attempts.'); 264 return (new update_overdue_attempts())->update_all_overdue_attempts((int) $timenow, (int) $processto); 265 } 266 267 /** 268 * @deprecated since Moodle 4.2. Code moved to mod_quiz\task\update_overdue_attempts. 269 */ 270 public function get_list_of_overdue_attempts($processto) { 271 debugging('mod_quiz_overdue_attempt_updater has been deprecated. The code wsa moved to ' . 272 'mod_quiz\task\update_overdue_attempts.'); 273 return (new update_overdue_attempts())->get_list_of_overdue_attempts((int) $processto); 274 } 275 } 276 277 /** 278 * Class for quiz exceptions. Just saves a couple of arguments on the 279 * constructor for a moodle_exception. 280 * 281 * @copyright 2008 Tim Hunt 282 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 283 * @since Moodle 2.0 284 * @deprecated since Moodle 4.2. Please just use moodle_exception. 285 * @todo MDL-76612 Final deprecation in Moodle 4.6 286 */ 287 class moodle_quiz_exception extends moodle_exception { 288 /** 289 * Constructor. 290 * 291 * @param quiz_settings $quizobj the quiz the error relates to. 292 * @param string $errorcode The name of the string from error.php to print. 293 * @param mixed $a Extra words and phrases that might be required in the error string. 294 * @param string $link The url where the user will be prompted to continue. 295 * If no url is provided the user will be directed to the site index page. 296 * @param string|null $debuginfo optional debugging information. 297 * @deprecated since Moodle 4.2. Please just use moodle_exception. 298 */ 299 public function __construct($quizobj, $errorcode, $a = null, $link = '', $debuginfo = null) { 300 debugging('Class moodle_quiz_exception is deprecated. ' . 301 'Please use a standard moodle_exception instead.', DEBUG_DEVELOPER); 302 if (!$link) { 303 $link = $quizobj->view_url(); 304 } 305 parent::__construct($errorcode, 'quiz', $link, $a, $debuginfo); 306 } 307 } 308 309 /** 310 * Update the sumgrades field of the quiz. This needs to be called whenever 311 * the grading structure of the quiz is changed. For example if a question is 312 * added or removed, or a question weight is changed. 313 * 314 * You should call {@see quiz_delete_previews()} before you call this function. 315 * 316 * @param stdClass $quiz a quiz. 317 * @deprecated since Moodle 4.2. Please use grade_calculator::recompute_quiz_sumgrades. 318 * @todo MDL-76612 Final deprecation in Moodle 4.6 319 */ 320 function quiz_update_sumgrades($quiz) { 321 debugging('quiz_update_sumgrades is deprecated. ' . 322 'Please use a standard grade_calculator::recompute_quiz_sumgrades instead.', DEBUG_DEVELOPER); 323 quiz_settings::create($quiz->id)->get_grade_calculator()->recompute_quiz_sumgrades(); 324 } 325 326 /** 327 * Update the sumgrades field of the attempts at a quiz. 328 * 329 * @param stdClass $quiz a quiz. 330 * @deprecated since Moodle 4.2. Please use grade_calculator::recompute_all_attempt_sumgrades. 331 * @todo MDL-76612 Final deprecation in Moodle 4.6 332 */ 333 function quiz_update_all_attempt_sumgrades($quiz) { 334 debugging('quiz_update_all_attempt_sumgrades is deprecated. ' . 335 'Please use a standard grade_calculator::recompute_all_attempt_sumgrades instead.', DEBUG_DEVELOPER); 336 quiz_settings::create($quiz->id)->get_grade_calculator()->recompute_all_attempt_sumgrades(); 337 } 338 339 /** 340 * Update the final grade at this quiz for all students. 341 * 342 * This function is equivalent to calling quiz_save_best_grade for all 343 * users, but much more efficient. 344 * 345 * @param stdClass $quiz the quiz settings. 346 * @deprecated since Moodle 4.2. Please use grade_calculator::recompute_all_final_grades. 347 * @todo MDL-76612 Final deprecation in Moodle 4.6 348 */ 349 function quiz_update_all_final_grades($quiz) { 350 debugging('quiz_update_all_final_grades is deprecated. ' . 351 'Please use a standard grade_calculator::recompute_all_final_grades instead.', DEBUG_DEVELOPER); 352 quiz_settings::create($quiz->id)->get_grade_calculator()->recompute_all_final_grades(); 353 } 354 355 /** 356 * The quiz grade is the maximum that student's results are marked out of. When it 357 * changes, the corresponding data in quiz_grades and quiz_feedback needs to be 358 * rescaled. After calling this function, you probably need to call 359 * quiz_update_all_attempt_sumgrades, grade_calculator::recompute_all_final_grades(); 360 * quiz_update_grades. (At least, that is what this comment has said for years, but 361 * it seems to call recompute_all_final_grades itself.) 362 * 363 * @param float $newgrade the new maximum grade for the quiz. 364 * @param stdClass $quiz the quiz we are updating. Passed by reference so its 365 * grade field can be updated too. 366 * @return bool indicating success or failure. 367 * @deprecated since Moodle 4.2. Please use grade_calculator::update_quiz_maximum_grade. 368 * @todo MDL-76612 Final deprecation in Moodle 4.6 369 */ 370 function quiz_set_grade($newgrade, $quiz) { 371 debugging('quiz_set_grade is deprecated. ' . 372 'Please use a standard grade_calculator::update_quiz_maximum_grade instead.', DEBUG_DEVELOPER); 373 quiz_settings::create($quiz->id)->get_grade_calculator()->update_quiz_maximum_grade($newgrade); 374 return true; 375 } 376 377 /** 378 * Save the overall grade for a user at a quiz in the quiz_grades table 379 * 380 * @param stdClass $quiz The quiz for which the best grade is to be calculated and then saved. 381 * @param int $userid The userid to calculate the grade for. Defaults to the current user. 382 * @param array $attempts The attempts of this user. Useful if you are 383 * looping through many users. Attempts can be fetched in one master query to 384 * avoid repeated querying. 385 * @return bool Indicates success or failure. 386 * @deprecated since Moodle 4.2. Please use grade_calculator::update_quiz_maximum_grade. 387 * @todo MDL-76612 Final deprecation in Moodle 4.6 388 */ 389 function quiz_save_best_grade($quiz, $userid = null, $attempts = []) { 390 debugging('quiz_save_best_grade is deprecated. ' . 391 'Please use a standard grade_calculator::recompute_final_grade instead.', DEBUG_DEVELOPER); 392 quiz_settings::create($quiz->id)->get_grade_calculator()->recompute_final_grade($userid, $attempts); 393 return true; 394 } 395 396 /** 397 * Calculate the overall grade for a quiz given a number of attempts by a particular user. 398 * 399 * @param stdClass $quiz the quiz settings object. 400 * @param array $attempts an array of all the user's attempts at this quiz in order. 401 * @return float the overall grade 402 * @deprecated since Moodle 4.2. No direct replacement. 403 * @todo MDL-76612 Final deprecation in Moodle 4.6 404 */ 405 function quiz_calculate_best_grade($quiz, $attempts) { 406 debugging('quiz_calculate_best_grade is deprecated with no direct replacement. It was only used ' . 407 'in one place in the quiz code so this logic is now private to grade_calculator.', DEBUG_DEVELOPER); 408 409 switch ($quiz->grademethod) { 410 411 case QUIZ_ATTEMPTFIRST: 412 $firstattempt = reset($attempts); 413 return $firstattempt->sumgrades; 414 415 case QUIZ_ATTEMPTLAST: 416 $lastattempt = end($attempts); 417 return $lastattempt->sumgrades; 418 419 case QUIZ_GRADEAVERAGE: 420 $sum = 0; 421 $count = 0; 422 foreach ($attempts as $attempt) { 423 if (!is_null($attempt->sumgrades)) { 424 $sum += $attempt->sumgrades; 425 $count++; 426 } 427 } 428 if ($count == 0) { 429 return null; 430 } 431 return $sum / $count; 432 433 case QUIZ_GRADEHIGHEST: 434 default: 435 $max = null; 436 foreach ($attempts as $attempt) { 437 if ($attempt->sumgrades > $max) { 438 $max = $attempt->sumgrades; 439 } 440 } 441 return $max; 442 } 443 } 444 445 /** 446 * Return the attempt with the best grade for a quiz 447 * 448 * Which attempt is the best depends on $quiz->grademethod. If the grade 449 * method is GRADEAVERAGE then this function simply returns the last attempt. 450 * @return stdClass The attempt with the best grade 451 * @param stdClass $quiz The quiz for which the best grade is to be calculated 452 * @param array $attempts An array of all the attempts of the user at the quiz 453 * @deprecated since Moodle 4.2. No direct replacement. 454 * @todo MDL-76612 Final deprecation in Moodle 4.6 455 */ 456 function quiz_calculate_best_attempt($quiz, $attempts) { 457 debugging('quiz_calculate_best_attempt is deprecated with no direct replacement. ' . 458 'It was not used anywhere!', DEBUG_DEVELOPER); 459 460 switch ($quiz->grademethod) { 461 462 case QUIZ_ATTEMPTFIRST: 463 foreach ($attempts as $attempt) { 464 return $attempt; 465 } 466 break; 467 468 case QUIZ_GRADEAVERAGE: // We need to do something with it. 469 case QUIZ_ATTEMPTLAST: 470 foreach ($attempts as $attempt) { 471 $final = $attempt; 472 } 473 return $final; 474 475 default: 476 case QUIZ_GRADEHIGHEST: 477 $max = -1; 478 foreach ($attempts as $attempt) { 479 if ($attempt->sumgrades > $max) { 480 $max = $attempt->sumgrades; 481 $maxattempt = $attempt; 482 } 483 } 484 return $maxattempt; 485 } 486 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body