MDL-53065 quiz redo question: avoid PHP notice in edge case
authorTim Hunt <T.J.Hunt@open.ac.uk>
Wed, 10 Feb 2016 19:22:17 +0000 (19:22 +0000)
committerTim Hunt <T.J.Hunt@open.ac.uk>
Fri, 19 Feb 2016 12:10:39 +0000 (12:10 +0000)
When selecting the variant of the new question, we need to add the
new question to the usage before trying to select a variant.

Also, we need to acutally use the selected variant number!

mod/quiz/attemptlib.php
question/classes/engine/variants/least_used_strategy.php

index ed1e9c5..a4a703a 100644 (file)
@@ -1789,6 +1789,7 @@ class quiz_attempt {
 
         $transaction = $DB->start_delegated_transaction();
 
+        // Choose the replacement question.
         $questiondata = $DB->get_record('question',
                 array('id' => $this->slots[$slot]->questionid));
         if ($questiondata->qtype != 'random') {
@@ -1803,7 +1804,11 @@ class quiz_attempt {
             }
         }
 
+        // Add the question to the usage. It is important we do this before we choose a variant.
         $newquestion = question_bank::load_question($newqusetionid);
+        $newslot = $this->quba->add_question_in_place_of_other($slot, $newquestion);
+
+        // Choose the variant.
         if ($newquestion->get_num_variants() == 1) {
             $variant = 1;
         } else {
@@ -1813,8 +1818,8 @@ class quiz_attempt {
                     $newquestion->get_variants_selection_seed());
         }
 
-        $newslot = $this->quba->add_question_in_place_of_other($slot, $newquestion);
-        $this->quba->start_question($slot);
+        // Start the question.
+        $this->quba->start_question($slot, $variant);
         $this->quba->set_max_mark($newslot, 0);
         $this->quba->set_question_attempt_metadata($newslot, 'originalslot', $slot);
         question_engine::save_questions_usage_by_activity($this->quba);
index 0772659..346174c 100644 (file)
@@ -90,6 +90,15 @@ class least_used_strategy implements \question_variant_selection_strategy {
             return $this->selectedvariant[$seed];
         }
 
+        // Catch a possible programming error, and make the problem clear.
+        if (!isset($this->variantsusecounts[$seed])) {
+            debugging('Variant requested for unknown seed ' . $seed . '. ' .
+                    'You must add all questions to the usage before creating the least_used_strategy. ' .
+                    'Continuing, but the variant choses may not actually be least used.',
+                    DEBUG_DEVELOPER);
+            $this->variantsusecounts[$seed] = array();
+        }
+
         if ($maxvariants > 2 * count($this->variantsusecounts[$seed])) {
             // Many many more variants exist than have been used so far.
             // It will be quicker to just pick until we miss a collision.