File: questiontype.php

package info (click to toggle)
moodle 1.4.4.dfsg.1-3sarge1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 57,876 kB
  • ctags: 29,496
  • sloc: php: 271,617; sql: 5,084; xml: 702; perl: 638; sh: 403; java: 283; makefile: 42; pascal: 21
file content (231 lines) | stat: -rw-r--r-- 9,366 bytes parent folder | download
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
<?PHP  // $Id: questiontype.php,v 1.2 2004/07/21 13:01:06 moodler Exp $

/////////////////////
/// RANDOMSAMATCH ///
/////////////////////

/// The use of this question type together with the
/// question type RANDOM within the same quiz can cause
/// a shortanswer question to appear in a RANDOM question
/// as well as one of the matcher questions in a question of this type

/// QUESTION TYPE CLASS //////////////////
class quiz_randomsamatch_qtype extends quiz_match_qtype {
/// Extends MATCH as there are quite a few simularities...

    // $catrandoms carries question ids for shortanswer questions
    // available as random questios.
    // They are sorted by category.
    var $catrandoms = array();

    function name() {
        return 'randomsamatch';
    }

    function save_question_options($question) {
        $options->question = $question->id;
        $options->choose = $question->choose;
        if ($existing = get_record("quiz_randomsamatch",
                                   "question", $options->question)) {
            $options->id = $existing->id;
            if (!update_record("quiz_randomsamatch", $options)) {
                $result->error = "Could not update quiz randomsamatch options!";
                return $result;
            }
        } else {
            if (!insert_record("quiz_randomsamatch", $options)) {
                $result->error = "Could not insert quiz randomsamatch options!";
                return $result;
            }
        }
        return true;
    }
    
    function wrapped_questions($question) {
        if (empty($question->response)) {
            return false;
        } else {
            $wrapped = '';
            $delimiter = '';
            foreach ($question->response as $rkey => $response) {
                $wrapped .= $delimiter.$this->extract_response_id($rkey);
                $delimiter = ',';
            }
            return $wrapped;
        }
    }

