From 98133a3eec62815619dfab5a2eff62058771b841 Mon Sep 17 00:00:00 2001 From: gustav_delius Date: Sun, 5 Jun 2005 13:22:03 +0000 Subject: [PATCH] Random questions now store both the wrapped question id and the response in the same state record, essentially going back to Julian's model. --- .../questiontypes/random/questiontype.php | 287 +++--------------- 1 file changed, 49 insertions(+), 238 deletions(-) diff --git a/mod/quiz/questiontypes/random/questiontype.php b/mod/quiz/questiontypes/random/questiontype.php index 334e12f08bf..0ce8bc1fdd5 100644 --- a/mod/quiz/questiontypes/random/questiontype.php +++ b/mod/quiz/questiontypes/random/questiontype.php @@ -7,13 +7,7 @@ /// QUESTION TYPE CLASS ////////////////// class quiz_random_qtype extends quiz_default_questiontype { - var $possiblerandomqtypes = array(SHORTANSWER, - NUMERICAL, - MULTICHOICE, - MATCH, - // RANDOMSAMATCH,// Can cause unexpected outcomes - TRUEFALSE, - MULTIANSWER); + var $excludedtypes = array(RANDOM, RANDOMSAMATCH); // Carries questions available as randoms sorted by category // This array is used when needed only @@ -52,8 +46,7 @@ class quiz_random_qtype extends quiz_default_questiontype { // Need to fetch random questions from category $question->category" // (Note: $this refers to the questiontype, not the question.) global $CFG; - $possiblerandomqtypes = "'" - . implode("','", $this->possiblerandomqtypes) . "'"; + $excludedtypes = implode(',', $this->excludedtypes); if ($question->questiontext == "1") { // recurse into subcategories $categorylist = quiz_categorylist($question->category); @@ -65,7 +58,7 @@ class quiz_random_qtype extends quiz_default_questiontype { WHERE category IN ($categorylist) AND parent = '0' AND id NOT IN ($quiz->questionsinuse) - AND qtype IN ($possiblerandomqtypes)"); + AND qtype NOT IN ($excludedtypes)"); $this->catrandoms[$question->category] = draw_rand_array($this->catrandoms[$question->category], count($this->catrandoms[$question->category])); // from bug 1889 @@ -80,13 +73,6 @@ class quiz_random_qtype extends quiz_default_questiontype { global $QUIZ_QTYPES; $QUIZ_QTYPES[$wrappedquestion->qtype] ->get_question_options($wrappedquestion); - - // Backup the original state of the random question - // And change the $state to match the wrapped question. This - // is sensible, because so the wrapped question's state gets - // put through all the generic processing. - $state->options->state = clone($state); - $state->question = $wrappedquestion->id; $QUIZ_QTYPES[$wrappedquestion->qtype] ->create_session_and_responses($wrappedquestion, $state, $quiz, $attempt); @@ -105,33 +91,45 @@ class quiz_random_qtype extends quiz_default_questiontype { } function restore_session_and_responses(&$question, &$state) { + /// The raw response records for random questions come in two flavours: + /// ---- 1 ---- + /// For responses stored by Moodle version 1.5 and later the answer + /// field has the pattern random#-* where the # part is the numeric + /// question id of the actual question shown in the quiz attempt + /// and * represents the student response to that actual question. + /// ---- 2 ---- + /// For responses stored by older Moodle versions - the answer field is + /// simply the question id of the actual question. The student response + /// to the actual question is stored in a separate response record. + /// ----------------------- + /// This means that prior to Moodle version 1.5, random questions needed + /// two response records for storing the response to a single question. + /// From version 1.5 and later the question type random works like all + /// the other question types in that it now only needs one response + /// record per question. global $QUIZ_QTYPES; - if(!$randomstate = get_record('quiz_states', 'question', - $question->id, 'attempt', $state->attempt)) { - return false; + if (!ereg('^random([0-9]+)-(.*)$', $state->responses[''], $answerregs)) { + // this must be an old-style state which stores only the id for the wrapped question + if (!$wrappedquestion = get_record('quiz_questions', 'id', $state->responses[''])) { + error("Can not find wrapped question $state->responses['']"); + } + // In the old model the actual response was stored in a separate entry in + // the state table + if (!$state->responses[''] = get_field('quiz_states', 'answer', 'attempt', $state->attempt, 'question', $wrappedquestion->id)) { + error("Wrapped state missing"); + } + } else { + if (!$wrappedquestion = get_record('quiz_questions', 'id', $answerregs[1])) { + return false; + } + $state->responses[''] = $answerregs[2]; } - if (!$wrappedquestion = get_record('quiz_questions', 'id', - $randomstate->answer)) { - return false; - } - $state->question = $wrappedquestion->id; - if (!$QUIZ_QTYPES[$wrappedquestion->qtype] ->get_question_options($wrappedquestion)) { return false; } - // We need to set responses[''] to whatever was saved in the most recent - // state of the wrapped question. - if(!$wrappedstates = get_records_select('quiz_states', - "question = $wrappedquestion->id AND attempt = $state->attempt", - 'seq_number DESC')) { - return false; - } - $wrappedstates = array_values($wrappedstates); - $state->responses = array('' => $wrappedstates[0]->answer); - if (!$QUIZ_QTYPES[$wrappedquestion->qtype] ->restore_session_and_responses($wrappedquestion, $state)) { return false; @@ -139,21 +137,12 @@ class quiz_random_qtype extends quiz_default_questiontype { $wrappedquestion->name_prefix = $question->name_prefix; $wrappedquestion->maxgrade = $question->maxgrade; $state->options->question = &$wrappedquestion; - $state->options->state = &$randomstate; return true; } function save_session_and_responses(&$question, &$state) { global $QUIZ_QTYPES; $wrappedquestion = &$state->options->question; - $randomstate = &$state->options->state; - - // We need to save the randomstate manually, because we can only process - // one response record automatically - if (empty($randomstate->id)) { - $randomstate->answer = $wrappedquestion->id; - $randomstate->id = insert_record('quiz_states', $randomstate); - } // Trick the wrapped question into pretending to be the random one. $realqid = $wrappedquestion->id; @@ -161,6 +150,21 @@ class quiz_random_qtype extends quiz_default_questiontype { $QUIZ_QTYPES[$wrappedquestion->qtype] ->save_session_and_responses($wrappedquestion, $state); + // Read what the wrapped question has just set the answer field to + // (if anything) + $response = get_field('quiz_states', 'answer', 'id', $state->id); + if(false === $response) { + return false; + } + + // Prefix the answer field... + $response = "random$realqid-$response"; + + // ... and save it again. + if (!set_field('quiz_states', 'answer', $response, 'id', $state->id)) { + return false; + } + // Restore the real id $wrappedquestion->id = $realqid; return true; @@ -196,34 +200,7 @@ class quiz_random_qtype extends quiz_default_questiontype { $QUIZ_QTYPES[$wrappedquestion->qtype] ->print_question($wrappedquestion, $state, $number, $quiz, $options); } -/* - function print_question_grading_details(&$question, &$state, $quiz, - $options) { - global $QUIZ_QTYPES; - $wrappedquestion = &$state->options->question; - $QUIZ_QTYPES[$wrappedquestion->qtype] - ->print_question_grading_details($wrappedquestion, $state, $quiz, - $options); - } - function print_question_formulation_and_controls(&$question, &$state, $quiz, - $options) { - global $QUIZ_QTYPES; - $wrappedquestion = &$state->options->question; - $QUIZ_QTYPES[$wrappedquestion->qtype] - ->print_question_formulation_and_controls($wrappedquestion, $state, - $quiz, $options); - } - - function print_question_submit_buttons(&$question, &$state, $quiz, - $options) { - global $QUIZ_QTYPES; - $wrappedquestion = &$state->options->question; - $QUIZ_QTYPES[$wrappedquestion->qtype] - ->print_question_submit_buttons($wrappedquestion, $state, $quiz, - $options); - } -*/ function grade_responses(&$question, &$state, $quiz) { global $QUIZ_QTYPES; $wrappedquestion = &$state->options->question; @@ -258,173 +235,7 @@ class quiz_random_qtype extends quiz_default_questiontype { return $QUIZ_QTYPES[$wrappedquestion->qtype] ->print_question_form_end($wrappedquestion, $state, $quizid); } -/* - function convert_to_response_answer_field($questionresponse) { - global $QUIZ_QTYPES; - foreach ($questionresponse as $key => $response) { - if (ereg('[^0-9][0-9]+random$', $key)) { - unset($questionresponse[$key]); - $randomquestion = get_record('quiz_questions', - 'id', $response); - return "random$response-" - .$QUIZ_QTYPES[$randomquestion->qtype] - ->convert_to_response_answer_field($questionresponse); - } - } - return ''; - } - - - - function create_response($question, $nameprefix, $questionsinuse) { - // It's for question types like RANDOMSAMATCH and RANDOM that - // the true power of the pattern with this function comes to the surface. - - - } - - -*/ - /* - function print_question_formulation_and_controls($question, - $quiz, $readonly, $answers, $correctanswers, $nameprefix) { - global $QUIZ_QTYPES; - - // Get the wrapped question... - if ($actualquestion = $this->get_wrapped_question($question, - $nameprefix)) { - echo ''; - return $QUIZ_QTYPES[$actualquestion->qtype] - ->print_question_formulation_and_controls($actualquestion, - $quiz, $readonly, $answers, $correctanswers, - quiz_qtype_nameprefix($actualquestion, $nameprefix)); - } else { - echo '

