Automatic installer.php lang files by installer_builder (20070726)
[moodle-linuxchix.git] / question / type / random / questiontype.php
blob19cfe7d04c17efc67267263242b551be98c73107
1 <?php // $Id$
2 /**
3 * Class for the random question type.
4 *
5 * The random question type does not have any options. When the question is
6 * attempted, it picks a question at random from the category it is in (and
7 * optionally its subcategories). For details see create_session_and_responses.
8 * Then all other method calls as delegated to that other question.
9 *
10 * @package questionbank
11 * @subpackage questiontypes
13 class random_qtype extends default_questiontype {
15 // Caches questions available as randoms sorted by category
16 // This is a 2-d array. The first key is question category, and the
17 // second is whether to include subcategories.
18 var $catrandoms = array();
20 function name() {
21 return 'random';
24 function menu_name() {
25 // Don't include this question type in the 'add new question' menu.
26 return false;
29 function is_usable_by_random() {
30 return false;
33 function get_question_options(&$question) {
34 // Don't do anything here, because the random question has no options.
35 // Everything is handled by the create- or restore_session_and_responses
36 // functions.
37 return true;
40 function save_question_options($question) {
41 // No options, but we set the parent field to the question's own id.
42 // Setting the parent field has the effect of hiding this question in
43 // various places.
44 return (set_field('question', 'parent', $question->id, 'id',
45 $question->id) ? true : false);
48 function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
49 global $QTYPE_EXCLUDE_FROM_RANDOM;
50 // Choose a random question from the category:
51 // We need to make sure that no question is used more than once in the
52 // quiz. Therfore the following need to be excluded:
53 // 1. All questions that are explicitly assigned to the quiz
54 // 2. All random questions
55 // 3. All questions that are already chosen by an other random question
56 // 4. Deleted questions
57 if (!isset($cmoptions->questionsinuse)) {
58 $cmoptions->questionsinuse = $attempt->layout;
61 if (!isset($this->catrandoms[$question->category][$question->questiontext])) {
62 // Need to fetch random questions from category $question->category"
63 // (Note: $this refers to the questiontype, not the question.)
64 global $CFG;
65 if ($question->questiontext == "1") {
66 // recurse into subcategories
67 $categorylist = question_categorylist($question->category);
68 } else {
69 $categorylist = $question->category;
71 if ($catrandoms = get_records_select('question',
72 "category IN ($categorylist)
73 AND parent = '0'
74 AND hidden = '0'
75 AND id NOT IN ($cmoptions->questionsinuse)
76 AND qtype NOT IN ($QTYPE_EXCLUDE_FROM_RANDOM)", '', 'id')) {
77 $this->catrandoms[$question->category][$question->questiontext] =
78 draw_rand_array($catrandoms, count($catrandoms));
79 } else {
80 $this->catrandoms[$question->category][$question->questiontext] = array();
84 while ($wrappedquestion =
85 array_pop($this->catrandoms[$question->category][$question->questiontext])) {
86 if (!ereg("(^|,)$wrappedquestion->id(,|$)", $cmoptions->questionsinuse)) {
87 /// $randomquestion is not in use and will therefore be used
88 /// as the randomquestion here...
89 $wrappedquestion = get_record('question', 'id', $wrappedquestion->id);
90 global $QTYPES;
91 $QTYPES[$wrappedquestion->qtype]
92 ->get_question_options($wrappedquestion);
93 $QTYPES[$wrappedquestion->qtype]
94 ->create_session_and_responses($wrappedquestion,
95 $state, $cmoptions, $attempt);
96 $wrappedquestion->name_prefix = $question->name_prefix;
97 $wrappedquestion->maxgrade = $question->maxgrade;
98 $cmoptions->questionsinuse .= ",$wrappedquestion->id";
99 $state->options->question = &$wrappedquestion;
100 return true;
103 $question->questiontext = '<span class="notifyproblem">'.
104 get_string('toomanyrandom', 'quiz'). '</span>';
105 $question->qtype = 'description';
106 $state->responses = array('' => '');
107 return true;
110 function restore_session_and_responses(&$question, &$state) {
111 /// The raw response records for random questions come in two flavours:
112 /// ---- 1 ----
113 /// For responses stored by Moodle version 1.5 and later the answer
114 /// field has the pattern random#-* where the # part is the numeric
115 /// question id of the actual question shown in the quiz attempt
116 /// and * represents the student response to that actual question.
117 /// ---- 2 ----
118 /// For responses stored by older Moodle versions - the answer field is
119 /// simply the question id of the actual question. The student response
120 /// to the actual question is stored in a separate response record.
121 /// -----------------------
122 /// This means that prior to Moodle version 1.5, random questions needed
123 /// two response records for storing the response to a single question.
124 /// From version 1.5 and later the question type random works like all
125 /// the other question types in that it now only needs one response
126 /// record per question.
127 global $QTYPES;
128 if (!ereg('^random([0-9]+)-(.*)$', $state->responses[''], $answerregs)) {
129 if (empty($state->responses[''])) {
130 // This is the case if there weren't enough questions available in the category.
131 $question->questiontext = '<span class="notifyproblem">'.
132 get_string('toomanyrandom', 'quiz'). '</span>';
133 $question->qtype = 'description';
134 return true;
136 // this must be an old-style state which stores only the id for the wrapped question
137 if (!$wrappedquestion = get_record('question', 'id', $state->responses[''])) {
138 notify("Can not find wrapped question {$state->responses['']}");
140 // In the old model the actual response was stored in a separate entry in
141 // the state table and fortunately there was only a single state per question
142 if (!$state->responses[''] = get_field('question_states', 'answer', 'attempt', $state->attempt, 'question', $wrappedquestion->id)) {
143 notify("Wrapped state missing");
145 } else {
146 if (!$wrappedquestion = get_record('question', 'id', $answerregs[1])) {
147 // The teacher must have deleted this question by mistake
148 // Convert it into a description type question with an explanation to the student
149 $wrappedquestion = clone($question);
150 $wrappedquestion->id = $answerregs[1];
151 $wrappedquestion->questiontext = get_string('questiondeleted', 'quiz');
152 $wrappedquestion->qtype = 'missingtype';
154 $state->responses[''] = (false === $answerregs[2]) ? '' : $answerregs[2];
157 if (!$QTYPES[$wrappedquestion->qtype]
158 ->get_question_options($wrappedquestion)) {
159 return false;
162 if (!$QTYPES[$wrappedquestion->qtype]
163 ->restore_session_and_responses($wrappedquestion, $state)) {
164 return false;
166 $wrappedquestion->name_prefix = $question->name_prefix;
167 $wrappedquestion->maxgrade = $question->maxgrade;
168 $state->options->question = &$wrappedquestion;
169 return true;
172 function save_session_and_responses(&$question, &$state) {
173 global $QTYPES;
174 $wrappedquestion = &$state->options->question;
176 // Trick the wrapped question into pretending to be the random one.
177 $realqid = $wrappedquestion->id;
178 $wrappedquestion->id = $question->id;
179 $QTYPES[$wrappedquestion->qtype]
180 ->save_session_and_responses($wrappedquestion, $state);
182 // Read what the wrapped question has just set the answer field to
183 // (if anything)
184 $response = get_field('question_states', 'answer', 'id', $state->id);
185 if(false === $response) {
186 return false;
189 // Prefix the answer field...
190 $response = "random$realqid-$response";
192 // ... and save it again.
193 if (!set_field('question_states', 'answer', addslashes($response), 'id', $state->id)) {
194 return false;
197 // Restore the real id
198 $wrappedquestion->id = $realqid;
199 return true;
202 function get_correct_responses(&$question, &$state) {
203 global $QTYPES;
204 $wrappedquestion = &$state->options->question;
205 return $QTYPES[$wrappedquestion->qtype]
206 ->get_correct_responses($wrappedquestion, $state);
209 // ULPGC ecastro
210 function get_all_responses(&$question, &$state){
211 global $QTYPES;
212 $wrappedquestion = &$state->options->question;
213 return $QTYPES[$wrappedquestion->qtype]
214 ->get_all_responses($wrappedquestion, $state);
217 // ULPGC ecastro
218 function get_actual_response(&$question, &$state){
219 global $QTYPES;
220 $wrappedquestion = &$state->options->question;
221 return $QTYPES[$wrappedquestion->qtype]
222 ->get_actual_response($wrappedquestion, $state);
225 function get_html_head_contributions(&$question, &$state) {
226 global $QTYPES;
227 $wrappedquestion = &$state->options->question;
228 return $QTYPES[$wrappedquestion->qtype]
229 ->get_html_head_contributions($wrappedquestion, $state);
232 function print_question(&$question, &$state, &$number, $cmoptions, $options) {
233 global $QTYPES;
234 $wrappedquestion = &$state->options->question;
235 $QTYPES[$wrappedquestion->qtype]
236 ->print_question($wrappedquestion, $state, $number, $cmoptions, $options);
239 function grade_responses(&$question, &$state, $cmoptions) {
240 global $QTYPES;
241 $wrappedquestion = &$state->options->question;
242 return $QTYPES[$wrappedquestion->qtype]
243 ->grade_responses($wrappedquestion, $state, $cmoptions);
246 function get_texsource(&$question, &$state, $cmoptions, $type) {
247 global $QTYPES;
248 $wrappedquestion = &$state->options->question;
249 return $QTYPES[$wrappedquestion->qtype]
250 ->get_texsource($wrappedquestion, $state, $cmoptions, $type);
253 function compare_responses(&$question, $state, $teststate) {
254 global $QTYPES;
255 $wrappedquestion = &$teststate->options->question;
256 return $QTYPES[$wrappedquestion->qtype]
257 ->compare_responses($wrappedquestion, $state, $teststate);
261 //// END OF CLASS ////
263 //////////////////////////////////////////////////////////////////////////
264 //// INITIATION - Without this line the question type is not in use... ///
265 //////////////////////////////////////////////////////////////////////////
266 question_register_questiontype(new random_qtype());