1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247
|
<?php // $Id: questiontype.php,v 1.4 2006/04/30 17:31:33 gustav_delius Exp $
//////////////
/// RANDOM ///
//////////////
/// QUESTION TYPE CLASS //////////////////
class random_qtype extends default_questiontype {
var $excludedtypes = array("'random'", "'randomsamatch'", "'essay'", "'description'");
// Carries questions available as randoms sorted by category
// This array is used when needed only
var $catrandoms = array();
function name() {
return 'random';
}
function get_question_options(&$question) {
// Don't do anything here, because the random question has no options.
// Everything is handled by the create- or restore_session_and_responses
// functions.
return true;
}
function save_question_options($question) {
// No options, but we use the parent field to hide random questions.
// To avoid problems we set the parent field to the question id.
return (set_field('question', 'parent', $question->id, 'id',
$question->id) ? true : false);
}
function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
// Choose a random question from the category:
// We need to make sure that no question is used more than once in the
// quiz. Therfore the following need to be excluded:
// 1. All questions that are explicitly assigned to the quiz
// 2. All random questions
// 3. All questions that are already chosen by an other random question
if (!isset($cmoptions->questionsinuse)) {
$cmoptions->questionsinuse = $attempt->layout;
}
if (!isset($this->catrandoms[$question->category][$question->questiontext])) {
// Need to fetch random questions from category $question->category"
// (Note: $this refers to the questiontype, not the question.)
global $CFG;
$excludedtypes = implode(',', $this->excludedtypes);
if ($question->questiontext == "1") {
// recurse into subcategories
$categorylist = question_categorylist($question->category);
} else {
$categorylist = $question->category;
}
if ($catrandoms = get_records_sql
("SELECT id,id FROM {$CFG->prefix}question
WHERE category IN ($categorylist)
AND parent = '0'
AND id NOT IN ($cmoptions->questionsinuse)
AND qtype NOT IN ($excludedtypes)")) {
$this->catrandoms[$question->category][$question->questiontext] =
draw_rand_array($catrandoms, count($catrandoms)); // from bug 1889
} else {
$this->catrandoms[$question->category][$question->questiontext] = array();
}
}
while ($wrappedquestion =
array_pop($this->catrandoms[$question->category][$question->questiontext])) {
if (!ereg("(^|,)$wrappedquestion->id(,|$)", $cmoptions->questionsinuse)) {
/// $randomquestion is not in use and will therefore be used
/// as the randomquestion here...
$wrappedquestion = get_record('question', 'id', $wrappedquestion->id);
global $QTYPES;
$QTYPES[$wrappedquestion->qtype]
->get_question_options($wrappedquestion);
$QTYPES[$wrappedquestion->qtype]
->create_session_and_responses($wrappedquestion,
$state, $cmoptions, $attempt);
$wrappedquestion->name_prefix = $question->name_prefix;
$wrappedquestion->maxgrade = $question->maxgrade;
$cmoptions->questionsinuse .= ",$wrappedquestion->id";
$state->options->question = &$wrappedquestion;
return true;
}
}
$question->questiontext = '<span class="notifyproblem">'.
get_string('toomanyrandom', 'quiz'). '</span>';
$question->qtype = 'description';
$state->responses = array('' => '');
return true;
}
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 $QTYPES;
if (!ereg('^random([0-9]+)-(.*)$', $state->responses[''], $answerregs)) {
if (empty($state->responses[''])) {
// This is the case if there weren't enough questions available in the category.
$question->questiontext = '<span class="notifyproblem">'.
get_string('toomanyrandom', 'quiz'). '</span>';
$question->qtype = 'description';
return true;
}
// this must be an old-style state which stores only the id for the wrapped question
if (!$wrappedquestion = get_record('question', 'id', $state->responses[''])) {
notify("Can not find wrapped question {$state->responses['']}");
}
// In the old model the actual response was stored in a separate entry in
// the state table and fortunately there was only a single state per question
if (!$state->responses[''] = get_field('question_states', 'answer', 'attempt', $state->attempt, 'question', $wrappedquestion->id)) {
notify("Wrapped state missing");
}
} else {
if (!$wrappedquestion = get_record('question', 'id', $answerregs[1])) {
// The teacher must have deleted this question by mistake
// Convert it into a description type question with an explanation to the student
$wrappedquestion = clone($question);
$wrappedquestion->id = $answerregs[1];
$wrappedquestion->questiontext = get_string('questiondeleted', 'quiz');
$wrappedquestion->qtype = 'missingtype';
}
$state->responses[''] = (false === $answerregs[2]) ? '' : $answerregs[2];
}
if (!$QTYPES[$wrappedquestion->qtype]
->get_question_options($wrappedquestion)) {
return false;
}
if (!$QTYPES[$wrappedquestion->qtype]
->restore_session_and_responses($wrappedquestion, $state)) {
return false;
}
$wrappedquestion->name_prefix = $question->name_prefix;
$wrappedquestion->maxgrade = $question->maxgrade;
$state->options->question = &$wrappedquestion;
return true;
}
function save_session_and_responses(&$question, &$state) {
global $QTYPES;
$wrappedquestion = &$state->options->question;
// Trick the wrapped question into pretending to be the random one.
$realqid = $wrappedquestion->id;
$wrappedquestion->id = $question->id;
$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('question_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('question_states', 'answer', addslashes($response), 'id', $state->id)) {
return false;
}
// Restore the real id
$wrappedquestion->id = $realqid;
return true;
}
function get_correct_responses(&$question, &$state) {
global $QTYPES;
$wrappedquestion = &$state->options->question;
return $QTYPES[$wrappedquestion->qtype]
->get_correct_responses($wrappedquestion, $state);
}
// ULPGC ecastro
function get_all_responses(&$question, &$state){
global $QTYPES;
$wrappedquestion = &$state->options->question;
return $QTYPES[$wrappedquestion->qtype]
->get_all_responses($wrappedquestion, $state);
}
// ULPGC ecastro
function get_actual_response(&$question, &$state){
global $QTYPES;
$wrappedquestion = &$state->options->question;
return $QTYPES[$wrappedquestion->qtype]
->get_actual_response($wrappedquestion, $state);
}
function print_question(&$question, &$state, &$number, $cmoptions, $options) {
global $QTYPES;
$wrappedquestion = &$state->options->question;
$QTYPES[$wrappedquestion->qtype]
->print_question($wrappedquestion, $state, $number, $cmoptions, $options);
}
function grade_responses(&$question, &$state, $cmoptions) {
global $QTYPES;
$wrappedquestion = &$state->options->question;
return $QTYPES[$wrappedquestion->qtype]
->grade_responses($wrappedquestion, $state, $cmoptions);
}
function get_texsource(&$question, &$state, $cmoptions, $type) {
global $QTYPES;
$wrappedquestion = &$state->options->question;
return $QTYPES[$wrappedquestion->qtype]
->get_texsource($wrappedquestion, $state, $cmoptions, $type);
}
function compare_responses(&$question, $state, $teststate) {
global $QTYPES;
$wrappedquestion = &$state->options->question;
return $QTYPES[$wrappedquestion->qtype]
->compare_responses($wrappedquestion, $state, $teststate);
}
}
//// END OF CLASS ////
//////////////////////////////////////////////////////////////////////////
//// INITIATION - Without this line the question type is not in use... ///
//////////////////////////////////////////////////////////////////////////
$QTYPES[RANDOM]= new random_qtype();
?>
|