' . get_string('random', 'quiz') . '

'; - } - } - - - function get_wrapped_question($question, $nameprefix) { - if (!empty($question->response[$nameprefix]) - and $actualquestion = get_record('quiz_questions', - 'id', $question->response[$nameprefix])) { - $actualquestion->response = $question->response; - unset($actualquestion->response[$nameprefix]); - $actualquestion->maxgrade = $question->maxgrade; - return $actualquestion; - } else { - return false; - } - } - - function grade_response($question, $nameprefix) { - global $QUIZ_QTYPES; - - // Get the wrapped question... - if ($actualquestion = $this->get_wrapped_question($question, - $nameprefix)) { - return $QUIZ_QTYPES[$actualquestion->qtype]->grade_response( - $actualquestion, - quiz_qtype_nameprefix($actualquestion, $nameprefix)); - } else { - $result->grade = 0.0; - $result->answers = array(); - $result->correctanswers = array(); - return $result; - } - } - -*/ - - function extract_response($rawresponse, $nameprefix) { - global $QUIZ_QTYPES; - - /// The raw response records for random questions come in two flavours: - /// ---- 1 ---- - /// For responses stored by Moodle version 1.5 and later the answer - /// field has the pattern random#-* where the # part is the numeric - /// question id of the actual question shown in the quiz attempt - /// and * represents the student response to that actual question. - /// ---- 2 ---- - /// For responses stored by older Moodle versions - the answer field is - /// simply the question id of the actual question. The student response - /// to the actual question is stored in a separate response record. - /// ----------------------- - /// This means that prior to Moodle version 1.5, random questions needed - /// two response records for storing the response to a single question. - /// From version 1.5 and later the question type random works like all - /// the other question types in that it now only needs one response - /// record per question. - /// Because updating the old response records to fit the new response - /// record format could need hours of CPU time and the equivalent - /// amount of down time for the Moodle site and because a response - /// storage with two response formats for random question only effect - /// this function, where the response record is translated, this - /// function is now able to handle both types of response record. - - - // Pick random question id from the answer field in a way that - /// works for both formats: - if (!ereg('^(random)?([0-9]+)(-(.*))?$', $rawresponse->answer, $answerregs)) { - error("The answer value '$rawresponse->answer' for the response with " - ."id=$rawresponse->id to the random question " - ."$rawresponse->question is malformated." - ." - No response can be extracted!"); - } - $randomquestionid = $answerregs[2]; - - if ($randomquestion = get_record('quiz_questions', - 'id', $randomquestionid)) { - - if ($answerregs[1] && $answerregs[3]) { - // The raw response is formatted according to - // Moodle version 1.5 or later - $randomresponse = $rawresponse; - $randomresponse->question = $randomquestionid; - $randomresponse->answer = $answerregs[4]; - - } else if ($randomresponse = get_record - ('quiz_responses', 'question', $rawresponse->answer, - 'attempt', $rawresponse->attempt)) { - // The response was stored by an older version of Moodle - // :-) - - } else { - notify("Error: Cannot find response to random question $randomquestionid"); - unset($randomresponse); - } - - if (isset($randomresponse)) { - /// The prefered case: - /// There is a random question and a response field, from - /// which the response array can be extracted: - - - } else { - - /// Instead: workaround by creating a new response: - $response = $QUIZ_QTYPES[$randomquestion->qtype] - ->create_response($randomquestion, - quiz_qtype_nameprefix($randomquestion, $nameprefix), - "$rawresponse->question,$randomquestionid"); - // (That last argument is instead of $questionsinuse. - // It is not correct but it would be very messy to - // determine the correct value, while very few - // question types actually use it and they who do have - // good chances to execute properly anyway.) - } - $response[$nameprefix] = $randomquestionid; - //return $response; - return ''; - } else { - notify("Error: Unable to find random question $rawresponse->question"); - /// No new random question is picked as this is probably - /// not what the moodle user has in mind anyway - return array(); - } - } } //// END OF CLASS ////