]> git.mjollnir.org Git - moodle.git/commitdiff
MDL-6269, MDL-8958, MDL-8990 - Major fix to do with each attempt builds on last:
authortjhunt <tjhunt>
Thu, 29 Mar 2007 16:36:16 +0000 (16:36 +0000)
committertjhunt <tjhunt>
Thu, 29 Mar 2007 16:36:16 +0000 (16:36 +0000)
It used not to work with random questions, and there were problems with the computation of the grade, and regrading. Fix thanks to Paulo Matos, who not only fixed the bug and tested it, but was also incredibly patient waiting for me to have time to commit the changes to CVS.

Merged from MOODLE_17_STABLE.

lib/questionlib.php
mod/quiz/attempt.php

index f641d8191b662ab9efc8608548b0f2ba6ed4b766..008373659ec1d5c55d1abda9488b9d3206c2e01c 100644 (file)
@@ -635,7 +635,7 @@ function get_question_options(&$questions) {
 * @param object $attempt  The attempt for which the question sessions are
 *                         to be restored or created.
 */
-function get_question_states(&$questions, $cmoptions, $attempt) {
+function get_question_states(&$questions, $cmoptions, $attempt, $lastattemptid=null) {
     global $CFG, $QTYPES;
 
     // get the question ids
@@ -674,8 +674,33 @@ function get_question_states(&$questions, $cmoptions, $attempt) {
                 $states[$i]->last_graded = clone($states[$i]);
             }
         } else {
-            // create a new empty state
-            $states[$i] = new object;
+            // If the new attempt is to be based on a previous attempt get it and clean things
+            // Having lastattemptid filled implies that (should we double check?):
+            //    $attempt->attempt > 1 and $cmoptions->attemptonlast and !$attempt->preview
+            if ($lastattemptid) {
+                // find the responses from the previous attempt and save them to the new session
+
+                // Load the last graded state for the question
+                $statefields = 'n.questionid as question, s.*, n.sumpenalty';
+                $sql = "SELECT $statefields".
+                       "  FROM {$CFG->prefix}question_states s,".
+                       "       {$CFG->prefix}question_sessions n".
+                       " WHERE s.id = n.newgraded".
+                       "   AND n.attemptid = '$lastattemptid'".
+                       "   AND n.questionid = '$i'";
+                if (!$laststate = get_record_sql($sql)) {
+                    // Only restore previous responses that have been graded
+                    continue;
+                }
+                // Restore the state so that the responses will be restored
+                restore_question_state($questions[$i], $laststate);
+                $states[$i] = clone ($laststate);
+            } else {
+               // create a new empty state
+               $states[$i] = new object;
+            }
+
+            // now fill/overide initial values
             $states[$i]->attempt = $attempt->uniqueid;
             $states[$i]->question = (int) $i;
             $states[$i]->seq_number = 0;
@@ -686,15 +711,36 @@ function get_question_states(&$questions, $cmoptions, $attempt) {
             $states[$i]->penalty = 0;
             $states[$i]->sumpenalty = 0;
             $states[$i]->manualcomment = '';
-            $states[$i]->responses = array('' => '');
+
+            // if building on last attempt we want to preserve responses  
+            if (!$lastattemptid) {
+              $states[$i]->responses = array('' => '');
+            }
             // Prevent further changes to the session from incrementing the
             // sequence number
             $states[$i]->changed = true;
 
-            // Create the empty question type specific information
-            if (!$QTYPES[$questions[$i]->qtype]->create_session_and_responses(
-                    $questions[$i], $states[$i], $cmoptions, $attempt)) {
-                return false;
+            if ($lastattemptid) {
+                // prepare the previous responses for new processing
+                $action = new stdClass;
+                $action->responses = $laststate->responses;
+                $action->timestamp = $laststate->timestamp;
+                $action->event = QUESTION_EVENTSAVE; //emulate save of questions from all pages MDL-7631
+
+                // Process these responses ...
+                question_process_responses($questions[$i], $states[$i], $action, $cmoptions, $attempt);
+
+                // Fix for Bug #5506: When each attempt is built on the last one,
+                // preserve the options from any previous attempt. 
+                if ( isset($laststate->options) ) {
+                    $states[$i]->options = $laststate->options;
+                }
+            } else {
+                // Create the empty question type specific information
+                if (!$QTYPES[$questions[$i]->qtype]->create_session_and_responses(
+                        $questions[$i], $states[$i], $cmoptions, $attempt)) {
+                    return false;
+                }
             }
             $states[$i]->last_graded = clone($states[$i]);
         }
index 26c22e9f3e035fbd94767c7d5a7fe7d3cfb9ade9..7ed0978b6a2f0c44f0dc86a11b27839fccf8591f 100644 (file)
         error('Could not load question options');
     }
 
+    // If the new attempt is to be based on a previous attempt find its id 
+    if ($newattempt and $attempt->attempt > 1 and $quiz->attemptonlast and !$attempt->preview) {
+        // Find the previous attempt
+        if (!$lastattemptid = get_field('quiz_attempts', 'uniqueid', 'quiz', $attempt->quiz, 'userid', $attempt->userid, 'attempt', $attempt->attempt-1)) {
+            error('Could not find previous attempt to build on');
+        }
+    }
+
     // Restore the question sessions to their most recent states
     // creating new sessions where required
-    if (!$states = get_question_states($questions, $quiz, $attempt)) {
+    if (!$states = get_question_states($questions, $quiz, $attempt, $lastattemptid)) {
         error('Could not restore question sessions');
     }
 
         }
     }
 
-    // If the new attempt is to be based on a previous attempt copy responses over
-    if ($newattempt and $attempt->attempt > 1 and $quiz->attemptonlast and !$attempt->preview) {
-        // Find the previous attempt
-        if (!$lastattemptid = get_field('quiz_attempts', 'uniqueid', 'quiz', $attempt->quiz, 'userid', $attempt->userid, 'attempt', $attempt->attempt-1)) {
-            error('Could not find previous attempt to build on');
-        }
-        // For each question find the responses from the previous attempt and save them to the new session
-        foreach ($questions as $i => $question) {
-            // Load the last graded state for the question
-            $statefields = 'n.questionid as question, s.*, n.sumpenalty';
-            $sql = "SELECT $statefields".
-                   "  FROM {$CFG->prefix}question_states s,".
-                   "       {$CFG->prefix}question_sessions n".
-                   " WHERE s.id = n.newgraded".
-                   "   AND n.attemptid = '$lastattemptid'".
-                   "   AND n.questionid = '$i'";
-            if (!$laststate = get_record_sql($sql)) {
-                // Only restore previous responses that have been graded
-                continue;
-            }
-            // Restore the state so that the responses will be restored
-            restore_question_state($questions[$i], $laststate);
-            // prepare the previous responses for new processing
-            $action = new stdClass;
-            $action->responses = $laststate->responses;
-            $action->timestamp = $laststate->timestamp;
-            $action->event = QUESTION_EVENTSAVE; //emulate save of questions from all pages MDL-7631
-
-            // Process these responses ...
-            question_process_responses($questions[$i], $states[$i], $action, $quiz, $attempt);
-
-            // Fix for Bug #5506: When each attempt is built on the last one,
-            // preserve the options from any previous attempt. 
-            if ( isset($laststate->options) ) {
-                $states[$i]->options = $laststate->options;
-            }
-
-            // ... and save the new states
-            save_question_session($questions[$i], $states[$i]);
-        }
-    }
-
-
 /// Process form data /////////////////////////////////////////////////
 
     if ($responses = data_submitted() and empty($_POST['quizpassword'])) {