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 | |
16 | define("SHORTANSWER", "1"); |
17 | define("TRUEFALSE", "2"); |
18 | define("MULTICHOICE", "3"); |
8db3eadd |
19 | define("RANDOM", "4"); |
8d94f5a0 |
20 | $QUIZ_QUESTION_TYPE = array ( MULTICHOICE => get_string("multichoice", "quiz"), |
a5e1f35c |
21 | TRUEFALSE => get_string("truefalse", "quiz"), |
e1c91df0 |
22 | SHORTANSWER => get_string("shortanswer", "quiz") ); |
a5e1f35c |
23 | |
24 | |
25 | |
26 | /// FUNCTIONS /////////////////////////////////////////////////////////////////// |
730fd187 |
27 | |
28 | function quiz_add_instance($quiz) { |
a5e1f35c |
29 | /// Given an object containing all the necessary data, |
30 | /// (defined by the form in mod.html) this function |
31 | /// will create a new instance and return the id number |
32 | /// of the new instance. |
730fd187 |
33 | |
49dcdd18 |
34 | $quiz->created = time(); |
730fd187 |
35 | $quiz->timemodified = time(); |
49dcdd18 |
36 | $quiz->timeopen = make_timestamp($quiz->openyear, $quiz->openmonth, $quiz->openday, |
37 | $quiz->openhour, $quiz->openminute, $quiz->opensecond); |
38 | $quiz->timeclose = make_timestamp($quiz->closeyear, $quiz->closemonth, $quiz->closeday, |
39 | $quiz->closehour, $quiz->closeminute, $quiz->closesecond); |
730fd187 |
40 | |
7bd1aa1d |
41 | if (!$quiz->id = insert_record("quiz", $quiz)) { |
42 | return false; // some error occurred |
43 | } |
44 | |
10b9291c |
45 | // The grades for every question in this quiz are stored in an array |
7bd1aa1d |
46 | if ($quiz->grades) { |
47 | foreach ($quiz->grades as $question => $grade) { |
8d94f5a0 |
48 | if ($question and $grade) { |
49 | unset($questiongrade); |
50 | $questiongrade->quiz = $quiz->id; |
51 | $questiongrade->question = $question; |
52 | $questiongrade->grade = $grade; |
53 | if (!insert_record("quiz_question_grades", $questiongrade)) { |
54 | return false; |
55 | } |
7bd1aa1d |
56 | } |
57 | } |
58 | } |
730fd187 |
59 | |
7bd1aa1d |
60 | return $quiz->id; |
730fd187 |
61 | } |
62 | |
63 | |
64 | function quiz_update_instance($quiz) { |
a5e1f35c |
65 | /// Given an object containing all the necessary data, |
66 | /// (defined by the form in mod.html) this function |
67 | /// will update an existing instance with new data. |
730fd187 |
68 | |
69 | $quiz->timemodified = time(); |
49dcdd18 |
70 | $quiz->timeopen = make_timestamp($quiz->openyear, $quiz->openmonth, $quiz->openday, |
71 | $quiz->openhour, $quiz->openminute, $quiz->opensecond); |
72 | $quiz->timeclose = make_timestamp($quiz->closeyear, $quiz->closemonth, $quiz->closeday, |
73 | $quiz->closehour, $quiz->closeminute, $quiz->closesecond); |
730fd187 |
74 | $quiz->id = $quiz->instance; |
75 | |
7bd1aa1d |
76 | if (!update_record("quiz", $quiz)) { |
77 | return false; // some error occurred |
78 | } |
730fd187 |
79 | |
7bd1aa1d |
80 | |
10b9291c |
81 | // The grades for every question in this quiz are stored in an array |
7bd1aa1d |
82 | // Insert or update records as appropriate |
83 | |
84 | $existing = get_records("quiz_question_grades", "quiz", $quiz->id, "", "question,grade,id"); |
85 | |
86 | if ($quiz->grades) { |
87 | foreach ($quiz->grades as $question => $grade) { |
8d94f5a0 |
88 | if ($question and $grade) { |
89 | unset($questiongrade); |
90 | $questiongrade->quiz = $quiz->id; |
91 | $questiongrade->question = $question; |
92 | $questiongrade->grade = $grade; |
93 | if (isset($existing[$question])) { |
94 | if ($existing[$question]->grade != $grade) { |
95 | $questiongrade->id = $existing[$question]->id; |
96 | if (!update_record("quiz_question_grades", $questiongrade)) { |
97 | return false; |
98 | } |
99 | } |
100 | } else { |
101 | if (!insert_record("quiz_question_grades", $questiongrade)) { |
7bd1aa1d |
102 | return false; |
103 | } |
104 | } |
7bd1aa1d |
105 | } |
106 | } |
107 | } |
108 | |
109 | return true; |
730fd187 |
110 | } |
111 | |
112 | |
113 | function quiz_delete_instance($id) { |
a5e1f35c |
114 | /// Given an ID of an instance of this module, |
115 | /// this function will permanently delete the instance |
116 | /// and any data that depends on it. |
730fd187 |
117 | |
118 | if (! $quiz = get_record("quiz", "id", "$id")) { |
119 | return false; |
120 | } |
121 | |
122 | $result = true; |
123 | |
10b9291c |
124 | if ($attempts = get_record("quiz_attempts", "quiz", "$quiz->id")) { |
125 | foreach ($attempts as $attempt) { |
126 | if (! delete_records("quiz_responses", "attempt", "$attempt->id")) { |
127 | $result = false; |
128 | } |
129 | } |
130 | } |
131 | |
132 | if (! delete_records("quiz_attempts", "quiz", "$quiz->id")) { |
133 | $result = false; |
134 | } |
135 | |
136 | if (! delete_records("quiz_grades", "quiz", "$quiz->id")) { |
137 | $result = false; |
138 | } |
139 | |
140 | if (! delete_records("quiz_question_grades", "quiz", "$quiz->id")) { |
141 | $result = false; |
142 | } |
730fd187 |
143 | |
144 | if (! delete_records("quiz", "id", "$quiz->id")) { |
145 | $result = false; |
146 | } |
147 | |
148 | return $result; |
149 | } |
150 | |
151 | function quiz_user_outline($course, $user, $mod, $quiz) { |
a5e1f35c |
152 | /// Return a small object with summary information about what a |
153 | /// user has done with a given particular instance of this module |
154 | /// Used for user activity reports. |
155 | /// $return->time = the time they did it |
156 | /// $return->info = a short text description |
98092498 |
157 | if ($grade = get_record_sql("SELECT * FROM quiz_grades WHERE user = '$user->id' AND quiz = '$quiz->id'")) { |
158 | |
159 | if ($grade->grade) { |
160 | $result->info = get_string("grade").": $grade->grade"; |
161 | } |
162 | $result->time = $grade->timemodified; |
163 | return $result; |
164 | } |
165 | return NULL; |
730fd187 |
166 | |
167 | return $return; |
168 | } |
169 | |
170 | function quiz_user_complete($course, $user, $mod, $quiz) { |
a5e1f35c |
171 | /// Print a detailed representation of what a user has done with |
172 | /// a given particular instance of this module, for user activity reports. |
730fd187 |
173 | |
174 | return true; |
175 | } |
176 | |
177 | function quiz_print_recent_activity(&$logs, $isteacher=false) { |
a5e1f35c |
178 | /// Given a list of logs, assumed to be those since the last login |
179 | /// this function prints a short list of changes related to this module |
180 | /// If isteacher is true then perhaps additional information is printed. |
181 | /// This function is called from course/lib.php: print_recent_activity() |
730fd187 |
182 | |
183 | global $CFG, $COURSE_TEACHER_COLOR; |
184 | |
185 | return $content; // True if anything was printed, otherwise false |
186 | } |
187 | |
188 | function quiz_cron () { |
a5e1f35c |
189 | /// Function to be run periodically according to the moodle cron |
190 | /// This function searches for things that need to be done, such |
191 | /// as sending out mail, toggling flags etc ... |
730fd187 |
192 | |
193 | global $CFG; |
194 | |
195 | return true; |
196 | } |
197 | |
d0ac6bc2 |
198 | function quiz_grades($quizid) { |
858deff0 |
199 | /// Must return an array of grades, indexed by user, and a max grade. |
200 | |
201 | $return->grades = get_records_sql_menu("SELECT user,grade FROM quiz_grades WHERE quiz = '$quizid'"); |
202 | $return->maxgrade = get_field("quiz", "grade", "id", "$quizid"); |
203 | return $return; |
d0ac6bc2 |
204 | } |
205 | |
730fd187 |
206 | |
207 | ////////////////////////////////////////////////////////////////////////////////////// |
a5e1f35c |
208 | /// Any other quiz functions go here. Each of them must have a name that |
209 | /// starts with quiz_ |
730fd187 |
210 | |
a8a372cc |
211 | function quiz_print_comment($text) { |
212 | global $THEME; |
213 | |
214 | echo "<FONT COLOR=\"$THEME->cellheading2\">".text_to_html($text, true, false)."</FONT>"; |
215 | } |
216 | |
8db3eadd |
217 | function quiz_print_correctanswer($text) { |
218 | global $THEME; |
219 | |
220 | echo "<P ALIGN=RIGHT><SPAN CLASS=highlight>$text</SPAN></P>"; |
221 | } |
222 | |
c74a0ca5 |
223 | function quiz_print_question_icon($question) { |
224 | // Prints a question icon |
cc3b8c75 |
225 | |
226 | global $QUIZ_QUESTION_TYPE; |
227 | |
228 | echo "<A HREF=\"question.php?id=$question->id\" TITLE=\"".$QUIZ_QUESTION_TYPE[$question->type]."\">"; |
c74a0ca5 |
229 | switch ($question->type) { |
230 | case SHORTANSWER: |
cc3b8c75 |
231 | echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/sa.gif\">"; |
c74a0ca5 |
232 | break; |
233 | case TRUEFALSE: |
cc3b8c75 |
234 | echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/tf.gif\">"; |
c74a0ca5 |
235 | break; |
236 | case MULTICHOICE: |
cc3b8c75 |
237 | echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/mc.gif\">"; |
c74a0ca5 |
238 | break; |
239 | case RANDOM: |
cc3b8c75 |
240 | echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/rs.gif\">"; |
c74a0ca5 |
241 | break; |
242 | } |
cc3b8c75 |
243 | echo "</A>\n"; |
c74a0ca5 |
244 | } |
245 | |
246 | function quiz_print_question($number, $questionid, $grade, $courseid, |
8db3eadd |
247 | $feedback=NULL, $response=NULL, $actualgrade=NULL, $correct=NULL) { |
a5e1f35c |
248 | /// Prints a quiz question, any format |
a8a372cc |
249 | |
14d8c0b4 |
250 | if (!$question = get_record("quiz_questions", "id", $questionid)) { |
251 | notify("Error: Question not found!"); |
252 | } |
253 | |
254 | $stranswer = get_string("answer", "quiz"); |
255 | $strmarks = get_string("marks", "quiz"); |
256 | |
257 | echo "<TABLE WIDTH=100% CELLSPACING=10><TR><TD NOWRAP WIDTH=100 VALIGN=top>"; |
a8a372cc |
258 | echo "<P ALIGN=CENTER><B>$number</B></P>"; |
19c4f55c |
259 | if ($feedback or $response) { |
a8a372cc |
260 | echo "<P ALIGN=CENTER><FONT SIZE=1>$strmarks: $actualgrade/$grade</FONT></P>"; |
261 | } else { |
262 | echo "<P ALIGN=CENTER><FONT SIZE=1>$grade $strmarks</FONT></P>"; |
263 | } |
14d8c0b4 |
264 | print_spacer(1,100); |
265 | echo "</TD><TD VALIGN=TOP>"; |
266 | |
267 | switch ($question->type) { |
a5e1f35c |
268 | case SHORTANSWER: |
14d8c0b4 |
269 | if (!$options = get_record("quiz_shortanswer", "question", $question->id)) { |
270 | notify("Error: Missing question options!"); |
271 | } |
2a2c9725 |
272 | echo text_to_html($question->questiontext); |
14d8c0b4 |
273 | if ($question->image) { |
274 | print_file_picture($question->image, $courseid, 200); |
275 | } |
a8a372cc |
276 | if ($response) { |
277 | $value = "VALUE=\"$response[0]\""; |
278 | } |
279 | echo "<P ALIGN=RIGHT>$stranswer: <INPUT TYPE=TEXT NAME=q$question->id SIZE=20 $value></P>"; |
280 | if ($feedback) { |
281 | quiz_print_comment("<P ALIGN=right>$feedback[0]</P>"); |
282 | } |
8db3eadd |
283 | if ($correct) { |
c74a0ca5 |
284 | $correctanswers = implode(", ", $correct); |
8db3eadd |
285 | quiz_print_correctanswer($correctanswers); |
286 | } |
14d8c0b4 |
287 | break; |
288 | |
a5e1f35c |
289 | case TRUEFALSE: |
14d8c0b4 |
290 | if (!$options = get_record("quiz_truefalse", "question", $question->id)) { |
291 | notify("Error: Missing question options!"); |
292 | } |
293 | if (!$true = get_record("quiz_answers", "id", $options->true)) { |
294 | notify("Error: Missing question answers!"); |
295 | } |
296 | if (!$false = get_record("quiz_answers", "id", $options->false)) { |
297 | notify("Error: Missing question answers!"); |
298 | } |
299 | if (!$true->answer) { |
300 | $true->answer = get_string("true", "quiz"); |
301 | } |
302 | if (!$false->answer) { |
303 | $false->answer = get_string("false", "quiz"); |
304 | } |
2a2c9725 |
305 | echo text_to_html($question->questiontext); |
14d8c0b4 |
306 | if ($question->image) { |
307 | print_file_picture($question->image, $courseid, 200); |
308 | } |
a8a372cc |
309 | |
310 | if ($response[$true->id]) { |
311 | $truechecked = "CHECKED"; |
312 | $feedbackid = $true->id; |
313 | } else if ($response[$false->id]) { |
314 | $falsechecked = "CHECKED"; |
315 | $feedbackid = $false->id; |
316 | } |
8db3eadd |
317 | if ($correct) { |
318 | if ($correct[$true->id]) { |
319 | $truecorrect = "CLASS=highlight"; |
320 | } |
321 | if ($correct[$false->id]) { |
322 | $falsecorrect = "CLASS=highlight"; |
323 | } |
324 | } |
325 | echo "<TABLE ALIGN=right cellpadding=5><TR><TD align=right>$stranswer: "; |
326 | echo "<TD $truecorrect>"; |
a8a372cc |
327 | echo "<INPUT $truechecked TYPE=RADIO NAME=\"q$question->id\" VALUE=\"$true->id\">$true->answer"; |
8db3eadd |
328 | echo "</TD><TD $falsecorrect>"; |
a8a372cc |
329 | echo "<INPUT $falsechecked TYPE=RADIO NAME=\"q$question->id\" VALUE=\"$false->id\">$false->answer</P>"; |
8db3eadd |
330 | echo "</TD></TR></TABLE><BR CLEAR=ALL>"; |
a8a372cc |
331 | if ($feedback) { |
332 | quiz_print_comment("<P ALIGN=right>$feedback[$feedbackid]</P>"); |
333 | } |
334 | |
14d8c0b4 |
335 | break; |
336 | |
a5e1f35c |
337 | case MULTICHOICE: |
14d8c0b4 |
338 | if (!$options = get_record("quiz_multichoice", "question", $question->id)) { |
339 | notify("Error: Missing question options!"); |
340 | } |
a5e1f35c |
341 | if (!$answers = get_records_list("quiz_answers", "id", $options->answers)) { |
14d8c0b4 |
342 | notify("Error: Missing question answers!"); |
343 | } |
2a2c9725 |
344 | echo text_to_html($question->questiontext); |
14d8c0b4 |
345 | if ($question->image) { |
346 | print_file_picture($question->image, $courseid, 200); |
347 | } |
348 | echo "<TABLE ALIGN=right>"; |
349 | echo "<TR><TD valign=top>$stranswer: </TD><TD>"; |
350 | echo "<TABLE ALIGN=right>"; |
351 | $answerids = explode(",", $options->answers); |
a8a372cc |
352 | |
14d8c0b4 |
353 | foreach ($answerids as $key => $answerid) { |
354 | $answer = $answers[$answerid]; |
355 | $qnum = $key + 1; |
a8a372cc |
356 | |
357 | if ($feedback and $response[$answerid]) { |
358 | $checked = "CHECKED"; |
359 | } else { |
360 | $checked = ""; |
361 | } |
14d8c0b4 |
362 | echo "<TR><TD valign=top>"; |
a5e1f35c |
363 | if ($options->single) { |
a8a372cc |
364 | echo "<INPUT $checked TYPE=RADIO NAME=q$question->id VALUE=\"$answer->id\">"; |
14d8c0b4 |
365 | } else { |
a8a372cc |
366 | echo "<INPUT $checked TYPE=CHECKBOX NAME=q$question->id"."a$answer->id VALUE=\"$answer->id\">"; |
14d8c0b4 |
367 | } |
368 | echo "</TD>"; |
8db3eadd |
369 | if ($feedback and $correct[$answer->id]) { |
370 | echo "<TD valign=top CLASS=highlight>$qnum. $answer->answer</TD>"; |
371 | } else { |
372 | echo "<TD valign=top>$qnum. $answer->answer</TD>"; |
373 | } |
a8a372cc |
374 | if ($feedback) { |
375 | echo "<TD valign=top> "; |
376 | if ($response[$answerid]) { |
377 | quiz_print_comment($feedback[$answerid]); |
378 | } |
379 | echo "</TD>"; |
380 | } |
14d8c0b4 |
381 | echo "</TR>"; |
382 | } |
383 | echo "</TABLE>"; |
384 | echo "</TABLE>"; |
385 | break; |
386 | |
8db3eadd |
387 | case RANDOM: |
388 | echo "<P>Random questions not supported yet</P>"; |
389 | break; |
390 | |
391 | |
14d8c0b4 |
392 | default: |
393 | notify("Error: Unknown question type!"); |
394 | } |
395 | |
396 | echo "</TD></TR></TABLE>"; |
3a506ca2 |
397 | } |
398 | |
a5e1f35c |
399 | function quiz_print_quiz_questions($quiz, $results=NULL) { |
400 | // Prints a whole quiz on one page. |
401 | |
402 | if (!$quiz->questions) { |
10b9291c |
403 | notify("No questions have been defined!", "view.php?id=$cm->id"); |
404 | return false; |
a5e1f35c |
405 | } |
406 | |
407 | $questions = explode(",", $quiz->questions); |
408 | |
409 | if (!$grades = get_records_list("quiz_question_grades", "question", $quiz->questions, "", "question,grade")) { |
10b9291c |
410 | notify("No grades were found for these questions!"); |
411 | return false; |
a5e1f35c |
412 | } |
413 | |
414 | echo "<FORM METHOD=POST ACTION=attempt.php>"; |
415 | echo "<INPUT TYPE=hidden NAME=q VALUE=\"$quiz->id\">"; |
a8a372cc |
416 | |
a5e1f35c |
417 | foreach ($questions as $key => $questionid) { |
8db3eadd |
418 | $feedback = NULL; |
419 | $response = NULL; |
420 | $actualgrades = NULL; |
421 | $correct = NULL; |
a8a372cc |
422 | if ($results) { |
8db3eadd |
423 | $feedback = $results->feedback[$questionid]; |
424 | $response = $results->response[$questionid]; |
425 | $actualgrades = $results->grades[$questionid]; |
426 | if ($quiz->correctanswers) { |
427 | $correct = $results->correct[$questionid]; |
428 | } |
a8a372cc |
429 | } |
8db3eadd |
430 | |
a5e1f35c |
431 | print_simple_box_start("CENTER", "90%"); |
a8a372cc |
432 | quiz_print_question($key+1, $questionid, $grades[$questionid]->grade, $quiz->course, |
8db3eadd |
433 | $feedback, $response, $actualgrades, $correct); |
a5e1f35c |
434 | print_simple_box_end(); |
435 | echo "<BR>"; |
436 | } |
a8a372cc |
437 | |
438 | if (!$results) { |
439 | echo "<CENTER><INPUT TYPE=submit VALUE=\"".get_string("savemyanswers", "quiz")."\"></CENTER>"; |
440 | } |
a5e1f35c |
441 | echo "</FORM>"; |
10b9291c |
442 | |
443 | return true; |
a5e1f35c |
444 | } |
6a952ce7 |
445 | |
446 | function quiz_get_default_category($courseid) { |
447 | if ($categories = get_records("quiz_categories", "course", $courseid, "id")) { |
448 | foreach ($categories as $category) { |
449 | return $category; // Return the first one (lowest id) |
450 | } |
451 | } |
452 | |
453 | // Otherwise, we need to make one |
10b9291c |
454 | $category->name = get_string("default", "quiz"); |
455 | $category->info = get_string("defaultinfo", "quiz"); |
6a952ce7 |
456 | $category->course = $courseid; |
457 | $category->publish = 0; |
458 | |
459 | if (!$category->id = insert_record("quiz_categories", $category)) { |
460 | notify("Error creating a default category!"); |
461 | return false; |
462 | } |
463 | return $category; |
464 | } |
465 | |
c74a0ca5 |
466 | function quiz_get_category_menu($courseid, $published=false) { |
467 | if ($published) { |
468 | $publish = "OR publish = '1'"; |
469 | } |
470 | return get_records_sql_menu("SELECT id,name FROM quiz_categories WHERE course='$courseid' $publish ORDER by name ASC"); |
471 | } |
472 | |
6a952ce7 |
473 | function quiz_print_category_form($course, $current) { |
474 | // Prints a form to choose categories |
475 | |
b55a466b |
476 | if (!$categories = get_records_sql("SELECT * FROM quiz_categories WHERE course='$course->id' OR publish = '1' ORDER by name ASC")) { |
6a952ce7 |
477 | if (!$category = quiz_get_default_category($course->id)) { |
478 | notify("Error creating a default category!"); |
479 | return false; |
480 | } |
cb62c00a |
481 | $categories[$category->id] = $category; |
6a952ce7 |
482 | } |
8d94f5a0 |
483 | foreach ($categories as $key => $category) { |
484 | if ($category->publish) { |
b55a466b |
485 | if ($catcourse = get_record("course", "id", $category->course)) { |
486 | $category->name .= " ($catcourse->shortname)"; |
8d94f5a0 |
487 | } |
488 | } |
b55a466b |
489 | $catmenu[$category->id] = $category->name; |
8d94f5a0 |
490 | } |
6a952ce7 |
491 | $strcategory = get_string("category", "quiz"); |
492 | $strshow = get_string("show", "quiz"); |
6b069ece |
493 | $streditcats = get_string("editcategories", "quiz"); |
6a952ce7 |
494 | |
6b069ece |
495 | echo "<TABLE width=\"100%\"><TR><TD>"; |
6a952ce7 |
496 | echo "<FORM METHOD=POST ACTION=edit.php>"; |
497 | echo "<B>$strcategory:</B> "; |
b55a466b |
498 | choose_from_menu($catmenu, "cat", "$current"); |
92a3c884 |
499 | echo "<INPUT TYPE=submit VALUE=\"$strshow\">"; |
6a952ce7 |
500 | echo "</FORM>"; |
6b069ece |
501 | echo "</TD><TD align=right>"; |
502 | echo "<FORM METHOD=GET ACTION=category.php>"; |
503 | echo "<INPUT TYPE=hidden NAME=id VALUE=\"$course->id\">"; |
504 | echo "<INPUT TYPE=submit VALUE=\"$streditcats\">"; |
505 | echo "</FORM>"; |
506 | echo "</TD></TR></TABLE>"; |
6a952ce7 |
507 | } |
508 | |
509 | |
7bd1aa1d |
510 | function quiz_get_all_question_grades($questionlist, $quizid) { |
511 | // Given a list of question IDs, finds grades or invents them to |
512 | // create an array of matching grades |
513 | |
92a3c884 |
514 | $questions = get_records_sql("SELECT question,grade FROM quiz_question_grades |
7bd1aa1d |
515 | WHERE quiz = '$quizid' |
516 | AND question IN ($questionlist)"); |
517 | |
518 | $list = explode(",", $questionlist); |
519 | $grades = array(); |
520 | |
521 | foreach ($list as $qid) { |
522 | if (isset($questions[$qid])) { |
523 | $grades[$qid] = $questions[$qid]->grade; |
524 | } else { |
525 | $grades[$qid] = 1; |
526 | } |
527 | } |
528 | return $grades; |
529 | } |
530 | |
531 | |
532 | function quiz_print_question_list($questionlist, $grades) { |
6a952ce7 |
533 | // Prints a list of quiz questions in a small layout form with knobs |
7bd1aa1d |
534 | // $questionlist is comma-separated list |
535 | // $grades is an array of corresponding grades |
6a952ce7 |
536 | |
537 | global $THEME; |
538 | |
539 | if (!$questionlist) { |
540 | echo "<P align=center>"; |
541 | print_string("noquestions", "quiz"); |
542 | echo "</P>"; |
543 | return; |
544 | } |
545 | |
546 | $order = explode(",", $questionlist); |
547 | |
7bd1aa1d |
548 | if (!$questions = get_records_list("quiz_questions", "id", $questionlist)) { |
6a952ce7 |
549 | error("No questions were found!"); |
550 | } |
551 | |
552 | $strorder = get_string("order"); |
553 | $strquestionname = get_string("questionname", "quiz"); |
554 | $strgrade = get_string("grade"); |
555 | $strdelete = get_string("delete"); |
556 | $stredit = get_string("edit"); |
557 | $strmoveup = get_string("moveup"); |
558 | $strmovedown = get_string("movedown"); |
559 | $strsavegrades = get_string("savegrades", "quiz"); |
c74a0ca5 |
560 | $strtype = get_string("type", "quiz"); |
6a952ce7 |
561 | |
10b9291c |
562 | for ($i=10; $i>=0; $i--) { |
7bd1aa1d |
563 | $gradesmenu[$i] = $i; |
6a952ce7 |
564 | } |
565 | $count = 0; |
566 | $sumgrade = 0; |
567 | $total = count($order); |
568 | echo "<FORM METHOD=post ACTION=edit.php>"; |
569 | echo "<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=2 WIDTH=\"100%\">"; |
c74a0ca5 |
570 | echo "<TR><TH WIDTH=10 COLSPAN=3>$strorder</TH><TH align=left WIDTH=\"100%\">$strquestionname</TH><TH width=16>$strtype</TH><TH WIDTH=10>$strgrade</TH><TH WIDTH=10>$stredit</TH></TR>"; |
6a952ce7 |
571 | foreach ($order as $qnum) { |
572 | $count++; |
573 | echo "<TR BGCOLOR=\"$THEME->cellcontent\">"; |
574 | echo "<TD>$count</TD>"; |
575 | echo "<TD>"; |
576 | if ($count != 1) { |
577 | echo "<A TITLE=\"$strmoveup\" HREF=\"edit.php?up=$qnum\"><IMG |
578 | SRC=\"../../pix/t/up.gif\" BORDER=0></A>"; |
579 | } |
580 | echo "</TD>"; |
581 | echo "<TD>"; |
582 | if ($count != $total) { |
583 | echo "<A TITLE=\"$strmovedown\" HREF=\"edit.php?down=$qnum\"><IMG |
584 | SRC=\"../../pix/t/down.gif\" BORDER=0></A>"; |
585 | } |
586 | echo "</TD>"; |
587 | echo "<TD>".$questions[$qnum]->name."</TD>"; |
c74a0ca5 |
588 | echo "<TD WIDTH=16 ALIGN=CENTER>"; |
589 | quiz_print_question_icon($questions[$qnum]); |
590 | echo "</TD>"; |
6a952ce7 |
591 | echo "<TD>"; |
8d94f5a0 |
592 | choose_from_menu($gradesmenu, "q$qnum", (string)$grades[$qnum], ""); |
6a952ce7 |
593 | echo "<TD>"; |
594 | echo "<A TITLE=\"$strdelete\" HREF=\"edit.php?delete=$qnum\"><IMG |
595 | SRC=\"../../pix/t/delete.gif\" BORDER=0></A> "; |
596 | echo "<A TITLE=\"$stredit\" HREF=\"question.php?id=$qnum\"><IMG |
597 | SRC=\"../../pix/t/edit.gif\" BORDER=0></A>"; |
598 | echo "</TD>"; |
599 | |
7bd1aa1d |
600 | $sumgrade += $grades[$qnum]; |
6a952ce7 |
601 | } |
c74a0ca5 |
602 | echo "<TR><TD COLSPAN=5 ALIGN=right>"; |
6a952ce7 |
603 | echo "<INPUT TYPE=submit VALUE=\"$strsavegrades:\">"; |
8d94f5a0 |
604 | echo "<INPUT TYPE=hidden NAME=setgrades VALUE=\"save\">"; |
6a952ce7 |
605 | echo "<TD ALIGN=LEFT BGCOLOR=\"$THEME->cellcontent\">"; |
606 | echo "<B>$sumgrade</B>"; |
607 | echo "</TD><TD></TD></TR>"; |
608 | echo "</TABLE>"; |
609 | echo "</FORM>"; |
10b9291c |
610 | |
611 | return $sumgrade; |
6a952ce7 |
612 | } |
613 | |
614 | |
615 | function quiz_print_cat_question_list($categoryid) { |
616 | // Prints a form to choose categories |
617 | |
618 | global $THEME, $QUIZ_QUESTION_TYPE; |
619 | |
10b9291c |
620 | $strcategory = get_string("category", "quiz"); |
6a952ce7 |
621 | $strquestion = get_string("question", "quiz"); |
622 | $strnoquestions = get_string("noquestions", "quiz"); |
623 | $strselect = get_string("select", "quiz"); |
624 | $strcreatenewquestion = get_string("createnewquestion", "quiz"); |
625 | $strquestionname = get_string("questionname", "quiz"); |
626 | $strdelete = get_string("delete"); |
627 | $stredit = get_string("edit"); |
628 | $straddselectedtoquiz = get_string("addselectedtoquiz", "quiz"); |
c74a0ca5 |
629 | $strtype = get_string("type", "quiz"); |
6a952ce7 |
630 | |
631 | if (!$categoryid) { |
632 | echo "<P align=center>"; |
633 | print_string("selectcategoryabove", "quiz"); |
634 | echo "</P>"; |
635 | return; |
636 | } |
a5e1f35c |
637 | |
6a952ce7 |
638 | if (!$category = get_record("quiz_categories", "id", "$categoryid")) { |
639 | notify("Category not found!"); |
640 | return; |
641 | } |
8d94f5a0 |
642 | echo "<CENTER>"; |
10b9291c |
643 | echo text_to_html($category->info); |
6a952ce7 |
644 | |
10b9291c |
645 | echo "<FORM METHOD=GET ACTION=question.php>"; |
6a952ce7 |
646 | echo "<B>$strquestion:</B> "; |
647 | choose_from_menu($QUIZ_QUESTION_TYPE, "type", "", ""); |
648 | echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">"; |
649 | echo "<INPUT TYPE=submit NAME=new VALUE=\"$strcreatenewquestion\">"; |
cd63d77e |
650 | helpbutton("questiontypes", $strcreatenewquestion, "quiz"); |
6a952ce7 |
651 | echo "</FORM>"; |
8d94f5a0 |
652 | echo "</CENTER>"; |
6a952ce7 |
653 | |
654 | if (!$questions = get_records("quiz_questions", "category", $category->id)) { |
655 | echo "<P align=center>"; |
656 | print_string("noquestions", "quiz"); |
657 | echo "</P>"; |
658 | return; |
659 | } |
660 | |
10b9291c |
661 | $canedit = isteacher($category->course); |
662 | |
6a952ce7 |
663 | echo "<FORM METHOD=post ACTION=edit.php>"; |
664 | echo "<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=2 WIDTH=\"100%\">"; |
c74a0ca5 |
665 | echo "<TR><TH width=10>$strselect</TH><TH width=* align=left>$strquestionname</TH><TH WIDTH=16>$strtype</TH>"; |
10b9291c |
666 | if ($canedit) { |
667 | echo "<TH width=10>$stredit</TH>"; |
668 | } |
669 | echo "</TR>"; |
6a952ce7 |
670 | foreach ($questions as $question) { |
671 | echo "<TR BGCOLOR=\"$THEME->cellcontent\">"; |
672 | echo "<TD ALIGN=CENTER>"; |
673 | echo "<INPUT TYPE=CHECKBOX NAME=q$question->id VALUE=\"1\">"; |
674 | echo "</TD>"; |
675 | echo "<TD>".$question->name."</TD>"; |
c74a0ca5 |
676 | echo "<TD WIDTH=16 ALIGN=CENTER>"; |
677 | quiz_print_question_icon($question); |
678 | echo "</TD>"; |
10b9291c |
679 | if ($canedit) { |
680 | echo "<TD>"; |
e1c91df0 |
681 | echo "<A TITLE=\"$strdelete\" HREF=\"question.php?id=$question->id&delete=$question->id\"><IMG |
10b9291c |
682 | SRC=\"../../pix/t/delete.gif\" BORDER=0></A> "; |
683 | echo "<A TITLE=\"$stredit\" HREF=\"question.php?id=$question->id\"><IMG |
684 | SRC=\"../../pix/t/edit.gif\" BORDER=0></A>"; |
685 | echo "</TD></TR>"; |
686 | } |
687 | echo "</TR>"; |
6a952ce7 |
688 | } |
689 | echo "<TR><TD COLSPAN=3>"; |
690 | echo "<INPUT TYPE=hidden NAME=add VALUE=\"1\">"; |
691 | echo "<INPUT TYPE=submit VALUE=\"<< $straddselectedtoquiz\">"; |
692 | echo "</TD></TR>"; |
693 | echo "</TABLE>"; |
694 | echo "</FORM>"; |
695 | } |
a5e1f35c |
696 | |
3a506ca2 |
697 | |
958aafe2 |
698 | function quiz_start_attempt($quizid, $userid, $numattempt) { |
699 | $attempt->quiz = $quizid; |
700 | $attempt->user = $userid; |
701 | $attempt->attempt = $numattempt; |
702 | $attempt->timestart = time(); |
703 | $attempt->timefinish = 0; |
704 | $attempt->timemodified = time(); |
705 | |
706 | return insert_record("quiz_attempts", $attempt); |
707 | } |
708 | |
709 | function quiz_get_user_attempt_unfinished($quizid, $userid) { |
710 | // Returns an object containing an unfinished attempt (if there is one) |
711 | return get_record_sql("SELECT * FROM quiz_attempts |
712 | WHERE quiz = '$quizid' and user = '$userid' AND timefinish = 0"); |
713 | } |
714 | |
3a506ca2 |
715 | function quiz_get_user_attempts($quizid, $userid) { |
a5e1f35c |
716 | // Returns a list of all attempts by a user |
958aafe2 |
717 | return get_records_sql("SELECT * FROM quiz_attempts |
718 | WHERE quiz = '$quizid' and user = '$userid' AND timefinish > 0 |
719 | ORDER by attempt ASC"); |
3a506ca2 |
720 | } |
721 | |
8d94f5a0 |
722 | |
723 | function quiz_get_user_attempts_string($quiz, $attempts, $bestgrade) { |
724 | /// Returns a simple little comma-separated list of all attempts, |
6d86b5dc |
725 | /// with each grade linked to the feedback report and with the best grade highlighted |
8d94f5a0 |
726 | |
727 | $bestgrade = format_float($bestgrade); |
728 | foreach ($attempts as $attempt) { |
729 | $attemptgrade = format_float(($attempt->sumgrades / $quiz->sumgrades) * $quiz->grade); |
730 | if ($attemptgrade == $bestgrade) { |
6d86b5dc |
731 | $userattempts[] = "<SPAN CLASS=highlight><A HREF=\"report.php?q=$quiz->id&attempt=$attempt->id\">$attemptgrade</A></SPAN>"; |
8d94f5a0 |
732 | } else { |
6d86b5dc |
733 | $userattempts[] = "<A HREF=\"report.php?q=$quiz->id&attempt=$attempt->id\">$attemptgrade</A>"; |
8d94f5a0 |
734 | } |
735 | } |
736 | return implode(",", $userattempts); |
737 | } |
738 | |
a5e1f35c |
739 | function quiz_get_best_grade($quizid, $userid) { |
740 | /// Get the best current grade for a particular user in a quiz |
3a506ca2 |
741 | if (!$grade = get_record_sql("SELECT * FROM quiz_grades WHERE quiz = '$quizid' and user = '$userid'")) { |
742 | return 0; |
743 | } |
744 | |
2383cadb |
745 | return (round($grade->grade,0)); |
3a506ca2 |
746 | } |
747 | |
579ddad5 |
748 | function quiz_get_grade_records($quiz) { |
749 | /// Gets all info required to display the table of quiz results |
750 | /// for report.php |
751 | |
752 | return get_records_sql("SELECT qg.*, u.firstname, u.lastname, u.picture |
753 | FROM quiz_grades qg, user u |
754 | WHERE qg.quiz = '$quiz->id' |
755 | AND qg.user = u.id"); |
756 | } |
757 | |
e331eb06 |
758 | function quiz_save_best_grade($quiz, $userid) { |
a5e1f35c |
759 | /// Calculates the best grade out of all attempts at a quiz for a user, |
760 | /// and then saves that grade in the quiz_grades table. |
761 | |
e331eb06 |
762 | if (!$attempts = quiz_get_user_attempts($quiz->id, $userid)) { |
e909c8d0 |
763 | notify("Could not find any user attempts"); |
a5e1f35c |
764 | return false; |
765 | } |
766 | |
767 | $bestgrade = quiz_calculate_best_grade($quiz, $attempts); |
768 | $bestgrade = (($bestgrade / $quiz->sumgrades) * $quiz->grade); |
769 | |
e331eb06 |
770 | if ($grade = get_record_sql("SELECT * FROM quiz_grades WHERE quiz='$quiz->id' AND user='$userid'")) { |
a5e1f35c |
771 | $grade->grade = $bestgrade; |
772 | $grade->timemodified = time(); |
773 | if (!update_record("quiz_grades", $grade)) { |
e909c8d0 |
774 | notify("Could not update best grade"); |
a5e1f35c |
775 | return false; |
776 | } |
777 | } else { |
778 | $grade->quiz = $quiz->id; |
e331eb06 |
779 | $grade->user = $userid; |
38f03e5a |
780 | $grade->grade = round($bestgrade, 2); |
a5e1f35c |
781 | $grade->timemodified = time(); |
782 | if (!insert_record("quiz_grades", $grade)) { |
e909c8d0 |
783 | notify("Could not insert new best grade"); |
a5e1f35c |
784 | return false; |
785 | } |
786 | } |
787 | return true; |
788 | } |
789 | |
790 | |
2a2c9725 |
791 | function quiz_get_answers($question) { |
a5e1f35c |
792 | // Given a question, returns the correct answers and grades |
793 | switch ($question->type) { |
794 | case SHORTANSWER; // Could be multiple answers |
2a2c9725 |
795 | return get_records_sql("SELECT a.*, sa.usecase, g.grade |
a5e1f35c |
796 | FROM quiz_shortanswer sa, quiz_answers a, quiz_question_grades g |
797 | WHERE sa.question = '$question->id' |
798 | AND sa.question = a.question |
799 | AND sa.question = g.question"); |
800 | break; |
801 | |
802 | case TRUEFALSE; // Should be always two answers |
803 | return get_records_sql("SELECT a.*, g.grade |
804 | FROM quiz_answers a, quiz_question_grades g |
805 | WHERE a.question = '$question->id' |
806 | AND a.question = g.question"); |
807 | break; |
808 | |
809 | case MULTICHOICE; // Should be multiple answers |
810 | return get_records_sql("SELECT a.*, mc.single, g.grade |
811 | FROM quiz_multichoice mc, quiz_answers a, quiz_question_grades g |
812 | WHERE mc.question = '$question->id' |
813 | AND mc.question = a.question |
814 | AND mc.question = g.question"); |
815 | break; |
816 | |
8db3eadd |
817 | case RANDOM: |
818 | return false; // Not done yet |
819 | break; |
820 | |
a5e1f35c |
821 | default: |
822 | return false; |
823 | } |
824 | } |
825 | |
3a506ca2 |
826 | function quiz_calculate_best_grade($quiz, $attempts) { |
a5e1f35c |
827 | /// Calculate the best grade for a quiz given a number of attempts by a particular user. |
3a506ca2 |
828 | |
829 | switch ($quiz->grademethod) { |
a5e1f35c |
830 | |
831 | case ATTEMPTFIRST: |
3a506ca2 |
832 | foreach ($attempts as $attempt) { |
a5e1f35c |
833 | return $attempt->sumgrades; |
3a506ca2 |
834 | } |
a5e1f35c |
835 | break; |
836 | |
837 | case ATTEMPTLAST: |
838 | foreach ($attempts as $attempt) { |
839 | $final = $attempt->sumgrades; |
840 | } |
841 | return $final; |
3a506ca2 |
842 | |
a5e1f35c |
843 | case GRADEAVERAGE: |
3a506ca2 |
844 | $sum = 0; |
845 | $count = 0; |
846 | foreach ($attempts as $attempt) { |
a5e1f35c |
847 | $sum += $attempt->sumgrades; |
3a506ca2 |
848 | $count++; |
849 | } |
850 | return (float)$sum/$count; |
851 | |
3a506ca2 |
852 | default: |
a5e1f35c |
853 | case GRADEHIGHEST: |
854 | $max = 0; |
3a506ca2 |
855 | foreach ($attempts as $attempt) { |
a5e1f35c |
856 | if ($attempt->sumgrades > $max) { |
857 | $max = $attempt->sumgrades; |
858 | } |
3a506ca2 |
859 | } |
a5e1f35c |
860 | return $max; |
861 | } |
862 | } |
863 | |
864 | function quiz_save_attempt($quiz, $questions, $result, $attemptnum) { |
865 | /// Given a quiz, a list of attempted questions and a total grade |
866 | /// this function saves EVERYTHING so it can be reconstructed later |
867 | /// if necessary. |
868 | |
869 | global $USER; |
870 | |
958aafe2 |
871 | // First find the attempt in the database (start of attempt) |
872 | |
873 | if (!$attempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) { |
874 | notify("Trying to save an attempt that was not started!"); |
875 | return false; |
876 | } |
877 | |
878 | if ($attempt->attempt != $attemptnum) { // Double check. |
879 | notify("Number of this attempt is different to the unfinished one!"); |
880 | return false; |
881 | } |
882 | |
883 | // Now let's complete this record and save it |
a5e1f35c |
884 | |
a5e1f35c |
885 | $attempt->sumgrades = $result->sumgrades; |
958aafe2 |
886 | $attempt->timefinish = time(); |
a5e1f35c |
887 | $attempt->timemodified = time(); |
888 | |
958aafe2 |
889 | if (! update_record("quiz_attempts", $attempt)) { |
7520988b |
890 | notify("Error while saving attempt"); |
a5e1f35c |
891 | return false; |
892 | } |
893 | |
894 | // Now let's save all the questions for this attempt |
895 | |
896 | foreach ($questions as $question) { |
897 | $response->attempt = $attempt->id; |
898 | $response->question = $question->id; |
899 | $response->grade = $result->grades[$question->id]; |
900 | if ($question->answer) { |
901 | $response->answer = implode(",",$question->answer); |
902 | } else { |
903 | $response->answer = ""; |
904 | } |
905 | if (!insert_record("quiz_responses", $response)) { |
7520988b |
906 | notify("Error while saving response"); |
a5e1f35c |
907 | return false; |
908 | } |
3a506ca2 |
909 | } |
a5e1f35c |
910 | return true; |
3a506ca2 |
911 | } |
730fd187 |
912 | |
a5e1f35c |
913 | |
914 | function quiz_grade_attempt_results($quiz, $questions) { |
915 | /// Given a list of questions (including answers for each one) |
916 | /// this function does all the hard work of calculating the |
917 | /// grades for each question, as well as a total grade for |
918 | /// for the whole quiz. It returns everything in a structure |
919 | /// that looks like: |
920 | /// $result->sumgrades (sum of all grades for all questions) |
921 | /// $result->percentage (Percentage of grades that were correct) |
922 | /// $result->grade (final grade result for the whole quiz) |
923 | /// $result->grades[] (array of grades, indexed by question id) |
a8a372cc |
924 | /// $result->response[] (array of response arrays, indexed by question id) |
a5e1f35c |
925 | /// $result->feedback[] (array of feedback arrays, indexed by question id) |
8db3eadd |
926 | /// $result->correct[] (array of feedback arrays, indexed by question id) |
a5e1f35c |
927 | |
928 | if (!$questions) { |
929 | error("No questions!"); |
930 | } |
931 | |
932 | $result->sumgrades = 0; |
933 | |
934 | foreach ($questions as $question) { |
2a2c9725 |
935 | if (!$answers = quiz_get_answers($question)) { |
936 | error("No answers defined for question id $question->id!"); |
a5e1f35c |
937 | } |
938 | |
939 | $grade = 0; // default |
8db3eadd |
940 | $correct = array(); |
19c4f55c |
941 | $feedback = array(); |
942 | $response = array(); |
a5e1f35c |
943 | |
944 | switch ($question->type) { |
945 | case SHORTANSWER: |
946 | if ($question->answer) { |
cd63d77e |
947 | $question->answer = trim($question->answer[0]); |
a5e1f35c |
948 | } else { |
19c4f55c |
949 | $question->answer = ""; |
a5e1f35c |
950 | } |
a8a372cc |
951 | $response[0] = $question->answer; |
a5e1f35c |
952 | foreach($answers as $answer) { // There might be multiple right answers |
8db3eadd |
953 | if ($answer->fraction > $bestshortanswer) { |
954 | $correct[$answer->id] = $answer->answer; |
955 | } |
2a2c9725 |
956 | if (!$answer->usecase) { // Don't compare case |
a5e1f35c |
957 | $answer->answer = strtolower($answer->answer); |
958 | $question->answer = strtolower($question->answer); |
959 | } |
960 | if ($question->answer == $answer->answer) { |
a8a372cc |
961 | $feedback[0] = $answer->feedback; |
a5e1f35c |
962 | $grade = (float)$answer->fraction * $answer->grade; |
963 | } |
964 | } |
965 | break; |
966 | |
967 | |
968 | case TRUEFALSE: |
969 | if ($question->answer) { |
970 | $question->answer = $question->answer[0]; |
971 | } else { |
972 | $question->answer = NULL; |
973 | } |
974 | foreach($answers as $answer) { // There should be two answers (true and false) |
975 | $feedback[$answer->id] = $answer->feedback; |
8db3eadd |
976 | if ($answer->fraction > 0) { |
977 | $correct[$answer->id] = true; |
978 | } |
a5e1f35c |
979 | if ($question->answer == $answer->id) { |
980 | $grade = (float)$answer->fraction * $answer->grade; |
a8a372cc |
981 | $response[$answer->id] = true; |
a5e1f35c |
982 | } |
983 | } |
984 | break; |
985 | |
986 | |
987 | case MULTICHOICE: |
988 | foreach($answers as $answer) { // There will be multiple answers, perhaps more than one is right |
989 | $feedback[$answer->id] = $answer->feedback; |
8db3eadd |
990 | if ($answer->fraction > 0) { |
991 | $correct[$answer->id] = true; |
992 | } |
a5e1f35c |
993 | if ($question->answer) { |
994 | foreach ($question->answer as $questionanswer) { |
995 | if ($questionanswer == $answer->id) { |
996 | if ($answer->single) { |
997 | $grade = (float)$answer->fraction * $answer->grade; |
a8a372cc |
998 | $response[$answer->id] = true; |
a5e1f35c |
999 | continue; |
1000 | } else { |
1001 | $grade += (float)$answer->fraction * $answer->grade; |
a8a372cc |
1002 | $response[$answer->id] = true; |
a5e1f35c |
1003 | } |
1004 | } |
1005 | } |
1006 | } |
1007 | } |
1008 | break; |
8db3eadd |
1009 | case RANDOM: |
1010 | // Not done yet |
1011 | break; |
a5e1f35c |
1012 | |
1013 | |
1014 | } |
1015 | if ($grade < 0.0) { // No negative grades |
1016 | $grade = 0.0; |
1017 | } |
10b9291c |
1018 | |
a5e1f35c |
1019 | $result->grades[$question->id] = $grade; |
1020 | $result->sumgrades += $grade; |
1021 | $result->feedback[$question->id] = $feedback; |
a8a372cc |
1022 | $result->response[$question->id] = $response; |
8db3eadd |
1023 | $result->correct[$question->id] = $correct; |
a5e1f35c |
1024 | } |
1025 | |
8d94f5a0 |
1026 | $fraction = (float)($result->sumgrades / $quiz->sumgrades); |
1027 | $result->percentage = format_float($fraction * 100.0); |
1028 | $result->grade = format_float($fraction * $quiz->grade); |
a5e1f35c |
1029 | |
1030 | return $result; |
1031 | } |
6d86b5dc |
1032 | |
1033 | |
1034 | function quiz_get_attempt_responses($attempt) { |
1035 | // Given an attempt object, this function gets all the |
1036 | // stored responses and returns them in a format suitable |
1037 | // for regrading using quiz_grade_attempt_results() |
1038 | |
1039 | if (!$responses = get_records_sql("SELECT q.id, q.type, r.answer |
1040 | FROM quiz_responses r, quiz_questions q |
1041 | WHERE r.attempt = '$attempt->id' |
1042 | AND q.id = r.question")) { |
1043 | notify("Could not find any responses for that attempt!"); |
1044 | return false; |
1045 | } |
1046 | |
1047 | foreach ($responses as $key => $response) { |
1048 | $responses[$key]->answer = explode(",",$response->answer); |
1049 | } |
1050 | |
1051 | return $responses; |
1052 | } |
1053 | |
a5e1f35c |
1054 | |
730fd187 |
1055 | ?> |