    function create_response($question, $nameprefix, $questionsinuse) {
    // It's for question types like RANDOMSAMATCH and RANDOM that
    // the true power of the pattern with this function comes to the surface.
    // This implementation will stand even after a possible exclusion of
    // the funtions extract_response and convert_to_response_answer_field

        if (!isset($this->catrandoms[$question->category])) {
            /// Need to fetch the shortanswer question ids for the category:

            $saquestions = get_records_select('quiz_questions',
                    " category='$question->category'
                      AND qtype='".SHORTANSWER."'
                      AND id NOT IN ($questionsinuse) ");
            $this->catrandoms[$question->category] = array_keys($saquestions);
            shuffle($this->catrandoms[$question->category]);
        }

        /// Access question options to find out how many short-answer
        /// questions we are supposed to pick...
        if ($options = get_record('quiz_randomsamatch',
                                  'question', $question->id)) {
            $questionstopick = $options->choose;
        } else {
            notify("Error: Missing question options! - Try to pick two shortanswer questions anyway");
            $questionstopick = 2;
        }

        /// Pick the short-answer question ids and create the $response array
        $response = array();
        while ($questionstopick) {
            $said = array_pop($this->catrandoms[$question->category]);
            if (!ereg("(^|,)$said(,|$)", $questionsinuse)) {
                $response[$nameprefix.$said] = '0';
                --$questionstopick;
            }
        }

        if ($questionstopick) {
            notify("Error: could not get enough Short-Answer questions!");
            $count = count($response);
            $wanted = $count + $questionstopick;
            notify("Got $count Short-Answer questions, but wanted $wanted.");
        }

        return $response;
    }

    function extract_response($rawresponse, $nameprefix) {
    /// Simple implementation that does not check with the database
    /// and thus - does not bother to check whether there has been
    /// any changes to the question options.
        $response = array();
        $rawitems = explode(',', $rawresponse->answer);
        foreach ($rawitems as $rawitem) {
            $splits = explode('-', $rawitem, 2);
            $response[$nameprefix.$splits[0]] = $splits[1];
        }
        return $response;
    }

    function print_question_formulation_and_controls($question,
            $quiz, $readonly, $answers, $correctanswers, $nameprefix) {

        // Print question formulation

        echo format_text($question->questiontext,
                         $question->questiontextformat, NULL, $quiz->course);
        quiz_print_possible_question_image($quiz->id, $question);

        // Summarize shortanswer questions answer alternatives:
        if (empty($correctanswers)) {
            // Get them using the grade_response method
            $tempresult = $this->grade_response($question, $nameprefix);
            $saanswers = $tempresult->correctanswers;
        } else {
            $saanswers = $correctanswers;
        }
        foreach ($saanswers as $key => $saanswer) {
            unset($saanswers[$key]); // Unsets the nameprefix occurence
            $saanswers[$saanswer->id] = trim($saanswer->answer);
        }
        $saanswers = draw_rand_array($saanswers, count($saanswers));

        // Print the shortanswer questions and input controls:
        echo '<table border="0" cellpadding="10">';
        foreach ($question->response as $inputname => $response) {
            if (!($saquestion = get_record('quiz_questions', 'id',
                    quiz_extract_posted_id($inputname, $nameprefix)))) {
                notify("Error: cannot find shortanswer question for $inputname ");
                continue;
            }
            
            echo '<tr><td align="left" valign="top">';
            echo $saquestion->questiontext;
            echo '</td>';
            echo '<td align="right" valign="top">';
            if (!empty($correctanswers)
                    && $correctanswers[$inputname]->id == $response) {
                echo '<span="highlight">';
                choose_from_menu($saanswers, $inputname, $response);
                echo '</span><br />';
            } else {
                choose_from_menu($saanswers, $inputname, $response);
                if ($readonly && $quiz->correctanswers
                        && isset($correctanswer[$inputname])) {
                    quiz_print_correctanswer($correctanswer[$inputname]->answer);
                }
            }
            if ($quiz->feedback && isset($answers[$inputname])
                    && $answers[$inputname]->feedback) {
                quiz_print_comment($answers[$inputname]->feedback);
            }
            echo '</td></tr>';
        }
        echo '</table>';
    }

    function grade_response($question, $nameprefix) {
        global $QUIZ_QTYPES;

        $result->answers = array();
        $result->correctanswers = array();
        $result->grade = 0.0;
        
        foreach ($question->response as $inputname => $subresponse) {
            if ($subquestion = get_record('quiz_questions',
                    'id', quiz_extract_posted_id($inputname, $nameprefix),
                    // These two query conditions are security checks that prevents cheating...
                    'qtype', SHORTANSWER,
                    'category', $question->category)) {

                if ($subresponse = get_record('quiz_answers',
                                              'id', $subresponse)) {
                    $subquestion->response[$inputname] = $subresponse->answer;
                } else {
                    $subquestion->response[$inputname] = '';
                }

                // Use the shortanswer framework to for grading...
                $subresult = $QUIZ_QTYPES[SHORTANSWER]
                            ->grade_response($subquestion, $inputname);

                // Summarize shortanswer results
                if (isset($subresult->answers[$inputname])) {
                    $result->answers[$inputname] =
                            $subresult->answers[$inputname];
                    $result->grade += $result->answers[$inputname]->fraction;
                    if ($result->answers[$inputname]->fraction >= 1.0) {
                        $result->correctanswers[$inputname] =
                                $result->answers[$inputname];
                        continue;
                    }
                }
                // Pick the first correctanswer:
                foreach ($subresult->correctanswers as $correct) {
                    $result->correctanswers[$inputname] = $correct;
                    break;
                }
            }
        }
        if ($result->grade) {
            $result->grade /= count($question->response);
        }
        return $result;
    }
}
//// END OF CLASS ////

//////////////////////////////////////////////////////////////////////////
//// INITIATION - Without this line the question type is not in use... ///
//////////////////////////////////////////////////////////////////////////
$QUIZ_QTYPES[RANDOMSAMATCH]= new quiz_randomsamatch_qtype();

?>