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