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