Random questions now store both the wrapped question id and the response in the same state record, essentially going back to Julian's model.

This commit is contained in:
gustav_delius
2005-06-05 13:22:03 +00:00
parent 52de50d2d5
commit 98133a3eec
+49 -238
View File
@@ -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 '<input type="hidden" name="' . $nameprefix
. '" value="' . $actualquestion->id . '" />';
return $QUIZ_QTYPES[$actualquestion->qtype]
->print_question_formulation_and_controls($actualquestion,
$quiz, $readonly, $answers, $correctanswers,
quiz_qtype_nameprefix($actualquestion, $nameprefix));
} else {
echo '<p>' . get_string('random', 'quiz') . '</p>';
}
}
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 ////