730fd187 |
1 | <?PHP // $Id$ |
2 | |
a5e1f35c |
3 | /// Library of function for module quiz |
730fd187 |
4 | |
a5e1f35c |
5 | /// CONSTANTS /////////////////////////////////////////////////////////////////// |
730fd187 |
6 | |
a5e1f35c |
7 | define("GRADEHIGHEST", "1"); |
8 | define("GRADEAVERAGE", "2"); |
9 | define("ATTEMPTFIRST", "3"); |
10 | define("ATTEMPTLAST", "4"); |
11 | $QUIZ_GRADE_METHOD = array ( GRADEHIGHEST => get_string("gradehighest", "quiz"), |
12 | GRADEAVERAGE => get_string("gradeaverage", "quiz"), |
13 | ATTEMPTFIRST => get_string("attemptfirst", "quiz"), |
14 | ATTEMPTLAST => get_string("attemptlast", "quiz")); |
15 | |
54a67a59 |
16 | define("SHORTANSWER", "1"); |
17 | define("TRUEFALSE", "2"); |
18 | define("MULTICHOICE", "3"); |
19 | define("RANDOM", "4"); |
20 | define("MATCH", "5"); |
21 | define("RANDOMSAMATCH", "6"); |
401c8de6 |
22 | define("DESCRIPTION", "7"); |
361f649d |
23 | define("NUMERICAL", "8"); |
54a67a59 |
24 | |
25 | $QUIZ_QUESTION_TYPE = array ( MULTICHOICE => get_string("multichoice", "quiz"), |
26 | TRUEFALSE => get_string("truefalse", "quiz"), |
27 | SHORTANSWER => get_string("shortanswer", "quiz"), |
361f649d |
28 | NUMERICAL => get_string("numerical", "quiz"), |
54a67a59 |
29 | MATCH => get_string("match", "quiz"), |
361f649d |
30 | DESCRIPTION => get_string("description", "quiz"), |
34d52ad7 |
31 | RANDOM => get_string("random", "quiz"), |
361f649d |
32 | RANDOMSAMATCH => get_string("randomsamatch", "quiz") |
33 | ); |
a5e1f35c |
34 | |
49220fa7 |
35 | $QUIZ_FILE_FORMAT = array ( "custom" => get_string("custom", "quiz"), |
c6bcd06a |
36 | "missingword" => get_string("missingword", "quiz"), |
37 | "blackboard" => get_string("blackboard", "quiz"), |
38 | "aon" => "AON" |
39 | ); |
49220fa7 |
40 | |
5325f8b8 |
41 | define("QUIZ_PICTURE_MAX_HEIGHT", "600"); // Not currently implemented |
42 | define("QUIZ_PICTURE_MAX_WIDTH", "600"); // Not currently implemented |
a5e1f35c |
43 | |
54a67a59 |
44 | define("QUIZ_MAX_NUMBER_ANSWERS", "8"); |
45 | |
a5e1f35c |
46 | /// FUNCTIONS /////////////////////////////////////////////////////////////////// |
730fd187 |
47 | |
48 | function quiz_add_instance($quiz) { |
a5e1f35c |
49 | /// Given an object containing all the necessary data, |
50 | /// (defined by the form in mod.html) this function |
51 | /// will create a new instance and return the id number |
52 | /// of the new instance. |
730fd187 |
53 | |
49dcdd18 |
54 | $quiz->created = time(); |
730fd187 |
55 | $quiz->timemodified = time(); |
49dcdd18 |
56 | $quiz->timeopen = make_timestamp($quiz->openyear, $quiz->openmonth, $quiz->openday, |
c04c41c7 |
57 | $quiz->openhour, $quiz->openminute, 0); |
49dcdd18 |
58 | $quiz->timeclose = make_timestamp($quiz->closeyear, $quiz->closemonth, $quiz->closeday, |
c04c41c7 |
59 | $quiz->closehour, $quiz->closeminute, 0); |
730fd187 |
60 | |
7bd1aa1d |
61 | if (!$quiz->id = insert_record("quiz", $quiz)) { |
62 | return false; // some error occurred |
63 | } |
64 | |
10b9291c |
65 | // The grades for every question in this quiz are stored in an array |
7bd1aa1d |
66 | if ($quiz->grades) { |
67 | foreach ($quiz->grades as $question => $grade) { |
401c8de6 |
68 | if ($question) { |
8d94f5a0 |
69 | unset($questiongrade); |
70 | $questiongrade->quiz = $quiz->id; |
71 | $questiongrade->question = $question; |
72 | $questiongrade->grade = $grade; |
73 | if (!insert_record("quiz_question_grades", $questiongrade)) { |
74 | return false; |
75 | } |
7bd1aa1d |
76 | } |
77 | } |
78 | } |
730fd187 |
79 | |
7bd1aa1d |
80 | return $quiz->id; |
730fd187 |
81 | } |
82 | |
83 | |
84 | function quiz_update_instance($quiz) { |
a5e1f35c |
85 | /// Given an object containing all the necessary data, |
86 | /// (defined by the form in mod.html) this function |
87 | /// will update an existing instance with new data. |
730fd187 |
88 | |
89 | $quiz->timemodified = time(); |
49dcdd18 |
90 | $quiz->timeopen = make_timestamp($quiz->openyear, $quiz->openmonth, $quiz->openday, |
c04c41c7 |
91 | $quiz->openhour, $quiz->openminute, 0); |
49dcdd18 |
92 | $quiz->timeclose = make_timestamp($quiz->closeyear, $quiz->closemonth, $quiz->closeday, |
c04c41c7 |
93 | $quiz->closehour, $quiz->closeminute, 0); |
730fd187 |
94 | $quiz->id = $quiz->instance; |
95 | |
7bd1aa1d |
96 | if (!update_record("quiz", $quiz)) { |
97 | return false; // some error occurred |
98 | } |
730fd187 |
99 | |
7bd1aa1d |
100 | |
10b9291c |
101 | // The grades for every question in this quiz are stored in an array |
7bd1aa1d |
102 | // Insert or update records as appropriate |
103 | |
104 | $existing = get_records("quiz_question_grades", "quiz", $quiz->id, "", "question,grade,id"); |
105 | |
106 | if ($quiz->grades) { |
107 | foreach ($quiz->grades as $question => $grade) { |
401c8de6 |
108 | if ($question) { |
8d94f5a0 |
109 | unset($questiongrade); |
110 | $questiongrade->quiz = $quiz->id; |
111 | $questiongrade->question = $question; |
112 | $questiongrade->grade = $grade; |
113 | if (isset($existing[$question])) { |
114 | if ($existing[$question]->grade != $grade) { |
115 | $questiongrade->id = $existing[$question]->id; |
116 | if (!update_record("quiz_question_grades", $questiongrade)) { |
117 | return false; |
118 | } |
119 | } |
120 | } else { |
121 | if (!insert_record("quiz_question_grades", $questiongrade)) { |
7bd1aa1d |
122 | return false; |
123 | } |
124 | } |
7bd1aa1d |
125 | } |
126 | } |
127 | } |
128 | |
129 | return true; |
730fd187 |
130 | } |
131 | |
132 | |
133 | function quiz_delete_instance($id) { |
a5e1f35c |
134 | /// Given an ID of an instance of this module, |
135 | /// this function will permanently delete the instance |
136 | /// and any data that depends on it. |
730fd187 |
137 | |
138 | if (! $quiz = get_record("quiz", "id", "$id")) { |
139 | return false; |
140 | } |
141 | |
142 | $result = true; |
143 | |
10b9291c |
144 | if ($attempts = get_record("quiz_attempts", "quiz", "$quiz->id")) { |
145 | foreach ($attempts as $attempt) { |
146 | if (! delete_records("quiz_responses", "attempt", "$attempt->id")) { |
147 | $result = false; |
148 | } |
149 | } |
150 | } |
151 | |
152 | if (! delete_records("quiz_attempts", "quiz", "$quiz->id")) { |
153 | $result = false; |
154 | } |
155 | |
156 | if (! delete_records("quiz_grades", "quiz", "$quiz->id")) { |
157 | $result = false; |
158 | } |
159 | |
160 | if (! delete_records("quiz_question_grades", "quiz", "$quiz->id")) { |
161 | $result = false; |
162 | } |
730fd187 |
163 | |
164 | if (! delete_records("quiz", "id", "$quiz->id")) { |
165 | $result = false; |
166 | } |
167 | |
168 | return $result; |
169 | } |
170 | |
171 | function quiz_user_outline($course, $user, $mod, $quiz) { |
a5e1f35c |
172 | /// Return a small object with summary information about what a |
173 | /// user has done with a given particular instance of this module |
174 | /// Used for user activity reports. |
175 | /// $return->time = the time they did it |
176 | /// $return->info = a short text description |
ebc3bd2b |
177 | if ($grade = get_record("quiz_grades", "userid", $user->id, "quiz", $quiz->id)) { |
98092498 |
178 | |
179 | if ($grade->grade) { |
180 | $result->info = get_string("grade").": $grade->grade"; |
181 | } |
182 | $result->time = $grade->timemodified; |
183 | return $result; |
184 | } |
185 | return NULL; |
730fd187 |
186 | |
187 | return $return; |
188 | } |
189 | |
190 | function quiz_user_complete($course, $user, $mod, $quiz) { |
a5e1f35c |
191 | /// Print a detailed representation of what a user has done with |
192 | /// a given particular instance of this module, for user activity reports. |
730fd187 |
193 | |
194 | return true; |
195 | } |
196 | |
730fd187 |
197 | function quiz_cron () { |
a5e1f35c |
198 | /// Function to be run periodically according to the moodle cron |
199 | /// This function searches for things that need to be done, such |
200 | /// as sending out mail, toggling flags etc ... |
730fd187 |
201 | |
202 | global $CFG; |
203 | |
204 | return true; |
205 | } |
206 | |
d0ac6bc2 |
207 | function quiz_grades($quizid) { |
858deff0 |
208 | /// Must return an array of grades, indexed by user, and a max grade. |
209 | |
ebc3bd2b |
210 | $return->grades = get_records_menu("quiz_grades", "quiz", $quizid, "", "userid,grade"); |
858deff0 |
211 | $return->maxgrade = get_field("quiz", "grade", "id", "$quizid"); |
212 | return $return; |
d0ac6bc2 |
213 | } |
214 | |
730fd187 |
215 | |
bdc23be0 |
216 | /// SQL FUNCTIONS //////////////////////////////////////////////////////////////////// |
217 | |
218 | function quiz_move_questions($category1, $category2) { |
219 | global $CFG; |
220 | return execute_sql("UPDATE {$CFG->prefix}quiz_questions |
221 | SET category = '$category2' |
222 | WHERE category = '$category1'", |
223 | false); |
224 | } |
225 | |
226 | function quiz_get_question_grades($quizid, $questionlist) { |
227 | global $CFG; |
228 | |
229 | return get_records_sql("SELECT question,grade |
230 | FROM {$CFG->prefix}quiz_question_grades |
231 | WHERE quiz = '$quizid' |
232 | AND question IN ($questionlist)"); |
233 | } |
234 | |
34d52ad7 |
235 | function quiz_get_random_categories($questionlist) { |
236 | /// Given an array of questions, this function looks for random |
237 | /// questions among them and returns a list of categories with |
238 | /// an associated count of random questions for each. |
239 | |
240 | global $CFG; |
241 | |
242 | return get_records_sql_menu("SELECT category,count(*) |
243 | FROM {$CFG->prefix}quiz_questions |
244 | WHERE id IN ($questionlist) |
245 | AND qtype = '".RANDOM."' |
246 | GROUP BY category "); |
247 | } |
248 | |
bdc23be0 |
249 | function quiz_get_grade_records($quiz) { |
250 | /// Gets all info required to display the table of quiz results |
251 | /// for report.php |
252 | global $CFG; |
253 | |
254 | return get_records_sql("SELECT qg.*, u.firstname, u.lastname, u.picture |
255 | FROM {$CFG->prefix}quiz_grades qg, |
256 | {$CFG->prefix}user u |
257 | WHERE qg.quiz = '$quiz->id' |
ebc3bd2b |
258 | AND qg.userid = u.id"); |
bdc23be0 |
259 | } |
260 | |
261 | function quiz_get_answers($question) { |
34d52ad7 |
262 | // Given a question, returns the correct answers for a given question |
bdc23be0 |
263 | global $CFG; |
95dbc030 |
264 | |
a2fe7cc0 |
265 | switch ($question->qtype) { |
95dbc030 |
266 | case SHORTANSWER: // Could be multiple answers |
34d52ad7 |
267 | return get_records_sql("SELECT a.*, sa.usecase |
bdc23be0 |
268 | FROM {$CFG->prefix}quiz_shortanswer sa, |
34d52ad7 |
269 | {$CFG->prefix}quiz_answers a |
bdc23be0 |
270 | WHERE sa.question = '$question->id' |
34d52ad7 |
271 | AND sa.question = a.question "); |
bdc23be0 |
272 | break; |
273 | |
95dbc030 |
274 | case TRUEFALSE: // Should be always two answers |
34d52ad7 |
275 | return get_records("quiz_answers", "question", $question->id); |
bdc23be0 |
276 | break; |
277 | |
95dbc030 |
278 | case MULTICHOICE: // Should be multiple answers |
34d52ad7 |
279 | return get_records_sql("SELECT a.*, mc.single |
bdc23be0 |
280 | FROM {$CFG->prefix}quiz_multichoice mc, |
34d52ad7 |
281 | {$CFG->prefix}quiz_answers a |
bdc23be0 |
282 | WHERE mc.question = '$question->id' |
34d52ad7 |
283 | AND mc.question = a.question "); |
bdc23be0 |
284 | break; |
285 | |
54a67a59 |
286 | case MATCH: |
34d52ad7 |
287 | return get_records("quiz_match_sub", "question", $question->id); |
40b1a221 |
288 | break; |
54a67a59 |
289 | |
290 | case RANDOMSAMATCH: // Could be any of many answers, return them all |
34d52ad7 |
291 | return get_records_sql("SELECT a.* |
95dbc030 |
292 | FROM {$CFG->prefix}quiz_questions q, |
34d52ad7 |
293 | {$CFG->prefix}quiz_answers a |
95dbc030 |
294 | WHERE q.category = '$question->category' |
295 | AND q.qtype = ".SHORTANSWER." |
34d52ad7 |
296 | AND q.id = a.question "); |
95dbc030 |
297 | break; |
298 | |
361f649d |
299 | case NUMERICAL: // Logical support for multiple answers |
300 | return get_records_sql("SELECT a.*, n.min, n.max |
301 | FROM {$CFG->prefix}quiz_numerical n, |
302 | {$CFG->prefix}quiz_answers a |
303 | WHERE a.question = '$question->id' |
304 | AND n.answer = a.id "); |
305 | break; |
306 | |
307 | |
bdc23be0 |
308 | default: |
309 | return false; |
310 | } |
311 | } |
312 | |
313 | |
ef4145f6 |
314 | function quiz_get_attempt_responses($attempt, $quiz) { |
bdc23be0 |
315 | // Given an attempt object, this function gets all the |
316 | // stored responses and returns them in a format suitable |
317 | // for regrading using quiz_grade_attempt_results() |
318 | global $CFG; |
319 | |
33de9f7b |
320 | if (!$responses = get_records_sql("SELECT q.id, q.qtype, q.category, q.questiontext, r.answer |
bdc23be0 |
321 | FROM {$CFG->prefix}quiz_responses r, |
322 | {$CFG->prefix}quiz_questions q |
323 | WHERE r.attempt = '$attempt->id' |
34d52ad7 |
324 | AND q.id = r.question")) { |
bdc23be0 |
325 | notify("Could not find any responses for that attempt!"); |
326 | return false; |
327 | } |
328 | |
34d52ad7 |
329 | |
330 | foreach ($responses as $key => $response) { |
331 | if ($response->qtype == RANDOM) { |
332 | $responses[$key]->random = $response->answer; |
333 | $responses[$key]->answer = explode(",",$responses[$response->answer]->answer); |
334 | $responses[$response->answer]->delete = true; |
3960a44b |
335 | } else if ($response->qtype == NUMERICAL or $response->qtype == SHORTANSWER) { |
336 | $responses[$key]->answer = array($response->answer); |
34d52ad7 |
337 | } else { |
338 | $responses[$key]->answer = explode(",",$response->answer); |
339 | } |
340 | } |
bdc23be0 |
341 | foreach ($responses as $key => $response) { |
34d52ad7 |
342 | if (!empty($response->delete)) { |
343 | unset($responses[$key]); |
344 | } |
bdc23be0 |
345 | } |
346 | |
347 | return $responses; |
348 | } |
349 | |
350 | |
351 | |
730fd187 |
352 | ////////////////////////////////////////////////////////////////////////////////////// |
a5e1f35c |
353 | /// Any other quiz functions go here. Each of them must have a name that |
354 | /// starts with quiz_ |
730fd187 |
355 | |
a8a372cc |
356 | function quiz_print_comment($text) { |
357 | global $THEME; |
358 | |
361f649d |
359 | echo "<span class=feedbacktext>".text_to_html($text, true, false)."</span>"; |
a8a372cc |
360 | } |
361 | |
8db3eadd |
362 | function quiz_print_correctanswer($text) { |
363 | global $THEME; |
364 | |
361f649d |
365 | echo "<p align=right><span class=highlight>$text</span></p>"; |
8db3eadd |
366 | } |
367 | |
34d52ad7 |
368 | function quiz_print_question_icon($question, $editlink=true) { |
c74a0ca5 |
369 | // Prints a question icon |
cc3b8c75 |
370 | |
371 | global $QUIZ_QUESTION_TYPE; |
372 | |
34d52ad7 |
373 | if ($editlink) { |
361f649d |
374 | echo "<a href=\"question.php?id=$question->id\" title=\"".$QUIZ_QUESTION_TYPE[$question->qtype]."\">"; |
34d52ad7 |
375 | } |
a2fe7cc0 |
376 | switch ($question->qtype) { |
c74a0ca5 |
377 | case SHORTANSWER: |
361f649d |
378 | echo '<img border=0 height=16 width=16 src="pix/sa.gif">'; |
c74a0ca5 |
379 | break; |
380 | case TRUEFALSE: |
361f649d |
381 | echo '<img border=0 height=16 width=16 src="pix/tf.gif">'; |
c74a0ca5 |
382 | break; |
383 | case MULTICHOICE: |
361f649d |
384 | echo '<img border=0 height=16 width=16 src="pix/mc.gif">'; |
c74a0ca5 |
385 | break; |
386 | case RANDOM: |
361f649d |
387 | echo '<img border=0 height=16 width=16 src="pix/rs.gif">'; |
c74a0ca5 |
388 | break; |
54a67a59 |
389 | case MATCH: |
361f649d |
390 | echo '<img border=0 height=16 width=16 src="pix/ma.gif">'; |
54a67a59 |
391 | break; |
392 | case RANDOMSAMATCH: |
361f649d |
393 | echo '<img border=0 height=16 width=16 src="pix/rm.gif">'; |
95dbc030 |
394 | break; |
401c8de6 |
395 | case DESCRIPTION: |
361f649d |
396 | echo '<img border=0 height=16 width=16 src="pix/de.gif">'; |
397 | break; |
398 | case NUMERICAL: |
399 | echo '<img border=0 height=16 width=16 src="pix/nu.gif">'; |
401c8de6 |
400 | break; |
c74a0ca5 |
401 | } |
34d52ad7 |
402 | if ($editlink) { |
361f649d |
403 | echo "</a>\n"; |
34d52ad7 |
404 | } |
c74a0ca5 |
405 | } |
406 | |
a8a372cc |
407 | |
34d52ad7 |
408 | |
409 | function quiz_print_question($number, $question, $grade, $courseid, |
410 | $feedback=NULL, $response=NULL, $actualgrade=NULL, $correct=NULL, |
4b85b717 |
411 | $realquestion=NULL, $shuffleanswers=false) { |
34d52ad7 |
412 | |
413 | /// Prints a quiz question, any format |
414 | /// $question is provided as an object |
14d8c0b4 |
415 | |
263cff8b |
416 | if ($question->image) { |
417 | if ($quizcategory = get_record("quiz_categories", "id", $question->category)) { |
418 | $question->course = $quizcategory->course; |
419 | } else { |
420 | $question->course = $courseid; |
421 | } |
422 | } |
423 | |
401c8de6 |
424 | if ($question->qtype == DESCRIPTION) { // Special case question - has no answers etc |
425 | echo '<p align="center">'; |
426 | echo text_to_html($question->questiontext); |
427 | if ($question->image) { |
263cff8b |
428 | print_file_picture($question->image, $question->course); |
401c8de6 |
429 | } |
430 | echo '</p>'; |
431 | return true; |
432 | } |
433 | |
a2fe7cc0 |
434 | if (empty($actualgrade)) { |
435 | $actualgrade = 0; |
436 | } |
437 | |
14d8c0b4 |
438 | $stranswer = get_string("answer", "quiz"); |
439 | $strmarks = get_string("marks", "quiz"); |
440 | |
361f649d |
441 | echo "<table width=100% cellspacing=10><tr><td nowrap width=100 valign=top>"; |
442 | echo "<p align=center><b>$number</b></p>"; |
19c4f55c |
443 | if ($feedback or $response) { |
361f649d |
444 | echo "<p align=center><font size=1>$strmarks: $actualgrade/$grade</font></p>"; |
a8a372cc |
445 | } else { |
361f649d |
446 | echo "<p align=center><font size=1>$grade $strmarks</font></p>"; |
a8a372cc |
447 | } |
14d8c0b4 |
448 | print_spacer(1,100); |
361f649d |
449 | echo "</td><td valign=top>"; |
34d52ad7 |
450 | |
451 | if (empty($realquestion)) { |
452 | $realquestion->id = $question->id; |
453 | } else { // Add a marker to connect this question to the actual random parent |
454 | echo "<input type=\"hidden\" name=\"q{$realquestion->id}rq$question->id\" value=\"x\">\n"; |
455 | } |
14d8c0b4 |
456 | |
a2fe7cc0 |
457 | switch ($question->qtype) { |
34d52ad7 |
458 | |
a5e1f35c |
459 | case SHORTANSWER: |
361f649d |
460 | case NUMERICAL: |
2a2c9725 |
461 | echo text_to_html($question->questiontext); |
14d8c0b4 |
462 | if ($question->image) { |
263cff8b |
463 | print_file_picture($question->image, $question->course); |
14d8c0b4 |
464 | } |
a8a372cc |
465 | if ($response) { |
466 | $value = "VALUE=\"$response[0]\""; |
a2fe7cc0 |
467 | } else { |
468 | $value = ""; |
a8a372cc |
469 | } |
34d52ad7 |
470 | echo "<P ALIGN=RIGHT>$stranswer: <INPUT TYPE=TEXT NAME=q$realquestion->id SIZE=20 $value></P>"; |
a8a372cc |
471 | if ($feedback) { |
472 | quiz_print_comment("<P ALIGN=right>$feedback[0]</P>"); |
473 | } |
8db3eadd |
474 | if ($correct) { |
c74a0ca5 |
475 | $correctanswers = implode(", ", $correct); |
8db3eadd |
476 | quiz_print_correctanswer($correctanswers); |
477 | } |
14d8c0b4 |
478 | break; |
479 | |
a5e1f35c |
480 | case TRUEFALSE: |
14d8c0b4 |
481 | if (!$options = get_record("quiz_truefalse", "question", $question->id)) { |
482 | notify("Error: Missing question options!"); |
483 | } |
a2fe7cc0 |
484 | if (!$true = get_record("quiz_answers", "id", $options->trueanswer)) { |
14d8c0b4 |
485 | notify("Error: Missing question answers!"); |
486 | } |
a2fe7cc0 |
487 | if (!$false = get_record("quiz_answers", "id", $options->falseanswer)) { |
14d8c0b4 |
488 | notify("Error: Missing question answers!"); |
489 | } |
490 | if (!$true->answer) { |
491 | $true->answer = get_string("true", "quiz"); |
492 | } |
493 | if (!$false->answer) { |
494 | $false->answer = get_string("false", "quiz"); |
495 | } |
2a2c9725 |
496 | echo text_to_html($question->questiontext); |
14d8c0b4 |
497 | if ($question->image) { |
263cff8b |
498 | print_file_picture($question->image, $question->course); |
14d8c0b4 |
499 | } |
a8a372cc |
500 | |
a2fe7cc0 |
501 | $truechecked = ""; |
502 | $falsechecked = ""; |
503 | |
504 | if (!empty($response[$true->id])) { |
a8a372cc |
505 | $truechecked = "CHECKED"; |
506 | $feedbackid = $true->id; |
a2fe7cc0 |
507 | } else if (!empty($response[$false->id])) { |
a8a372cc |
508 | $falsechecked = "CHECKED"; |
509 | $feedbackid = $false->id; |
510 | } |
a2fe7cc0 |
511 | |
512 | $truecorrect = ""; |
513 | $falsecorrect = ""; |
8db3eadd |
514 | if ($correct) { |
a2fe7cc0 |
515 | if (!empty($correct[$true->id])) { |
8db3eadd |
516 | $truecorrect = "CLASS=highlight"; |
517 | } |
a2fe7cc0 |
518 | if (!empty($correct[$false->id])) { |
8db3eadd |
519 | $falsecorrect = "CLASS=highlight"; |
520 | } |
521 | } |
522 | echo "<TABLE ALIGN=right cellpadding=5><TR><TD align=right>$stranswer: "; |
523 | echo "<TD $truecorrect>"; |
34d52ad7 |
524 | echo "<INPUT $truechecked TYPE=RADIO NAME=\"q$realquestion->id\" VALUE=\"$true->id\">$true->answer"; |
8db3eadd |
525 | echo "</TD><TD $falsecorrect>"; |
0bf2925d |
526 | echo "<INPUT $falsechecked TYPE=RADIO NAME=\"q$realquestion->id\" VALUE=\"$false->id\">$false->answer"; |
8db3eadd |
527 | echo "</TD></TR></TABLE><BR CLEAR=ALL>"; |
a8a372cc |
528 | if ($feedback) { |
529 | quiz_print_comment("<P ALIGN=right>$feedback[$feedbackid]</P>"); |
530 | } |
531 | |
14d8c0b4 |
532 | break; |
533 | |
a5e1f35c |
534 | case MULTICHOICE: |
14d8c0b4 |
535 | if (!$options = get_record("quiz_multichoice", "question", $question->id)) { |
536 | notify("Error: Missing question options!"); |
537 | } |
a5e1f35c |
538 | if (!$answers = get_records_list("quiz_answers", "id", $options->answers)) { |
14d8c0b4 |
539 | notify("Error: Missing question answers!"); |
540 | } |
2a2c9725 |
541 | echo text_to_html($question->questiontext); |
14d8c0b4 |
542 | if ($question->image) { |
263cff8b |
543 | print_file_picture($question->image, $question->course); |
14d8c0b4 |
544 | } |
545 | echo "<TABLE ALIGN=right>"; |
546 | echo "<TR><TD valign=top>$stranswer: </TD><TD>"; |
81b635c3 |
547 | echo "<TABLE>"; |
14d8c0b4 |
548 | $answerids = explode(",", $options->answers); |
a8a372cc |
549 | |
4b85b717 |
550 | if ($shuffleanswers) { |
551 | $answerids = swapshuffle($answerids); |
552 | } |
553 | |
14d8c0b4 |
554 | foreach ($answerids as $key => $answerid) { |
555 | $answer = $answers[$answerid]; |
68fefdbe |
556 | $qnumchar = chr(ord('a') + $key); |
a8a372cc |
557 | |
8e6c87cc |
558 | if (empty($feedback) or empty($response[$answerid])) { |
a8a372cc |
559 | $checked = ""; |
8e6c87cc |
560 | } else { |
561 | $checked = "CHECKED"; |
a8a372cc |
562 | } |
14d8c0b4 |
563 | echo "<TR><TD valign=top>"; |
a5e1f35c |
564 | if ($options->single) { |
34d52ad7 |
565 | echo "<INPUT $checked TYPE=RADIO NAME=q$realquestion->id VALUE=\"$answer->id\">"; |
14d8c0b4 |
566 | } else { |
34d52ad7 |
567 | echo "<INPUT $checked TYPE=CHECKBOX NAME=q$realquestion->id"."a$answer->id VALUE=\"$answer->id\">"; |
14d8c0b4 |
568 | } |
569 | echo "</TD>"; |
8e6c87cc |
570 | if (empty($feedback) or empty($correct[$answer->id])) { |
68fefdbe |
571 | echo "<TD valign=top>$qnumchar. $answer->answer</TD>"; |
8e6c87cc |
572 | } else { |
68fefdbe |
573 | echo "<TD valign=top CLASS=highlight>$qnumchar. $answer->answer</TD>"; |
8db3eadd |
574 | } |
8e6c87cc |
575 | if (!empty($feedback)) { |
a8a372cc |
576 | echo "<TD valign=top> "; |
8e6c87cc |
577 | if (!empty($response[$answerid])) { |
a8a372cc |
578 | quiz_print_comment($feedback[$answerid]); |
579 | } |
580 | echo "</TD>"; |
581 | } |
14d8c0b4 |
582 | echo "</TR>"; |
583 | } |
584 | echo "</TABLE>"; |
585 | echo "</TABLE>"; |
586 | break; |
587 | |
54a67a59 |
588 | case MATCH: |
589 | if (!$options = get_record("quiz_match", "question", $question->id)) { |
590 | notify("Error: Missing question options!"); |
591 | } |
592 | if (!$subquestions = get_records_list("quiz_match_sub", "id", $options->subquestions)) { |
593 | notify("Error: Missing subquestions for this question!"); |
594 | } |
96192c44 |
595 | if (!empty($question->questiontext)) { |
596 | echo text_to_html($question->questiontext); |
4b85b717 |
597 | } |
96192c44 |
598 | if (!empty($question->image)) { |
263cff8b |
599 | print_file_picture($question->image, $question->course); |
54a67a59 |
600 | } |
601 | |
96192c44 |
602 | if ($shuffleanswers) { |
603 | $subquestions = draw_rand_array($subquestions, count($subquestions)); |
604 | } |
54a67a59 |
605 | foreach ($subquestions as $subquestion) { |
606 | $answers[$subquestion->id] = $subquestion->answertext; |
607 | } |
608 | |
609 | $answers = draw_rand_array($answers, count($answers)); |
610 | |
611 | echo "<table border=0 cellpadding=10 align=right>"; |
612 | foreach ($subquestions as $key => $subquestion) { |
613 | echo "<tr><td align=left valign=top>"; |
614 | echo $subquestion->questiontext; |
615 | echo "</td>"; |
616 | if (empty($response)) { |
617 | echo "<td align=right valign=top>"; |
34d52ad7 |
618 | choose_from_menu($answers, "q$realquestion->id"."r$subquestion->id"); |
54a67a59 |
619 | } else { |
620 | if (empty($response[$key])) { |
621 | echo "<td align=right valign=top>"; |
34d52ad7 |
622 | choose_from_menu($answers, "q$realquestion->id"."r$subquestion->id"); |
54a67a59 |
623 | } else { |
624 | if ($response[$key] == $correct[$key]) { |
625 | echo "<td align=right valign=top class=highlight>"; |
34d52ad7 |
626 | choose_from_menu($answers, "q$realquestion->id"."r$subquestion->id", $response[$key]); |
54a67a59 |
627 | } else { |
628 | echo "<td align=right valign=top>"; |
34d52ad7 |
629 | choose_from_menu($answers, "q$realquestion->id"."r$subquestion->id", $response[$key]); |
54a67a59 |
630 | } |
631 | } |
632 | |
633 | if (!empty($feedback[$key])) { |
634 | quiz_print_comment($feedback[$key]); |
635 | } |
636 | } |
637 | echo "</td></tr>"; |
638 | } |
639 | echo "</table>"; |
640 | |
641 | break; |
642 | |
643 | case RANDOMSAMATCH: |
644 | if (!$options = get_record("quiz_randomsamatch", "question", $question->id)) { |
95dbc030 |
645 | notify("Error: Missing question options!"); |
646 | } |
647 | echo text_to_html($question->questiontext); |
648 | if ($question->image) { |
263cff8b |
649 | print_file_picture($question->image, $question->course); |
95dbc030 |
650 | } |
651 | |
652 | /// First, get all the questions available |
653 | |
654 | $allquestions = get_records_select("quiz_questions", |
655 | "category = $question->category AND qtype = ".SHORTANSWER); |
656 | if (count($allquestions) < $options->choose) { |
657 | notify("Error: could not find enough Short Answer questions in the database!"); |
658 | notify("Found ".count($allquestions).", need $options->choose."); |
659 | break; |
660 | } |
661 | |
662 | if (empty($response)) { // Randomly pick the questions |
663 | if (!$randomquestions = draw_rand_array($allquestions, $options->choose)) { |
664 | notify("Error choosing $options->choose random questions"); |
665 | break; |
666 | } |
667 | } else { // Use existing questions |
668 | $randomquestions = array(); |
669 | foreach ($response as $key => $rrr) { |
670 | $rrr = explode("-", $rrr); |
671 | $randomquestions[$key] = $allquestions[$key]; |
672 | $responseanswer[$key] = $rrr[1]; |
673 | } |
674 | } |
675 | |
676 | /// For each selected, find the best matching answers |
677 | |
678 | foreach ($randomquestions as $randomquestion) { |
679 | $shortanswerquestion = get_record("quiz_shortanswer", "question", $randomquestion->id); |
680 | $questionanswers = get_records_list("quiz_answers", "id", $shortanswerquestion->answers); |
681 | $bestfraction = 0; |
682 | $bestanswer = NULL; |
683 | foreach ($questionanswers as $questionanswer) { |
684 | if ($questionanswer->fraction > $bestfraction) { |
685 | $bestanswer = $questionanswer; |
686 | } |
687 | } |
688 | if (empty($bestanswer)) { |
689 | notify("Error: Could not find the best answer for question: ".$randomquestions->name); |
690 | break; |
691 | } |
692 | $randomanswers[$bestanswer->id] = trim($bestanswer->answer); |
693 | } |
694 | |
695 | if (!$randomanswers = draw_rand_array($randomanswers, $options->choose)) { // Mix them up |
696 | notify("Error randomising answers!"); |
697 | break; |
698 | } |
699 | |
700 | echo "<table border=0 cellpadding=10>"; |
701 | foreach ($randomquestions as $key => $randomquestion) { |
702 | echo "<tr><td align=left valign=top>"; |
703 | echo $randomquestion->questiontext; |
704 | echo "</td>"; |
705 | echo "<td align=right valign=top>"; |
706 | if (empty($response)) { |
34d52ad7 |
707 | choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id"); |
95dbc030 |
708 | } else { |
709 | if (!empty($correct[$key])) { |
710 | if ($randomanswers[$responseanswer[$key]] == $correct[$key]) { |
711 | echo "<span=highlight>"; |
34d52ad7 |
712 | choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id", $responseanswer[$key]); |
95dbc030 |
713 | echo "</span><br \>"; |
714 | } else { |
34d52ad7 |
715 | choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id", $responseanswer[$key]); |
95dbc030 |
716 | quiz_print_correctanswer($correct[$key]); |
717 | } |
718 | } else { |
34d52ad7 |
719 | choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id", $responseanswer[$key]); |
95dbc030 |
720 | } |
721 | if (!empty($feedback[$key])) { |
722 | quiz_print_comment($feedback[$key]); |
723 | } |
724 | } |
725 | echo "</td></tr>"; |
726 | } |
727 | echo "</table>"; |
728 | break; |
729 | |
34d52ad7 |
730 | case RANDOM: |
731 | echo "<P>Random questions should not be printed this way!</P>"; |
732 | break; |
8db3eadd |
733 | |
14d8c0b4 |
734 | default: |
735 | notify("Error: Unknown question type!"); |
736 | } |
737 | |
738 | echo "</TD></TR></TABLE>"; |
3a506ca2 |
739 | } |
740 | |
34d52ad7 |
741 | |
742 | |
96192c44 |
743 | function quiz_print_quiz_questions($quiz, $results=NULL, $questions=NULL, $shuffleorder=NULL) { |
a5e1f35c |
744 | // Prints a whole quiz on one page. |
745 | |
34d52ad7 |
746 | /// Get the questions |
747 | |
34d52ad7 |
748 | if (!$questions) { |
434802d5 |
749 | if (empty($quiz->questions)) { |
750 | notify("No questions have been defined!"); |
751 | return false; |
752 | } |
753 | |
34d52ad7 |
754 | if (!$questions = get_records_list("quiz_questions", "id", $quiz->questions, "")) { |
434802d5 |
755 | notify("Error when reading questions from the database!"); |
34d52ad7 |
756 | return false; |
757 | } |
d288fa52 |
758 | } |
4b85b717 |
759 | |
d288fa52 |
760 | if (!$shuffleorder) { |
761 | if (!empty($quiz->shufflequestions)) { // Mix everything up |
4b85b717 |
762 | $questions = swapshuffle_assoc($questions); |
ada728e2 |
763 | } else { |
d288fa52 |
764 | $shuffleorder = explode(",", $quiz->questions); // Use originally defined order |
4b85b717 |
765 | } |
34d52ad7 |
766 | } |
767 | |
e1122620 |
768 | if ($shuffleorder) { // Order has been defined, so reorder questions |
769 | $oldquestions = $questions; |
770 | $questions = array(); |
771 | foreach ($shuffleorder as $key) { |
772 | $questions[] = $oldquestions[$key]; // This loses the index key, but doesn't matter |
773 | } |
774 | } |
775 | |
434802d5 |
776 | if (!$grades = get_records_list("quiz_question_grades", "question", $quiz->questions, "", "question,grade")) { |
777 | notify("No grades were found for these questions!"); |
778 | return false; |
779 | } |
780 | |
34d52ad7 |
781 | |
782 | /// Examine the set of questions for random questions, and retrieve them |
783 | |
434802d5 |
784 | if (empty($results)) { // Choose some new random questions |
34d52ad7 |
785 | if ($randomcats = quiz_get_random_categories($quiz->questions)) { |
786 | foreach ($randomcats as $randomcat => $randomdraw) { |
787 | /// Get the appropriate amount of random questions from this category |
7bfa4fad |
788 | if (!$catquestions[$randomcat] = quiz_choose_random_questions($randomcat, $randomdraw, $quiz->questions)) { |
434802d5 |
789 | notify(get_string("toomanyrandom", "quiz", $randomcat)); |
34d52ad7 |
790 | return false; |
791 | } |
792 | } |
793 | } |
434802d5 |
794 | } else { // Get the previously chosen questions |
795 | $chosen = array(); |
796 | foreach ($questions as $question) { |
797 | if (isset($question->random)) { |
798 | $chosen[] = $question->random; |
799 | } |
800 | } |
801 | if ($chosen) { |
802 | $chosenlist = implode(",", $chosen); |
803 | if (!$chosen = get_records_list("quiz_questions", "id", $chosenlist, "")) { |
804 | notify("Error when reading questions from the database!"); |
805 | return false; |
806 | } |
807 | } |
a5e1f35c |
808 | } |
809 | |
9307692f |
810 | $strconfirmattempt = addslashes(get_string("readytosend", "quiz")); |
811 | |
812 | echo "<FORM METHOD=POST ACTION=attempt.php onsubmit=\"return confirm('$strconfirmattempt');\">"; |
a5e1f35c |
813 | echo "<INPUT TYPE=hidden NAME=q VALUE=\"$quiz->id\">"; |
a8a372cc |
814 | |
34d52ad7 |
815 | $count = 0; |
96192c44 |
816 | $questionorder = array(); |
817 | |
34d52ad7 |
818 | foreach ($questions as $question) { |
401c8de6 |
819 | |
820 | if ($question->qtype != DESCRIPTION) { // Description questions are not counted |
821 | $count++; |
822 | } |
34d52ad7 |
823 | |
e1122620 |
824 | $questionorder[] = $question->id; |
825 | |
8db3eadd |
826 | $feedback = NULL; |
827 | $response = NULL; |
828 | $actualgrades = NULL; |
829 | $correct = NULL; |
34d52ad7 |
830 | $randomquestion = NULL; |
831 | |
832 | if (empty($results)) { |
833 | if ($question->qtype == RANDOM ) { // Set up random questions |
834 | $randomquestion = $question; |
835 | $question = array_pop($catquestions[$randomquestion->category]); |
836 | $grades[$question->id]->grade = $grades[$randomquestion->id]->grade; |
8e6c87cc |
837 | } |
34d52ad7 |
838 | } else { |
839 | if (!empty($results->feedback[$question->id])) { |
840 | $feedback = $results->feedback[$question->id]; |
8e6c87cc |
841 | } |
34d52ad7 |
842 | if (!empty($results->response[$question->id])) { |
843 | $response = $results->response[$question->id]; |
844 | } |
845 | if (!empty($results->grades[$question->id])) { |
846 | $actualgrades = $results->grades[$question->id]; |
8e6c87cc |
847 | } |
8db3eadd |
848 | if ($quiz->correctanswers) { |
34d52ad7 |
849 | if (!empty($results->correct[$question->id])) { |
850 | $correct = $results->correct[$question->id]; |
8e6c87cc |
851 | } |
8db3eadd |
852 | } |
34d52ad7 |
853 | if (!empty($question->random)) { |
854 | $randomquestion = $question; |
434802d5 |
855 | $question = $chosen[$question->random]; |
34d52ad7 |
856 | $grades[$question->id]->grade = $grades[$randomquestion->id]->grade; |
857 | } |
a8a372cc |
858 | } |
8db3eadd |
859 | |
2408867e |
860 | |
a5e1f35c |
861 | print_simple_box_start("CENTER", "90%"); |
34d52ad7 |
862 | quiz_print_question($count, $question, $grades[$question->id]->grade, $quiz->course, |
4b85b717 |
863 | $feedback, $response, $actualgrades, $correct, |
864 | $randomquestion, $quiz->shuffleanswers); |
a5e1f35c |
865 | print_simple_box_end(); |
96192c44 |
866 | echo "<br \>"; |
a5e1f35c |
867 | } |
a8a372cc |
868 | |
8e6c87cc |
869 | if (empty($results)) { |
96192c44 |
870 | if (!empty($quiz->shufflequestions)) { // Things have been mixed up, so pass the question order |
871 | $shuffleorder = implode(',', $questionorder); |
872 | echo "<input type=hidden name=shuffleorder value=\"$shuffleorder\">\n"; |
873 | } |
874 | echo "<center><input type=submit value=\"".get_string("savemyanswers", "quiz")."\"></center>"; |
a8a372cc |
875 | } |
96192c44 |
876 | echo "</form>"; |
10b9291c |
877 | |
878 | return true; |
a5e1f35c |
879 | } |
34d52ad7 |
880 | |
881 | |
6a952ce7 |
882 | |
883 | function quiz_get_default_category($courseid) { |
34d52ad7 |
884 | /// Returns the current category |
885 | |
6a952ce7 |
886 | if ($categories = get_records("quiz_categories", "course", $courseid, "id")) { |
887 | foreach ($categories as $category) { |
888 | return $category; // Return the first one (lowest id) |
889 | } |
890 | } |
891 | |
892 | // Otherwise, we need to make one |
10b9291c |
893 | $category->name = get_string("default", "quiz"); |
894 | $category->info = get_string("defaultinfo", "quiz"); |
6a952ce7 |
895 | $category->course = $courseid; |
896 | $category->publish = 0; |
897 | |
898 | if (!$category->id = insert_record("quiz_categories", $category)) { |
899 | notify("Error creating a default category!"); |
900 | return false; |
901 | } |
902 | return $category; |
903 | } |
904 | |
c74a0ca5 |
905 | function quiz_get_category_menu($courseid, $published=false) { |
da5fb074 |
906 | /// Returns the list of categories |
907 | $publish = ""; |
c74a0ca5 |
908 | if ($published) { |
909 | $publish = "OR publish = '1'"; |
910 | } |
bdc23be0 |
911 | return get_records_select_menu("quiz_categories", "course='$courseid' $publish", "name ASC", "id,name"); |
c74a0ca5 |
912 | } |
913 | |
6a952ce7 |
914 | function quiz_print_category_form($course, $current) { |
915 | // Prints a form to choose categories |
916 | |
bdc23be0 |
917 | if (!$categories = get_records_select("quiz_categories", "course='$course->id' OR publish = '1'", "name ASC")) { |
6a952ce7 |
918 | if (!$category = quiz_get_default_category($course->id)) { |
919 | notify("Error creating a default category!"); |
920 | return false; |
921 | } |
cb62c00a |
922 | $categories[$category->id] = $category; |
6a952ce7 |
923 | } |
8d94f5a0 |
924 | foreach ($categories as $key => $category) { |
925 | if ($category->publish) { |
b55a466b |
926 | if ($catcourse = get_record("course", "id", $category->course)) { |
927 | $category->name .= " ($catcourse->shortname)"; |
8d94f5a0 |
928 | } |
929 | } |
b55a466b |
930 | $catmenu[$category->id] = $category->name; |
8d94f5a0 |
931 | } |
6a952ce7 |
932 | $strcategory = get_string("category", "quiz"); |
933 | $strshow = get_string("show", "quiz"); |
6b069ece |
934 | $streditcats = get_string("editcategories", "quiz"); |
6a952ce7 |
935 | |
467aaec6 |
936 | echo "<TABLE width=\"100%\"><TR><TD NOWRAP>"; |
6a952ce7 |
937 | echo "<FORM METHOD=POST ACTION=edit.php>"; |
938 | echo "<B>$strcategory:</B> "; |
b55a466b |
939 | choose_from_menu($catmenu, "cat", "$current"); |
92a3c884 |
940 | echo "<INPUT TYPE=submit VALUE=\"$strshow\">"; |
6a952ce7 |
941 | echo "</FORM>"; |
6b069ece |
942 | echo "</TD><TD align=right>"; |
943 | echo "<FORM METHOD=GET ACTION=category.php>"; |
944 | echo "<INPUT TYPE=hidden NAME=id VALUE=\"$course->id\">"; |
945 | echo "<INPUT TYPE=submit VALUE=\"$streditcats\">"; |
946 | echo "</FORM>"; |
947 | echo "</TD></TR></TABLE>"; |
6a952ce7 |
948 | } |
949 | |
950 | |
34d52ad7 |
951 | |
7bfa4fad |
952 | function quiz_choose_random_questions($category, $draws, $excluded=0) { |
34d52ad7 |
953 | /// Given a question category and a number of draws, this function |
954 | /// creates a random subset of that size - returned as an array of questions |
955 | |
956 | if (!$pool = get_records_select_menu("quiz_questions", |
575de48f |
957 | "category = '$category' AND id NOT IN ($excluded) |
958 | AND qtype <> ".RANDOM." |
959 | AND qtype <> ".DESCRIPTION, |
960 | "", "id,qtype")) { |
34d52ad7 |
961 | return false; |
962 | } |
963 | |
964 | $countpool = count($pool); |
965 | |
966 | if ($countpool == $draws) { |
967 | $chosen = $pool; |
968 | } else if ($countpool < $draws) { |
969 | return false; |
970 | } else { |
971 | $chosen = draw_rand_array($pool, $draws); |
972 | } |
973 | |
974 | $chosenlist = implode(",", array_keys($chosen)); |
975 | return get_records_list("quiz_questions", "id", $chosenlist); |
976 | } |
977 | |
978 | |
7bd1aa1d |
979 | function quiz_get_all_question_grades($questionlist, $quizid) { |
980 | // Given a list of question IDs, finds grades or invents them to |
981 | // create an array of matching grades |
982 | |
5a25f84d |
983 | if (empty($questionlist)) { |
984 | return array(); |
985 | } |
986 | |
bdc23be0 |
987 | $questions = quiz_get_question_grades($quizid, $questionlist); |
7bd1aa1d |
988 | |
989 | $list = explode(",", $questionlist); |
990 | $grades = array(); |
991 | |
992 | foreach ($list as $qid) { |
993 | if (isset($questions[$qid])) { |
994 | $grades[$qid] = $questions[$qid]->grade; |
995 | } else { |
996 | $grades[$qid] = 1; |
997 | } |
998 | } |
999 | return $grades; |
1000 | } |
1001 | |
1002 | |
1003 | function quiz_print_question_list($questionlist, $grades) { |
6a952ce7 |
1004 | // Prints a list of quiz questions in a small layout form with knobs |
7bd1aa1d |
1005 | // $questionlist is comma-separated list |
1006 | // $grades is an array of corresponding grades |
6a952ce7 |
1007 | |
1008 | global $THEME; |
1009 | |
1010 | if (!$questionlist) { |
1011 | echo "<P align=center>"; |
1012 | print_string("noquestions", "quiz"); |
1013 | echo "</P>"; |
1014 | return; |
1015 | } |
1016 | |
1017 | $order = explode(",", $questionlist); |
1018 | |
7bd1aa1d |
1019 | if (!$questions = get_records_list("quiz_questions", "id", $questionlist)) { |
9a652ddb |
1020 | echo "<P align=center>"; |
1021 | print_string("noquestions", "quiz"); |
1022 | echo "</P>"; |
1023 | return; |
1024 | |
6a952ce7 |
1025 | } |
1026 | |
1027 | $strorder = get_string("order"); |
1028 | $strquestionname = get_string("questionname", "quiz"); |
1029 | $strgrade = get_string("grade"); |
1030 | $strdelete = get_string("delete"); |
1031 | $stredit = get_string("edit"); |
1032 | $strmoveup = get_string("moveup"); |
1033 | $strmovedown = get_string("movedown"); |
1034 | $strsavegrades = get_string("savegrades", "quiz"); |
c74a0ca5 |
1035 | $strtype = get_string("type", "quiz"); |
6a952ce7 |
1036 | |
10b9291c |
1037 | for ($i=10; $i>=0; $i--) { |
7bd1aa1d |
1038 | $gradesmenu[$i] = $i; |
6a952ce7 |
1039 | } |
1040 | $count = 0; |
1041 | $sumgrade = 0; |
1042 | $total = count($order); |
1043 | echo "<FORM METHOD=post ACTION=edit.php>"; |
1044 | echo "<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=2 WIDTH=\"100%\">"; |
467aaec6 |
1045 | echo "<TR><TH WIDTH=\"*\" COLSPAN=3 NOWRAP>$strorder</TH><TH align=left WIDTH=\"100%\" NOWRAP>$strquestionname</TH><TH width=\"*\" NOWRAP>$strtype</TH><TH WIDTH=\"*\" NOWRAP>$strgrade</TH><TH WIDTH=\"*\" NOWRAP>$stredit</TH></TR>"; |
6a952ce7 |
1046 | foreach ($order as $qnum) { |
95dbc030 |
1047 | if (empty($questions[$qnum])) { |
1048 | continue; |
1049 | } |
bca64a12 |
1050 | $question = $questions[$qnum]; |
6a952ce7 |
1051 | $count++; |
1052 | echo "<TR BGCOLOR=\"$THEME->cellcontent\">"; |
1053 | echo "<TD>$count</TD>"; |
1054 | echo "<TD>"; |
1055 | if ($count != 1) { |
1056 | echo "<A TITLE=\"$strmoveup\" HREF=\"edit.php?up=$qnum\"><IMG |
1057 | SRC=\"../../pix/t/up.gif\" BORDER=0></A>"; |
1058 | } |
1059 | echo "</TD>"; |
1060 | echo "<TD>"; |
1061 | if ($count != $total) { |
1062 | echo "<A TITLE=\"$strmovedown\" HREF=\"edit.php?down=$qnum\"><IMG |
1063 | SRC=\"../../pix/t/down.gif\" BORDER=0></A>"; |
1064 | } |
1065 | echo "</TD>"; |
bca64a12 |
1066 | echo "<TD>$question->name</TD>"; |
467aaec6 |
1067 | echo "<TD ALIGN=CENTER>"; |
bca64a12 |
1068 | quiz_print_question_icon($question); |
c74a0ca5 |
1069 | echo "</TD>"; |
6a952ce7 |
1070 | echo "<TD>"; |
bca64a12 |
1071 | if ($question->qtype == DESCRIPTION) { |
1072 | echo "<INPUT TYPE=hidden NAME=q$qnum VALUE=\"0\"> "; |
1073 | } else { |
1074 | choose_from_menu($gradesmenu, "q$qnum", (string)$grades[$qnum], ""); |
1075 | } |
6a952ce7 |
1076 | echo "<TD>"; |
1077 | echo "<A TITLE=\"$strdelete\" HREF=\"edit.php?delete=$qnum\"><IMG |
1078 | SRC=\"../../pix/t/delete.gif\" BORDER=0></A> "; |
1079 | echo "<A TITLE=\"$stredit\" HREF=\"question.php?id=$qnum\"><IMG |
1080 | SRC=\"../../pix/t/edit.gif\" BORDER=0></A>"; |
1081 | echo "</TD>"; |
1082 | |
7bd1aa1d |
1083 | $sumgrade += $grades[$qnum]; |
6a952ce7 |
1084 | } |
c74a0ca5 |
1085 | echo "<TR><TD COLSPAN=5 ALIGN=right>"; |
6a952ce7 |
1086 | echo "<INPUT TYPE=submit VALUE=\"$strsavegrades:\">"; |
8d94f5a0 |
1087 | echo "<INPUT TYPE=hidden NAME=setgrades VALUE=\"save\">"; |
6a952ce7 |
1088 | echo "<TD ALIGN=LEFT BGCOLOR=\"$THEME->cellcontent\">"; |
1089 | echo "<B>$sumgrade</B>"; |
1090 | echo "</TD><TD></TD></TR>"; |
1091 | echo "</TABLE>"; |
1092 | echo "</FORM>"; |
10b9291c |
1093 | |
1094 | return $sumgrade; |
6a952ce7 |
1095 | } |
1096 | |
1097 | |
1098 | function quiz_print_cat_question_list($categoryid) { |
1099 | // Prints a form to choose categories |
1100 | |
1101 | global $THEME, $QUIZ_QUESTION_TYPE; |
1102 | |
10b9291c |
1103 | $strcategory = get_string("category", "quiz"); |
6a952ce7 |
1104 | $strquestion = get_string("question", "quiz"); |
49220fa7 |
1105 | $straddquestions = get_string("addquestions", "quiz"); |
1106 | $strimportquestions = get_string("importquestions", "quiz"); |
6a952ce7 |
1107 | $strnoquestions = get_string("noquestions", "quiz"); |
1108 | $strselect = get_string("select", "quiz"); |
a01b2571 |
1109 | $strselectall = get_string("selectall", "quiz"); |
6a952ce7 |
1110 | $strcreatenewquestion = get_string("createnewquestion", "quiz"); |
1111 | $strquestionname = get_string("questionname", "quiz"); |
1112 | $strdelete = get_string("delete"); |
1113 | $stredit = get_string("edit"); |
1114 | $straddselectedtoquiz = get_string("addselectedtoquiz", "quiz"); |
c74a0ca5 |
1115 | $strtype = get_string("type", "quiz"); |
c6eed097 |
1116 | $strcreatemultiple = get_string("createmultiple", "quiz"); |
6a952ce7 |
1117 | |
1118 | if (!$categoryid) { |
5325f8b8 |
1119 | echo "<p align=center><b>"; |
6a952ce7 |
1120 | print_string("selectcategoryabove", "quiz"); |
5325f8b8 |
1121 | echo "</b></p>"; |
1122 | echo "<p>"; |
1123 | print_string("addingquestions", "quiz"); |
1124 | echo "</p>"; |
6a952ce7 |
1125 | return; |
1126 | } |
a5e1f35c |
1127 | |
6a952ce7 |
1128 | if (!$category = get_record("quiz_categories", "id", "$categoryid")) { |
1129 | notify("Category not found!"); |
1130 | return; |
1131 | } |
8d94f5a0 |
1132 | echo "<CENTER>"; |
10b9291c |
1133 | echo text_to_html($category->info); |
6a952ce7 |
1134 | |
49220fa7 |
1135 | echo "<TABLE><TR>"; |
1136 | echo "<TD valign=top><B>$straddquestions:</B></TD>"; |
1137 | echo "<TD valign=top align=right>"; |
10b9291c |
1138 | echo "<FORM METHOD=GET ACTION=question.php>"; |
a2fe7cc0 |
1139 | choose_from_menu($QUIZ_QUESTION_TYPE, "qtype", "", ""); |
6a952ce7 |
1140 | echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">"; |
7d2e5b65 |
1141 | echo "<INPUT TYPE=submit VALUE=\"$strcreatenewquestion\">"; |
cd63d77e |
1142 | helpbutton("questiontypes", $strcreatenewquestion, "quiz"); |
6a952ce7 |
1143 | echo "</FORM>"; |
49220fa7 |
1144 | |
1145 | echo "<FORM METHOD=GET ACTION=import.php>"; |
1146 | echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">"; |
1147 | echo "<INPUT TYPE=submit VALUE=\"$strimportquestions\">"; |
1148 | helpbutton("import", $strimportquestions, "quiz"); |
1149 | echo "</FORM>"; |
1150 | |
c6eed097 |
1151 | echo "<FORM METHOD=GET ACTION=multiple.php>"; |
1152 | echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">"; |
1153 | echo "<INPUT TYPE=submit VALUE=\"$strcreatemultiple\">"; |
1154 | helpbutton("createmultiple", $strcreatemultiple, "quiz"); |
1155 | echo "</FORM>"; |
1156 | |
49220fa7 |
1157 | echo "</TR></TABLE>"; |
1158 | |
8d94f5a0 |
1159 | echo "</CENTER>"; |
6a952ce7 |
1160 | |
14bdb238 |
1161 | if (!$questions = get_records("quiz_questions", "category", $category->id, "qtype ASC")) { |
6a952ce7 |
1162 | echo "<P align=center>"; |
1163 | print_string("noquestions", "quiz"); |
1164 | echo "</P>"; |
1165 | return; |
1166 | } |
1167 | |
10b9291c |
1168 | $canedit = isteacher($category->course); |
1169 | |
6a952ce7 |
1170 | echo "<FORM METHOD=post ACTION=edit.php>"; |
1171 | echo "<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=2 WIDTH=\"100%\">"; |
467aaec6 |
1172 | echo "<TR><TH width=\"*\" NOWRAP>$strselect</TH><TH width=\"100%\" align=left NOWRAP>$strquestionname</TH><TH WIDTH=\"*\" NOWRAP>$strtype</TH>"; |
10b9291c |
1173 | if ($canedit) { |
467aaec6 |
1174 | echo "<TH width=\"*\" NOWRAP>$stredit</TH>"; |
10b9291c |
1175 | } |
1176 | echo "</TR>"; |
6a952ce7 |
1177 | foreach ($questions as $question) { |
1178 | echo "<TR BGCOLOR=\"$THEME->cellcontent\">"; |
1179 | echo "<TD ALIGN=CENTER>"; |
1180 | echo "<INPUT TYPE=CHECKBOX NAME=q$question->id VALUE=\"1\">"; |
1181 | echo "</TD>"; |
1182 | echo "<TD>".$question->name."</TD>"; |
467aaec6 |
1183 | echo "<TD ALIGN=CENTER>"; |
c74a0ca5 |
1184 | quiz_print_question_icon($question); |
1185 | echo "</TD>"; |
10b9291c |
1186 | if ($canedit) { |
1187 | echo "<TD>"; |
e1c91df0 |
1188 | echo "<A TITLE=\"$strdelete\" HREF=\"question.php?id=$question->id&delete=$question->id\"><IMG |
10b9291c |
1189 | SRC=\"../../pix/t/delete.gif\" BORDER=0></A> "; |
1190 | echo "<A TITLE=\"$stredit\" HREF=\"question.php?id=$question->id\"><IMG |
1191 | SRC=\"../../pix/t/edit.gif\" BORDER=0></A>"; |
1192 | echo "</TD></TR>"; |
1193 | } |
1194 | echo "</TR>"; |
6a952ce7 |
1195 | } |
1196 | echo "<TR><TD COLSPAN=3>"; |
a01b2571 |
1197 | echo "<INPUT TYPE=submit NAME=add VALUE=\"<< $straddselectedtoquiz\">"; |
1198 | //echo "<INPUT TYPE=submit NAME=delete VALUE=\"XX Delete selected\">"; |
1199 | echo "<INPUT type=button onclick=\"checkall()\" value=\"$strselectall\">"; |
6a952ce7 |
1200 | echo "</TD></TR>"; |
1201 | echo "</TABLE>"; |
1202 | echo "</FORM>"; |
1203 | } |
a5e1f35c |
1204 | |
3a506ca2 |
1205 | |
958aafe2 |
1206 | function quiz_start_attempt($quizid, $userid, $numattempt) { |
1207 | $attempt->quiz = $quizid; |
ebc3bd2b |
1208 | $attempt->userid = $userid; |
958aafe2 |
1209 | $attempt->attempt = $numattempt; |
1210 | $attempt->timestart = time(); |
1211 | $attempt->timefinish = 0; |
1212 | $attempt->timemodified = time(); |
1213 | |
1214 | return insert_record("quiz_attempts", $attempt); |
1215 | } |
1216 | |
1217 | function quiz_get_user_attempt_unfinished($quizid, $userid) { |
1218 | // Returns an object containing an unfinished attempt (if there is one) |
ebc3bd2b |
1219 | return get_record("quiz_attempts", "quiz", $quizid, "userid", $userid, "timefinish", 0); |
958aafe2 |
1220 | } |
1221 | |
3a506ca2 |
1222 | function quiz_get_user_attempts($quizid, $userid) { |
a5e1f35c |
1223 | // Returns a list of all attempts by a user |
ebc3bd2b |
1224 | return get_records_select("quiz_attempts", "quiz = '$quizid' AND userid = '$userid' AND timefinish > 0", |
bdc23be0 |
1225 | "attempt ASC"); |
3a506ca2 |
1226 | } |
1227 | |
8d94f5a0 |
1228 | |
1229 | function quiz_get_user_attempts_string($quiz, $attempts, $bestgrade) { |
1230 | /// Returns a simple little comma-separated list of all attempts, |
6d86b5dc |
1231 | /// with each grade linked to the feedback report and with the best grade highlighted |
8d94f5a0 |
1232 | |
1233 | $bestgrade = format_float($bestgrade); |
1234 | foreach ($attempts as $attempt) { |
1235 | $attemptgrade = format_float(($attempt->sumgrades / $quiz->sumgrades) * $quiz->grade); |
1236 | if ($attemptgrade == $bestgrade) { |
29d5d0b4 |
1237 | $userattempts[] = "<span class=highlight><a href=\"review.php?q=$quiz->id&attempt=$attempt->id\">$attemptgrade</a></span>"; |
8d94f5a0 |
1238 | } else { |
29d5d0b4 |
1239 | $userattempts[] = "<a href=\"review.php?q=$quiz->id&attempt=$attempt->id\">$attemptgrade</a>"; |
8d94f5a0 |
1240 | } |
1241 | } |
1242 | return implode(",", $userattempts); |
1243 | } |
1244 | |
a5e1f35c |
1245 | function quiz_get_best_grade($quizid, $userid) { |
1246 | /// Get the best current grade for a particular user in a quiz |
ebc3bd2b |
1247 | if (!$grade = get_record("quiz_grades", "quiz", $quizid, "userid", $userid)) { |
3a506ca2 |
1248 | return 0; |
1249 | } |
1250 | |
2383cadb |
1251 | return (round($grade->grade,0)); |
3a506ca2 |
1252 | } |
1253 | |
e331eb06 |
1254 | function quiz_save_best_grade($quiz, $userid) { |
a5e1f35c |
1255 | /// Calculates the best grade out of all attempts at a quiz for a user, |
1256 | /// and then saves that grade in the quiz_grades table. |
1257 | |
e331eb06 |
1258 | if (!$attempts = quiz_get_user_attempts($quiz->id, $userid)) { |
e909c8d0 |
1259 | notify("Could not find any user attempts"); |
a5e1f35c |
1260 | return false; |
1261 | } |
1262 | |
1263 | $bestgrade = quiz_calculate_best_grade($quiz, $attempts); |
1264 | $bestgrade = (($bestgrade / $quiz->sumgrades) * $quiz->grade); |
1265 | |
ebc3bd2b |
1266 | if ($grade = get_record("quiz_grades", "quiz", $quiz->id, "userid", $userid)) { |
1d2603b1 |
1267 | $grade->grade = round($bestgrade, 2); |
a5e1f35c |
1268 | $grade->timemodified = time(); |
1269 | if (!update_record("quiz_grades", $grade)) { |
e909c8d0 |
1270 | notify("Could not update best grade"); |
a5e1f35c |
1271 | return false; |
1272 | } |
1273 | } else { |
1274 | $grade->quiz = $quiz->id; |
ebc3bd2b |
1275 | $grade->userid = $userid; |
38f03e5a |
1276 | $grade->grade = round($bestgrade, 2); |
a5e1f35c |
1277 | $grade->timemodified = time(); |
1278 | if (!insert_record("quiz_grades", $grade)) { |
e909c8d0 |
1279 | notify("Could not insert new best grade"); |
a5e1f35c |
1280 | return false; |
1281 | } |
1282 | } |
1283 | return true; |
1284 | } |
1285 | |
1286 | |
3a506ca2 |
1287 | function quiz_calculate_best_grade($quiz, $attempts) { |
a5e1f35c |
1288 | /// Calculate the best grade for a quiz given a number of attempts by a particular user. |
3a506ca2 |
1289 | |
1290 | switch ($quiz->grademethod) { |
a5e1f35c |
1291 | |
1292 | case ATTEMPTFIRST: |
3a506ca2 |
1293 | foreach ($attempts as $attempt) { |
a5e1f35c |
1294 | return $attempt->sumgrades; |
3a506ca2 |
1295 | } |
a5e1f35c |
1296 | break; |
1297 | |
1298 | case ATTEMPTLAST: |
1299 | foreach ($attempts as $attempt) { |
1300 | $final = $attempt->sumgrades; |
1301 | } |
1302 | return $final; |
3a506ca2 |
1303 | |
a5e1f35c |
1304 | case GRADEAVERAGE: |
3a506ca2 |
1305 | $sum = 0; |
1306 | $count = 0; |
1307 | foreach ($attempts as $attempt) { |
a5e1f35c |
1308 | $sum += $attempt->sumgrades; |
3a506ca2 |
1309 | $count++; |
1310 | } |
1311 | return (float)$sum/$count; |
1312 | |
3a506ca2 |
1313 | default: |
a5e1f35c |
1314 | case GRADEHIGHEST: |
1315 | $max = 0; |
3a506ca2 |
1316 | foreach ($attempts as $attempt) { |
a5e1f35c |
1317 | if ($attempt->sumgrades > $max) { |
1318 | $max = $attempt->sumgrades; |
1319 | } |
3a506ca2 |
1320 | } |
a5e1f35c |
1321 | return $max; |
1322 | } |
1323 | } |
1324 | |
34d52ad7 |
1325 | |
40b1a221 |
1326 | function quiz_calculate_best_attempt($quiz, $attempts) { |
1327 | /// Return the attempt with the best grade for a quiz |
1328 | |
1329 | switch ($quiz->grademethod) { |
1330 | |
1331 | case ATTEMPTFIRST: |
1332 | foreach ($attempts as $attempt) { |
1333 | return $attempt; |
1334 | } |
1335 | break; |
1336 | |
1337 | case GRADEAVERAGE: // need to do something with it :-) |
1338 | case ATTEMPTLAST: |
1339 | foreach ($attempts as $attempt) { |
1340 | $final = $attempt; |
1341 | } |
1342 | return $final; |
1343 | |
1344 | default: |
1345 | case GRADEHIGHEST: |
1346 | $max = -1; |
1347 | foreach ($attempts as $attempt) { |
1348 | if ($attempt->sumgrades > $max) { |
1349 | $max = $attempt->sumgrades; |
1350 | $maxattempt = $attempt; |
1351 | } |
1352 | } |
1353 | return $maxattempt; |
1354 | } |
1355 | } |
1356 | |
1357 | |
a5e1f35c |
1358 | function quiz_save_attempt($quiz, $questions, $result, $attemptnum) { |
1359 | /// Given a quiz, a list of attempted questions and a total grade |
1360 | /// this function saves EVERYTHING so it can be reconstructed later |
1361 | /// if necessary. |
1362 | |
1363 | global $USER; |
1364 | |
958aafe2 |
1365 | // First find the attempt in the database (start of attempt) |
1366 | |
1367 | if (!$attempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) { |
1368 | notify("Trying to save an attempt that was not started!"); |
1369 | return false; |
1370 | } |
1371 | |
1372 | if ($attempt->attempt != $attemptnum) { // Double check. |
1373 | notify("Number of this attempt is different to the unfinished one!"); |
1374 | return false; |
1375 | } |
1376 | |
1377 | // Now let's complete this record and save it |
a5e1f35c |
1378 | |
a5e1f35c |
1379 | $attempt->sumgrades = $result->sumgrades; |
958aafe2 |
1380 | $attempt->timefinish = time(); |
a5e1f35c |
1381 | $attempt->timemodified = time(); |
1382 | |
958aafe2 |
1383 | if (! update_record("quiz_attempts", $attempt)) { |
7520988b |
1384 | notify("Error while saving attempt"); |
a5e1f35c |
1385 | return false; |
1386 | } |
1387 | |
1388 | // Now let's save all the questions for this attempt |
1389 | |
1390 | foreach ($questions as $question) { |
1391 | $response->attempt = $attempt->id; |
1392 | $response->question = $question->id; |
1393 | $response->grade = $result->grades[$question->id]; |
34d52ad7 |
1394 | |
77cff589 |
1395 | if (!empty($question->random)) { |
34d52ad7 |
1396 | // First save the response of the random question |
1397 | // the answer is the id of the REAL response |
1398 | $response->answer = $question->random; |
1399 | if (!insert_record("quiz_responses", $response)) { |
1400 | notify("Error while saving response"); |
1401 | return false; |
1402 | } |
1403 | $response->question = $question->random; |
1404 | } |
1405 | |
54d0590b |
1406 | if (!empty($question->answer)) { |
a5e1f35c |
1407 | $response->answer = implode(",",$question->answer); |
1408 | } else { |
1409 | $response->answer = ""; |
1410 | } |
1411 | if (!insert_record("quiz_responses", $response)) { |
7520988b |
1412 | notify("Error while saving response"); |
a5e1f35c |
1413 | return false; |
1414 | } |
3a506ca2 |
1415 | } |
a5e1f35c |
1416 | return true; |
3a506ca2 |
1417 | } |
730fd187 |
1418 | |
a5e1f35c |
1419 | |
1420 | function quiz_grade_attempt_results($quiz, $questions) { |
1421 | /// Given a list of questions (including answers for each one) |
1422 | /// this function does all the hard work of calculating the |
1423 | /// grades for each question, as well as a total grade for |
1424 | /// for the whole quiz. It returns everything in a structure |
1425 | /// that looks like: |
1426 | /// $result->sumgrades (sum of all grades for all questions) |
1427 | /// $result->percentage (Percentage of grades that were correct) |
1428 | /// $result->grade (final grade result for the whole quiz) |
1429 | /// $result->grades[] (array of grades, indexed by question id) |
a8a372cc |
1430 | /// $result->response[] (array of response arrays, indexed by question id) |
a5e1f35c |
1431 | /// $result->feedback[] (array of feedback arrays, indexed by question id) |
8db3eadd |
1432 | /// $result->correct[] (array of feedback arrays, indexed by question id) |
a5e1f35c |
1433 | |
1434 | if (!$questions) { |
1435 | error("No questions!"); |
1436 | } |
34d52ad7 |
1437 | |
1438 | if (!$grades = get_records_menu("quiz_question_grades", "quiz", $quiz->id, "", "question,grade")) { |
1439 | error("No grades defined for these quiz questions!"); |
1440 | } |
1441 | |
a5e1f35c |
1442 | $result->sumgrades = 0; |
1443 | |
1444 | foreach ($questions as $question) { |
34d52ad7 |
1445 | |
1446 | if (!empty($question->random)) { // This question has been randomly chosen |
1447 | $randomquestion = $question; // Save it for later |
1448 | if (!$question = get_record("quiz_questions", "id", $question->random)) { |
1449 | error("Could not find the real question behind this random question!"); |
1450 | } |
61367e64 |
1451 | if (isset($randomquestion->answer)) { |
1452 | $question->answer = $randomquestion->answer; |
1453 | } else { |
1454 | $question->answer = ""; |
1455 | } |
34d52ad7 |
1456 | $question->grade = $grades[$randomquestion->id]; |
1457 | } else { |
1458 | $question->grade = $grades[$question->id]; |
1459 | } |
1460 | |
401c8de6 |
1461 | if ($question->qtype != DESCRIPTION) { // All real questions need answers defined |
1462 | if (!$answers = quiz_get_answers($question)) { |
1463 | error("No answers defined for question id $question->id!"); |
1464 | } |
a5e1f35c |
1465 | } |
1466 | |
1467 | $grade = 0; // default |
34d52ad7 |
1468 | $correct = array(); |
19c4f55c |
1469 | $feedback = array(); |
1470 | $response = array(); |
a5e1f35c |
1471 | |
a2fe7cc0 |
1472 | switch ($question->qtype) { |
a5e1f35c |
1473 | case SHORTANSWER: |
1474 | if ($question->answer) { |
41b95af2 |
1475 | $question->answer = trim(stripslashes($question->answer[0])); |
a5e1f35c |
1476 | } else { |
19c4f55c |
1477 | $question->answer = ""; |
a5e1f35c |
1478 | } |
a8a372cc |
1479 | $response[0] = $question->answer; |
a2fe7cc0 |
1480 | $bestshortanswer = 0; |
361f649d |
1481 | foreach ($answers as $answer) { // There might be multiple right answers |
8db3eadd |
1482 | if ($answer->fraction > $bestshortanswer) { |
1483 | $correct[$answer->id] = $answer->answer; |
a2fe7cc0 |
1484 | $bestshortanswer = $answer->fraction; |
8db3eadd |
1485 | } |
2a2c9725 |
1486 | if (!$answer->usecase) { // Don't compare case |
a5e1f35c |
1487 | $answer->answer = strtolower($answer->answer); |
1488 | $question->answer = strtolower($question->answer); |
1489 | } |
1490 | if ($question->answer == $answer->answer) { |
a8a372cc |
1491 | $feedback[0] = $answer->feedback; |
34d52ad7 |
1492 | $grade = (float)$answer->fraction * $question->grade; |
a5e1f35c |
1493 | } |
1494 | } |
1495 | break; |
1496 | |
361f649d |
1497 | case NUMERICAL: |
1498 | if ($question->answer) { |
1499 | $question->answer = trim(stripslashes($question->answer[0])); |
1500 | } else { |
1501 | $question->answer = ""; |
1502 | } |
1503 | $response[0] = $question->answer; |
1504 | $bestshortanswer = 0; |
1505 | foreach ($answers as $answer) { // There might be multiple right answers |
1506 | if ($answer->fraction > $bestshortanswer) { |
1507 | $correct[$answer->id] = $answer->answer; |
1508 | $bestshortanswer = $answer->fraction; |
1509 | } |
1510 | if ( ((float)$question->answer >= (float)$answer->min) and |
1511 | ((float)$question->answer <= (float)$answer->max) ) { |
1512 | $feedback[0] = $answer->feedback; |
1513 | $grade = (float)$answer->fraction * $question->grade; |
1514 | } |
1515 | } |
1516 | break; |
a5e1f35c |
1517 | |
1518 | case TRUEFALSE: |
1519 | if ($question->answer) { |
1520 | $question->answer = $question->answer[0]; |
1521 | } else { |
1522 | $question->answer = NULL; |
1523 | } |
1524 | foreach($answers as $answer) { // There should be two answers (true and false) |
1525 | $feedback[$answer->id] = $answer->feedback; |
8db3eadd |
1526 | if ($answer->fraction > 0) { |
1527 | $correct[$answer->id] = true; |
1528 | } |
a5e1f35c |
1529 | if ($question->answer == $answer->id) { |
34d52ad7 |
1530 | $grade = (float)$answer->fraction * $question->grade; |
a8a372cc |
1531 | $response[$answer->id] = true; |
a5e1f35c |
1532 | } |
1533 | } |
1534 | break; |
1535 | |
1536 | |
1537 | case MULTICHOICE: |
1538 | foreach($answers as $answer) { // There will be multiple answers, perhaps more than one is right |
1539 | $feedback[$answer->id] = $answer->feedback; |
8db3eadd |
1540 | if ($answer->fraction > 0) { |
1541 | $correct[$answer->id] = true; |
1542 | } |
54d0590b |
1543 | if (!empty($question->answer)) { |
a5e1f35c |
1544 | foreach ($question->answer as $questionanswer) { |
1545 | if ($questionanswer == $answer->id) { |
95dbc030 |
1546 | $response[$answer->id] = true; |
a5e1f35c |
1547 | if ($answer->single) { |
34d52ad7 |
1548 | $grade = (float)$answer->fraction * $question->grade; |
a5e1f35c |
1549 | continue; |
1550 | } else { |
34d52ad7 |
1551 | $grade += (float)$answer->fraction * $question->grade; |
a5e1f35c |
1552 | } |
1553 | } |
1554 | } |
1555 | } |
1556 | } |
1557 | break; |
95dbc030 |
1558 | |
54a67a59 |
1559 | case MATCH: |
1560 | $matchcount = $totalcount = 0; |
1561 | |
34d52ad7 |
1562 | foreach ($question->answer as $questionanswer) { // Each answer is "subquestionid-answerid" |
54a67a59 |
1563 | $totalcount++; |
34d52ad7 |
1564 | $qarr = explode('-', $questionanswer); // Extract subquestion/answer. |
1565 | $subquestionid = $qarr[0]; |
1566 | $subanswerid = $qarr[1]; |
e1122620 |
1567 | if ($subquestionid and $subanswerid and (($subquestionid == $subanswerid) or |
1568 | ($answers[$subquestionid]->answertext == $answers[$subanswerid]->answertext))) { |
34d52ad7 |
1569 | // Either the ids match exactly, or the answertexts match exactly |
1570 | // (in case two subquestions had the same answer) |
54a67a59 |
1571 | $matchcount++; |
34d52ad7 |
1572 | $correct[$subquestionid] = true; |
54a67a59 |
1573 | } else { |
34d52ad7 |
1574 | $correct[$subquestionid] = false; |
54a67a59 |
1575 | } |
34d52ad7 |
1576 | $response[$subquestionid] = $subanswerid; |
54a67a59 |
1577 | } |
1578 | |
34d52ad7 |
1579 | $grade = $question->grade * $matchcount / $totalcount; |
54a67a59 |
1580 | |
1581 | break; |
1582 | |
1583 | case RANDOMSAMATCH: |
95dbc030 |
1584 | $bestanswer = array(); |
1585 | foreach ($answers as $answer) { // Loop through them all looking for correct answers |
1586 | if (empty($bestanswer[$answer->question])) { |
1587 | $bestanswer[$answer->question] = 0; |
1588 | $correct[$answer->question] = ""; |
1589 | } |
1590 | if ($answer->fraction > $bestanswer[$answer->question]) { |
1591 | $bestanswer[$answer->question] = $answer->fraction; |
1592 | $correct[$answer->question] = $answer->answer; |
1593 | } |
1594 | } |
1595 | $answerfraction = 1.0 / (float) count($question->answer); |
1596 | foreach ($question->answer as $questionanswer) { // For each random answered question |
1597 | $rqarr = explode('-', $questionanswer); // Extract question/answer. |
1598 | $rquestion = $rqarr[0]; |
1599 | $ranswer = $rqarr[1]; |
1600 | $response[$rquestion] = $questionanswer; |
1601 | if (isset($answers[$ranswer])) { // If the answer exists in the list |
1602 | $answer = $answers[$ranswer]; |
1603 | $feedback[$rquestion] = $answer->feedback; |
1604 | if ($answer->question == $rquestion) { // Check that this answer matches the question |
34d52ad7 |
1605 | $grade += (float)$answer->fraction * $question->grade * $answerfraction; |
95dbc030 |
1606 | } |
1607 | } |
1608 | } |
8db3eadd |
1609 | break; |
a5e1f35c |
1610 | |
a5e1f35c |
1611 | } |
34d52ad7 |
1612 | |
1613 | if (!empty($randomquestion)) { // This question has been randomly chosen |
1614 | $question = $randomquestion; // Restore the question->id |
1615 | unset($randomquestion); |
1616 | } |
1617 | |
a5e1f35c |
1618 | if ($grade < 0.0) { // No negative grades |
1619 | $grade = 0.0; |
1620 | } |
10b9291c |
1621 | |
3a50203f |
1622 | $result->grades[$question->id] = round($grade, 2); |
a5e1f35c |
1623 | $result->sumgrades += $grade; |
1624 | $result->feedback[$question->id] = $feedback; |
a8a372cc |
1625 | $result->response[$question->id] = $response; |
8db3eadd |
1626 | $result->correct[$question->id] = $correct; |
a5e1f35c |
1627 | } |
1628 | |
8d94f5a0 |
1629 | $fraction = (float)($result->sumgrades / $quiz->sumgrades); |
1630 | $result->percentage = format_float($fraction * 100.0); |
1631 | $result->grade = format_float($fraction * $quiz->grade); |
3a50203f |
1632 | $result->sumgrades = round($result->sumgrades, 2); |
a5e1f35c |
1633 | |
1634 | return $result; |
1635 | } |
6d86b5dc |
1636 | |
1637 | |
49220fa7 |
1638 | function quiz_save_question_options($question) { |
1639 | /// Given some question info and some data about the the answers |
1640 | /// this function parses, organises and saves the question |
1641 | /// It is used by question.php when saving new data from a |
1642 | /// form, and also by import.php when importing questions |
77cff589 |
1643 | /// |
1644 | /// If this is an update, and old answers already exist, then |
1645 | /// these are overwritten using an update(). To do this, it |
1646 | /// it is assumed that the IDs in quiz_answers are in the same |
1647 | /// sort order as the new answers being saved. This should always |
1648 | /// be true, but it's something to keep in mind if fiddling with |
1649 | /// question.php |
49220fa7 |
1650 | /// |
1651 | /// Returns $result->error or $result->notice |
a5e1f35c |
1652 | |
49220fa7 |
1653 | switch ($question->qtype) { |
1654 | case SHORTANSWER: |
77cff589 |
1655 | |
e1122620 |
1656 | if (!$oldanswers = get_records("quiz_answers", "question", $question->id, "id ASC")) { |
1657 | $oldanswers = array(); |
1658 | } |
49220fa7 |
1659 | |
1660 | $answers = array(); |
1661 | $maxfraction = -1; |
1662 | |
1663 | // Insert all the new answers |
1664 | foreach ($question->answer as $key => $dataanswer) { |
1665 | if ($dataanswer != "") { |
77cff589 |
1666 | if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it |
1667 | $answer = $oldanswer; |
1668 | $answer->answer = $dataanswer; |
1669 | $answer->fraction = $question->fraction[$key]; |
1670 | $answer->feedback = $question->feedback[$key]; |
1671 | if (!update_record("quiz_answers", $answer)) { |
1672 | $result->error = "Could not update quiz answer! (id=$answer->id)"; |
1673 | return $result; |
1674 | } |
1675 | } else { // This is a completely new answer |
1676 | unset($answer); |
1677 | $answer->answer = $dataanswer; |
1678 | $answer->question = $question->id; |
1679 | $answer->fraction = $question->fraction[$key]; |
1680 | $answer->feedback = $question->feedback[$key]; |
1681 | if (!$answer->id = insert_record("quiz_answers", $answer)) { |
1682 | $result->error = "Could not insert quiz answer!"; |
1683 | return $result; |
1684 | } |
49220fa7 |
1685 | } |
1686 | $answers[] = $answer->id; |
1687 | if ($question->fraction[$key] > $maxfraction) { |
1688 | $maxfraction = $question->fraction[$key]; |
1689 | } |
1690 | } |
1691 | } |
1692 | |
77cff589 |
1693 | if ($options = get_record("quiz_shortanswer", "question", $question->id)) { |
1694 | $options->answers = implode(",",$answers); |
1695 | $options->usecase = $question->usecase; |
1696 | if (!update_record("quiz_shortanswer", $options)) { |
1697 | $result->error = "Could not update quiz shortanswer options! (id=$options->id)"; |
1698 | return $result; |
1699 | } |
1700 | } else { |
1701 | unset($options); |
1702 | $options->question = $question->id; |
1703 | $options->answers = implode(",",$answers); |
1704 | $options->usecase = $question->usecase; |
1705 | if (!insert_record("quiz_shortanswer", $options)) { |
1706 | $result->error = "Could not insert quiz shortanswer options!"; |
1707 | return $result; |
1708 | } |
49220fa7 |
1709 | } |
1710 | |
1711 | /// Perform sanity checks on fractional grades |
1712 | if ($maxfraction != 1) { |
1713 | $maxfraction = $maxfraction * 100; |
1714 | $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); |
1715 | return $result; |
1716 | } |
1717 | break; |
77cff589 |
1718 | |
361f649d |
1719 | case NUMERICAL: // Note similarities to SHORTANSWER |
1720 | |
1721 | if (!$oldanswers = get_records("quiz_answers", "question", $question->id, "id ASC")) { |
1722 | $oldanswers = array(); |
1723 | } |
1724 | |
1725 | $answers = array(); |
1726 | $maxfraction = -1; |
1727 | |
1728 | // Insert all the new answers |
1729 | foreach ($question->answer as $key => $dataanswer) { |
1730 | if ($dataanswer != "") { |
1731 | if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it |
1732 | $answer = $oldanswer; |
1733 | $answer->answer = $dataanswer; |
1734 | $answer->fraction = $question->fraction[$key]; |
1735 | $answer->feedback = $question->feedback[$key]; |
1736 | if (!update_record("quiz_answers", $answer)) { |
1737 | $result->error = "Could not update quiz answer! (id=$answer->id)"; |
1738 | return $result; |
1739 | } |
1740 | } else { // This is a completely new answer |
1741 | unset($answer); |
1742 | $answer->answer = $dataanswer; |
1743 | $answer->question = $question->id; |
1744 | $answer->fraction = $question->fraction[$key]; |
1745 | $answer->feedback = $question->feedback[$key]; |
1746 | if (!$answer->id = insert_record("quiz_answers", $answer)) { |
1747 | $result->error = "Could not insert quiz answer!"; |
1748 | return $result; |
1749 | } |
1750 | } |
1751 | $answers[] = $answer->id; |
1752 | if ($question->fraction[$key] > $maxfraction) { |
1753 | $maxfraction = $question->fraction[$key]; |
1754 | } |
1755 | |
1756 | if ($options = get_record("quiz_numerical", "answer", $answer->id)) { |
1757 | $options->min= $question->min[$key]; |
1758 | $options->max= $question->max[$key]; |
1759 | if (!update_record("quiz_numerical", $options)) { |
1760 | $result->error = "Could not update quiz numerical options! (id=$options->id)"; |
1761 | return $result; |
1762 | } |
1763 | } else { // completely new answer |
1764 | unset($options); |
9c026610 |
1765 | $options->question = $question->id; |
1766 | $options->answer = $answer->id; |
1767 | $options->min = $question->min[$key]; |
1768 | $options->max = $question->max[$key]; |
361f649d |
1769 | if (!insert_record("quiz_numerical", $options)) { |
1770 | $result->error = "Could not insert quiz numerical options!"; |
1771 | return $result; |
1772 | } |
1773 | } |
1774 | } |
1775 | } |
1776 | |
1777 | /// Perform sanity checks on fractional grades |
1778 | if ($maxfraction != 1) { |
1779 | $maxfraction = $maxfraction * 100; |
1780 | $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); |
1781 | return $result; |
1782 | } |
1783 | break; |
77cff589 |
1784 | |
1785 | |
49220fa7 |
1786 | case TRUEFALSE: |
77cff589 |
1787 | |
e1122620 |
1788 | if (!$oldanswers = get_records("quiz_answers", "question", $question->id, "id ASC")) { |
1789 | $oldanswers = array(); |
1790 | } |
77cff589 |
1791 | |
1792 | if ($true = array_shift($oldanswers)) { // Existing answer, so reuse it |
4d01ada3 |
1793 | $true->answer = get_string("true", "quiz"); |
77cff589 |
1794 | $true->fraction = $question->answer; |
1795 | $true->feedback = $question->feedbacktrue; |
1796 | if (!update_record("quiz_answers", $true)) { |
1797 | $result->error = "Could not update quiz answer \"true\")!"; |
1798 | return $result; |
1799 | } |
1800 | } else { |
1801 | unset($true); |
4d01ada3 |
1802 | $true->answer = get_string("true", "quiz"); |
77cff589 |
1803 | $true->question = $question->id; |
1804 | $true->fraction = $question->answer; |
1805 | $true->feedback = $question->feedbacktrue; |
1806 | if (!$true->id = insert_record("quiz_answers", $true)) { |
1807 | $result->error = "Could not insert quiz answer \"true\")!"; |
1808 | return $result; |
1809 | } |
49220fa7 |
1810 | } |
1811 | |
77cff589 |
1812 | if ($false = array_shift($oldanswers)) { // Existing answer, so reuse it |
4d01ada3 |
1813 | $false->answer = get_string("false", "quiz"); |
77cff589 |
1814 | $false->fraction = 1 - (int)$question->answer; |
1815 | $false->feedback = $question->feedbackfalse; |
1816 | if (!update_record("quiz_answers", $false)) { |
1817 | $result->error = "Could not insert quiz answer \"false\")!"; |
1818 | return $result; |
1819 | } |
1820 | } else { |
1821 | unset($false); |
4d01ada3 |
1822 | $false->answer = get_string("false", "quiz"); |
77cff589 |
1823 | $false->question = $question->id; |
1824 | $false->fraction = 1 - (int)$question->answer; |
1825 | $false->feedback = $question->feedbackfalse; |
1826 | if (!$false->id = insert_record("quiz_answers", $false)) { |
1827 | $result->error = "Could not insert quiz answer \"false\")!"; |
1828 | return $result; |
1829 | } |
49220fa7 |
1830 | } |
1831 | |
77cff589 |
1832 | if ($options = get_record("quiz_truefalse", "question", $question->id)) { |
1833 | // No need to do anything, since the answer IDs won't have changed |
1834 | // But we'll do it anyway, just for robustness |
1835 | $options->trueanswer = $true->id; |
1836 | $options->falseanswer = $false->id; |
1837 | if (!update_record("quiz_truefalse", $options)) { |
1838 | $result->error = "Could not update quiz truefalse options! (id=$options->id)"; |
1839 | return $result; |
1840 | } |
1841 | } else { |
1842 | unset($options); |
1843 | $options->question = $question->id; |
1844 | $options->trueanswer = $true->id; |
1845 | $options->falseanswer = $false->id; |
1846 | if (!insert_record("quiz_truefalse", $options)) { |
1847 | $result->error = "Could not insert quiz truefalse options!"; |
1848 | return $result; |
1849 | } |
49220fa7 |
1850 | } |
1851 | break; |
77cff589 |
1852 | |
1853 | |
49220fa7 |
1854 | case MULTICHOICE: |
77cff589 |
1855 | |
e1122620 |
1856 | if (!$oldanswers = get_records("quiz_answers", "question", $question->id, "id ASC")) { |
1857 | $oldanswers = array(); |
1858 | } |
49220fa7 |
1859 | |
1860 | $totalfraction = 0; |
1861 | $maxfraction = -1; |
1862 | |
1863 | $answers = array(); |
1864 | |
1865 | // Insert all the new answers |
1866 | foreach ($question->answer as $key => $dataanswer) { |
1867 | if ($dataanswer != "") { |
77cff589 |
1868 | if ($answer = array_shift($oldanswers)) { // Existing answer, so reuse it |
1869 | $answer->answer = $dataanswer; |
1870 | $answer->fraction = $question->fraction[$key]; |
1871 | $answer->feedback = $question->feedback[$key]; |
1872 | if (!update_record("quiz_answers", $answer)) { |
1873 | $result->error = "Could not update quiz answer! (id=$answer->id)"; |
1874 | return $result; |
1875 | } |
1876 | } else { |
1877 | unset($answer); |
1878 | $answer->answer = $dataanswer; |
1879 | $answer->question = $question->id; |
1880 | $answer->fraction = $question->fraction[$key]; |
1881 | $answer->feedback = $question->feedback[$key]; |
1882 | if (!$answer->id = insert_record("quiz_answers", $answer)) { |
1883 | $result->error = "Could not insert quiz answer! "; |
1884 | return $result; |
1885 | } |
49220fa7 |
1886 | } |
1887 | $answers[] = $answer->id; |
1888 | |
1889 | if ($question->fraction[$key] > 0) { // Sanity checks |
1890 | $totalfraction += $question->fraction[$key]; |
1891 | } |
1892 | if ($question->fraction[$key] > $maxfraction) { |
1893 | $maxfraction = $question->fraction[$key]; |
1894 | } |
1895 | } |
1896 | } |
1897 | |
77cff589 |
1898 | if ($options = get_record("quiz_multichoice", "question", $question->id)) { |
1899 | $options->answers = implode(",",$answers); |
1900 | $options->single = $question->single; |
1901 | if (!update_record("quiz_multichoice", $options)) { |
1902 | $result->error = "Could not update quiz multichoice options! (id=$options->id)"; |
1903 | return $result; |
1904 | } |
1905 | } else { |
1906 | unset($options); |
1907 | $options->question = $question->id; |
1908 | $options->answers = implode(",",$answers); |
1909 | $options->single = $question->single; |
1910 | if (!insert_record("quiz_multichoice", $options)) { |
1911 | $result->error = "Could not insert quiz multichoice options!"; |
1912 | return $result; |
1913 | } |
49220fa7 |
1914 | } |
1915 | |
1916 | /// Perform sanity checks on fractional grades |
1917 | if ($options->single) { |
1918 | if ($maxfraction != 1) { |
1919 | $maxfraction = $maxfraction * 100; |
1920 | $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); |
1921 | return $result; |
1922 | } |
1923 | } else { |
1924 | $totalfraction = round($totalfraction,2); |
1925 | if ($totalfraction != 1) { |
1926 | $totalfraction = $totalfraction * 100; |
1927 | $result->notice = get_string("fractionsaddwrong", "quiz", $totalfraction); |
1928 | return $result; |
1929 | } |
1930 | } |
1931 | break; |
95dbc030 |
1932 | |
54a67a59 |
1933 | case MATCH: |
77cff589 |
1934 | |
e1122620 |
1935 | if (!$oldsubquestions = get_records("quiz_match_sub", "question", $question->id, "id ASC")) { |
1936 | $oldsubquestions = array(); |
1937 | } |
54a67a59 |
1938 | |
1939 | $subquestions = array(); |
1940 | |
1941 | // Insert all the new question+answer pairs |
1942 | foreach ($question->subquestions as $key => $questiontext) { |
1943 | $answertext = $question->subanswers[$key]; |
1944 | if (!empty($questiontext) and !empty($answertext)) { |
77cff589 |
1945 | if ($subquestion = array_shift($oldsubquestions)) { // Existing answer, so reuse it |
1946 | $subquestion->questiontext = $questiontext; |
1947 | $subquestion->answertext = $answertext; |
1948 | if (!update_record("quiz_match_sub", $subquestion)) { |
1949 | $result->error = "Could not insert quiz match subquestion! (id=$subquestion->id)"; |
1950 | return $result; |
1951 | } |
1952 | } else { |
1953 | unset($subquestion); |
1954 | $subquestion->question = $question->id; |
1955 | $subquestion->questiontext = $questiontext; |
1956 | $subquestion->answertext = $answertext; |
1957 | if (!$subquestion->id = insert_record("quiz_match_sub", $subquestion)) { |
1958 | $result->error = "Could not insert quiz match subquestion!"; |
1959 | return $result; |
1960 | } |
54a67a59 |
1961 | } |
1962 | $subquestions[] = $subquestion->id; |
1963 | } |
1964 | } |
1965 | |
1966 | if (count($subquestions) < 3) { |
1967 | $result->notice = get_string("notenoughsubquestions", "quiz"); |
1968 | return $result; |
1969 | } |
1970 | |
77cff589 |
1971 | if ($options = get_record("quiz_match", "question", $question->id)) { |
1972 | $options->subquestions = implode(",",$subquestions); |
1973 | if (!update_record("quiz_match", $options)) { |
1974 | $result->error = "Could not update quiz match options! (id=$options->id)"; |
1975 | return $result; |
1976 | } |
1977 | } else { |
1978 | unset($options); |
1979 | $options->question = $question->id; |
1980 | $options->subquestions = implode(",",$subquestions); |
1981 | if (!insert_record("quiz_match", $options)) { |
1982 | $result->error = "Could not insert quiz match options!"; |
1983 | return $result; |
1984 | } |
54a67a59 |
1985 | } |
1986 | |
1987 | break; |
1988 | |
77cff589 |
1989 | |
54a67a59 |
1990 | case RANDOMSAMATCH: |
95dbc030 |
1991 | $options->question = $question->id; |
1992 | $options->choose = $question->choose; |
54a67a59 |
1993 | if ($existing = get_record("quiz_randomsamatch", "question", $options->question)) { |
95dbc030 |
1994 | $options->id = $existing->id; |
54a67a59 |
1995 | if (!update_record("quiz_randomsamatch", $options)) { |
1996 | $result->error = "Could not update quiz randomsamatch options!"; |
95dbc030 |
1997 | return $result; |
1998 | } |
1999 | } else { |
54a67a59 |
2000 | if (!insert_record("quiz_randomsamatch", $options)) { |
2001 | $result->error = "Could not insert quiz randomsamatch options!"; |
95dbc030 |
2002 | return $result; |
2003 | } |
2004 | } |
2005 | break; |
2006 | |
34d52ad7 |
2007 | case RANDOM: |
2008 | break; |
2009 | |
401c8de6 |
2010 | case DESCRIPTION: |
2011 | break; |
2012 | |
49220fa7 |
2013 | default: |
2014 | $result->error = "Unsupported question type ($question->qtype)!"; |
2015 | return $result; |
2016 | break; |
2017 | } |
2018 | return true; |
2019 | } |
2020 | |
2021 | |
29d5d0b4 |
2022 | function quiz_remove_unwanted_questions(&$questions, $quiz) { |
40b1a221 |
2023 | /// Given an array of questions, and a list of question IDs, |
2024 | /// this function removes unwanted questions from the array |
2025 | /// Used by review.php to counter changing quizzes |
29d5d0b4 |
2026 | |
2027 | $quizquestions = array(); |
2028 | $quizids = explode(",", $quiz->questions); |
2029 | foreach ($quizids as $quizid) { |
2030 | $quizquestions[$quizid] = true; |
2031 | } |
2032 | foreach ($questions as $key => $question) { |
2033 | if (!isset($quizquestions[$question->id])) { |
2034 | unset($questions[$key]); |
2035 | } |
2036 | } |
2037 | } |
2038 | |
95dbc030 |
2039 | |
2040 | |
730fd187 |
2041 | ?> |