* @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
$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;
$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]);
}
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'])) {