MDL-76897 quiz: quiz_set_grade -> update_quiz_maximum_grade
This commit is contained in:
@@ -18,6 +18,7 @@ namespace core_grades;
|
||||
|
||||
use grade_plugin_return;
|
||||
use grade_report_grader;
|
||||
use mod_quiz\quiz_settings;
|
||||
|
||||
defined('MOODLE_INTERNAL') || die();
|
||||
|
||||
@@ -478,8 +479,7 @@ class report_graderlib_test extends \advanced_testcase {
|
||||
|
||||
// Set the grade for the second one to 0 (note, you have to do this after creating it,
|
||||
// otherwise it doesn't create an ungraded grade item).
|
||||
$ungradedquiz->instance = $ungradedquiz->id;
|
||||
quiz_set_grade(0, $ungradedquiz);
|
||||
quiz_settings::create($ungradedquiz->id)->get_grade_calculator()->update_quiz_maximum_grade(0);
|
||||
|
||||
// Set current user.
|
||||
$this->setUser($manager);
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
namespace mod_quiz;
|
||||
|
||||
use mod_quiz\event\quiz_grade_updated;
|
||||
use question_engine_data_mapper;
|
||||
use stdClass;
|
||||
|
||||
/**
|
||||
* This class contains all the logic for computing the grade of a quiz.
|
||||
@@ -64,7 +66,7 @@ class grade_calculator {
|
||||
*
|
||||
* You should call {@see quiz_delete_previews()} before you call this function.
|
||||
*/
|
||||
public function recompute_quiz_sumgrades() {
|
||||
public function recompute_quiz_sumgrades(): void {
|
||||
global $DB;
|
||||
$quiz = $this->quizobj->get_quiz();
|
||||
|
||||
@@ -86,14 +88,14 @@ class grade_calculator {
|
||||
// If the quiz has been attempted, and the sumgrades has been
|
||||
// set to 0, then we must also set the maximum possible grade to 0, or
|
||||
// we will get a divide by zero error.
|
||||
quiz_set_grade(0, $quiz);
|
||||
self::update_quiz_maximum_grade(0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the sumgrades field of attempts at this quiz.
|
||||
*/
|
||||
public function recompute_all_attempt_sumgrades() {
|
||||
public function recompute_all_attempt_sumgrades(): void {
|
||||
global $DB;
|
||||
$dm = new question_engine_data_mapper();
|
||||
$timenow = time();
|
||||
@@ -260,4 +262,77 @@ class grade_calculator {
|
||||
array_merge([$quiz->id], $params));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the quiz setting for the grade the quiz is out of.
|
||||
*
|
||||
* This function will update the data in quiz_grades and quiz_feedback, and
|
||||
* pass the new grades on to the gradebook.
|
||||
*
|
||||
* @param float $newgrade the new maximum grade for the quiz.
|
||||
*/
|
||||
public function update_quiz_maximum_grade(float $newgrade): void {
|
||||
global $DB;
|
||||
$quiz = $this->quizobj->get_quiz();
|
||||
|
||||
// This is potentially expensive, so only do it if necessary.
|
||||
if (abs($quiz->grade - $newgrade) < self::ALMOST_ZERO) {
|
||||
// Nothing to do.
|
||||
return;
|
||||
}
|
||||
|
||||
// Use a transaction.
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
|
||||
// Update the quiz table.
|
||||
$oldgrade = $quiz->grade;
|
||||
$quiz->grade = $newgrade;
|
||||
$timemodified = time();
|
||||
$DB->update_record('quiz', (object) [
|
||||
'id' => $quiz->id,
|
||||
'grade' => $newgrade,
|
||||
'timemodified' => $timemodified,
|
||||
]);
|
||||
|
||||
// Rescale the grade of all quiz attempts.
|
||||
if ($oldgrade < $newgrade) {
|
||||
// The new total is bigger, so we need to recompute fully to avoid underflow problems.
|
||||
$this->recompute_all_final_grades();
|
||||
|
||||
} else {
|
||||
// New total smaller, so we can rescale the grades efficiently.
|
||||
$DB->execute("
|
||||
UPDATE {quiz_grades}
|
||||
SET grade = ? * grade, timemodified = ?
|
||||
WHERE quiz = ?
|
||||
", [$newgrade / $oldgrade, $timemodified, $quiz->id]);
|
||||
}
|
||||
|
||||
// Rescale the overall feedback boundaries.
|
||||
if ($oldgrade > self::ALMOST_ZERO) {
|
||||
// Update the quiz_feedback table.
|
||||
$factor = $newgrade / $oldgrade;
|
||||
$DB->execute("
|
||||
UPDATE {quiz_feedback}
|
||||
SET mingrade = ? * mingrade, maxgrade = ? * maxgrade
|
||||
WHERE quizid = ?
|
||||
", [$factor, $factor, $quiz->id]);
|
||||
}
|
||||
|
||||
// Update grade item and send all grades to gradebook.
|
||||
quiz_grade_item_update($quiz);
|
||||
quiz_update_grades($quiz);
|
||||
|
||||
// Log quiz grade updated event.
|
||||
quiz_grade_updated::create([
|
||||
'context' => $this->quizobj->get_context(),
|
||||
'objectid' => $quiz->id,
|
||||
'other' => [
|
||||
'oldgrade' => $oldgrade + 0, // Remove trailing 0s.
|
||||
'newgrade' => $newgrade,
|
||||
]
|
||||
])->trigger();
|
||||
|
||||
$transaction->allow_commit();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -351,3 +351,25 @@ function quiz_update_all_final_grades($quiz) {
|
||||
'Please use a standard grade_calculator::recompute_all_final_grades instead.', DEBUG_DEVELOPER);
|
||||
quiz_settings::create($quiz->id)->get_grade_calculator()->recompute_all_final_grades();
|
||||
}
|
||||
|
||||
/**
|
||||
* The quiz grade is the maximum that student's results are marked out of. When it
|
||||
* changes, the corresponding data in quiz_grades and quiz_feedback needs to be
|
||||
* rescaled. After calling this function, you probably need to call
|
||||
* quiz_update_all_attempt_sumgrades, grade_calculator::recompute_all_final_grades();
|
||||
* quiz_update_grades. (At least, that is what this comment has said for years, but
|
||||
* it seems to call recompute_all_final_grades itself.)
|
||||
*
|
||||
* @param float $newgrade the new maximum grade for the quiz.
|
||||
* @param stdClass $quiz the quiz we are updating. Passed by reference so its
|
||||
* grade field can be updated too.
|
||||
* @return bool indicating success or failure.
|
||||
* @deprecated since Moodle 4.2. Please use grade_calculator::update_quiz_maximum_grade.
|
||||
* @todo MDL-76612 Final deprecation in Moodle 4.6
|
||||
*/
|
||||
function quiz_set_grade($newgrade, $quiz) {
|
||||
debugging('quiz_set_grade is deprecated. ' .
|
||||
'Please use a standard grade_calculator::update_quiz_maximum_grade instead.', DEBUG_DEVELOPER);
|
||||
quiz_settings::create($quiz->id)->get_grade_calculator()->update_quiz_maximum_grade($newgrade);
|
||||
return true;
|
||||
}
|
||||
|
||||
+1
-3
@@ -150,9 +150,7 @@ if (optional_param('savechanges', false, PARAM_BOOL) && confirm_sesskey()) {
|
||||
// If rescaling is required save the new maximum.
|
||||
$maxgrade = unformat_float(optional_param('maxgrade', '', PARAM_RAW_TRIMMED), true);
|
||||
if (is_float($maxgrade) && $maxgrade >= 0) {
|
||||
quiz_set_grade($maxgrade, $quiz);
|
||||
$gradecalculator->recompute_all_final_grades();
|
||||
quiz_update_grades($quiz, 0, true);
|
||||
$gradecalculator->update_quiz_maximum_grade($maxgrade);
|
||||
}
|
||||
|
||||
redirect($afteractionurl);
|
||||
|
||||
@@ -629,83 +629,6 @@ function quiz_has_feedback($quiz) {
|
||||
return $cache[$quiz->id];
|
||||
}
|
||||
|
||||
/**
|
||||
* The quiz grade is the maximum that student's results are marked out of. When it
|
||||
* changes, the corresponding data in quiz_grades and quiz_feedback needs to be
|
||||
* rescaled. After calling this function, you probably need to call
|
||||
* quiz_update_all_attempt_sumgrades, grade_calculator::recompute_all_final_grades();
|
||||
* quiz_update_grades. (At least, that is what this comment has said for years, but
|
||||
* it seems to call recompute_all_final_grades itself.)
|
||||
*
|
||||
* @param float $newgrade the new maximum grade for the quiz.
|
||||
* @param stdClass $quiz the quiz we are updating. Passed by reference so its
|
||||
* grade field can be updated too.
|
||||
* @return bool indicating success or failure.
|
||||
*/
|
||||
function quiz_set_grade($newgrade, $quiz) {
|
||||
global $DB;
|
||||
// This is potentially expensive, so only do it if necessary.
|
||||
if (abs($quiz->grade - $newgrade) < 1e-7) {
|
||||
// Nothing to do.
|
||||
return true;
|
||||
}
|
||||
|
||||
$oldgrade = $quiz->grade;
|
||||
$quiz->grade = $newgrade;
|
||||
|
||||
// Use a transaction, so that on those databases that support it, this is safer.
|
||||
$transaction = $DB->start_delegated_transaction();
|
||||
|
||||
// Update the quiz table.
|
||||
$DB->set_field('quiz', 'grade', $newgrade, ['id' => $quiz->instance]);
|
||||
|
||||
if ($oldgrade < 1) {
|
||||
// If the old grade was zero, we cannot rescale, we have to recompute.
|
||||
// We also recompute if the old grade was too small to avoid underflow problems.
|
||||
$gradecalculator = quiz_settings::create($quiz->id)->get_grade_calculator();
|
||||
$gradecalculator->recompute_all_final_grades($quiz);
|
||||
|
||||
} else {
|
||||
// We can rescale the grades efficiently.
|
||||
$timemodified = time();
|
||||
$DB->execute("
|
||||
UPDATE {quiz_grades}
|
||||
SET grade = ? * grade, timemodified = ?
|
||||
WHERE quiz = ?
|
||||
", [$newgrade / $oldgrade, $timemodified, $quiz->id]);
|
||||
}
|
||||
|
||||
if ($oldgrade > 1e-7) {
|
||||
// Update the quiz_feedback table.
|
||||
$factor = $newgrade/$oldgrade;
|
||||
$DB->execute("
|
||||
UPDATE {quiz_feedback}
|
||||
SET mingrade = ? * mingrade, maxgrade = ? * maxgrade
|
||||
WHERE quizid = ?
|
||||
", [$factor, $factor, $quiz->id]);
|
||||
}
|
||||
|
||||
// Update grade item and send all grades to gradebook.
|
||||
quiz_grade_item_update($quiz);
|
||||
quiz_update_grades($quiz);
|
||||
|
||||
$transaction->allow_commit();
|
||||
|
||||
// Log quiz grade updated event.
|
||||
// We use $num + 0 as a trick to remove the useless 0 digits from decimals.
|
||||
$cm = get_coursemodule_from_instance('quiz', $quiz->id);
|
||||
$event = \mod_quiz\event\quiz_grade_updated::create([
|
||||
'context' => \context_module::instance($cm->id),
|
||||
'objectid' => $quiz->id,
|
||||
'other' => [
|
||||
'oldgrade' => $oldgrade + 0,
|
||||
'newgrade' => $newgrade + 0
|
||||
]
|
||||
]);
|
||||
$event->trigger();
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Save the overall grade for a user at a quiz in the quiz_grades table
|
||||
*
|
||||
|
||||
@@ -82,6 +82,7 @@ This files describes API changes in the quiz code.
|
||||
- quiz_update_sumgrades -> recompute_quiz_sumgrades
|
||||
- quiz_update_all_attempt_sumgrades -> recompute_all_attempt_sumgrades
|
||||
- quiz_update_all_final_grades -> recompute_all_final_grades
|
||||
- quiz_set_grade -> update_quiz_maximum_grade
|
||||
|
||||
* Final deprecation (complete removal) of the following functions which were deprecated long ago:
|
||||
- quiz_groups_member_added_handler - deprecated since 2.6
|
||||
|
||||
Reference in New Issue
Block a user