File: questiontype.php

package info (click to toggle)
moodle 1.6.3-2
  • links: PTS
  • area: main
  • in suites: etch-m68k
  • size: 37,052 kB
  • ctags: 51,688
  • sloc: php: 231,916; sql: 5,631; xml: 2,688; perl: 638; sh: 441; makefile: 48; pascal: 36
file content (247 lines) | stat: -rw-r--r-- 10,789 bytes parent folder | download | duplicates (2)
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();

?>