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"); |
19 | $QUIZ_QUESTION_TYPE = array ( SHORTANSWER => get_string("shortanswer", "quiz"), |
20 | TRUEFALSE => get_string("truefalse", "quiz"), |
21 | MULTICHOICE => get_string("multichoice", "quiz")); |
22 | |
23 | |
24 | |
25 | /// FUNCTIONS /////////////////////////////////////////////////////////////////// |
730fd187 |
26 | |
27 | function quiz_add_instance($quiz) { |
a5e1f35c |
28 | /// Given an object containing all the necessary data, |
29 | /// (defined by the form in mod.html) this function |
30 | /// will create a new instance and return the id number |
31 | /// of the new instance. |
730fd187 |
32 | |
33 | $quiz->timemodified = time(); |
34 | |
7bd1aa1d |
35 | if (!$quiz->id = insert_record("quiz", $quiz)) { |
36 | return false; // some error occurred |
37 | } |
38 | |
10b9291c |
39 | // The grades for every question in this quiz are stored in an array |
7bd1aa1d |
40 | if ($quiz->grades) { |
41 | foreach ($quiz->grades as $question => $grade) { |
42 | $questiongrade->quiz = $quiz->id; |
43 | $questiongrade->question = $question; |
44 | $questiongrade->grade = $grade; |
45 | if (!insert_record("quiz_question_grades", $questiongrade)) { |
46 | return false; |
47 | } |
48 | } |
49 | } |
730fd187 |
50 | |
7bd1aa1d |
51 | return $quiz->id; |
730fd187 |
52 | } |
53 | |
54 | |
55 | function quiz_update_instance($quiz) { |
a5e1f35c |
56 | /// Given an object containing all the necessary data, |
57 | /// (defined by the form in mod.html) this function |
58 | /// will update an existing instance with new data. |
730fd187 |
59 | |
60 | $quiz->timemodified = time(); |
61 | $quiz->id = $quiz->instance; |
62 | |
7bd1aa1d |
63 | if (!update_record("quiz", $quiz)) { |
64 | return false; // some error occurred |
65 | } |
730fd187 |
66 | |
7bd1aa1d |
67 | |
10b9291c |
68 | // The grades for every question in this quiz are stored in an array |
7bd1aa1d |
69 | // Insert or update records as appropriate |
70 | |
71 | $existing = get_records("quiz_question_grades", "quiz", $quiz->id, "", "question,grade,id"); |
72 | |
73 | if ($quiz->grades) { |
74 | foreach ($quiz->grades as $question => $grade) { |
75 | $questiongrade->quiz = $quiz->id; |
76 | $questiongrade->question = $question; |
77 | $questiongrade->grade = $grade; |
78 | if (isset($existing[$question])) { |
79 | if ($existing[$question]->grade != $grade) { |
80 | $questiongrade->id = $existing[$question]->id; |
81 | if (!update_record("quiz_question_grades", $questiongrade)) { |
82 | return false; |
83 | } |
84 | } |
85 | } else { |
86 | if (!insert_record("quiz_question_grades", $questiongrade)) { |
87 | return false; |
88 | } |
89 | } |
90 | } |
91 | } |
92 | |
93 | return true; |
730fd187 |
94 | } |
95 | |
96 | |
97 | function quiz_delete_instance($id) { |
a5e1f35c |
98 | /// Given an ID of an instance of this module, |
99 | /// this function will permanently delete the instance |
100 | /// and any data that depends on it. |
730fd187 |
101 | |
102 | if (! $quiz = get_record("quiz", "id", "$id")) { |
103 | return false; |
104 | } |
105 | |
106 | $result = true; |
107 | |
10b9291c |
108 | if ($attempts = get_record("quiz_attempts", "quiz", "$quiz->id")) { |
109 | foreach ($attempts as $attempt) { |
110 | if (! delete_records("quiz_responses", "attempt", "$attempt->id")) { |
111 | $result = false; |
112 | } |
113 | } |
114 | } |
115 | |
116 | if (! delete_records("quiz_attempts", "quiz", "$quiz->id")) { |
117 | $result = false; |
118 | } |
119 | |
120 | if (! delete_records("quiz_grades", "quiz", "$quiz->id")) { |
121 | $result = false; |
122 | } |
123 | |
124 | if (! delete_records("quiz_question_grades", "quiz", "$quiz->id")) { |
125 | $result = false; |
126 | } |
730fd187 |
127 | |
128 | if (! delete_records("quiz", "id", "$quiz->id")) { |
129 | $result = false; |
130 | } |
131 | |
132 | return $result; |
133 | } |
134 | |
135 | function quiz_user_outline($course, $user, $mod, $quiz) { |
a5e1f35c |
136 | /// Return a small object with summary information about what a |
137 | /// user has done with a given particular instance of this module |
138 | /// Used for user activity reports. |
139 | /// $return->time = the time they did it |
140 | /// $return->info = a short text description |
730fd187 |
141 | |
142 | return $return; |
143 | } |
144 | |
145 | function quiz_user_complete($course, $user, $mod, $quiz) { |
a5e1f35c |
146 | /// Print a detailed representation of what a user has done with |
147 | /// a given particular instance of this module, for user activity reports. |
730fd187 |
148 | |
149 | return true; |
150 | } |
151 | |
152 | function quiz_print_recent_activity(&$logs, $isteacher=false) { |
a5e1f35c |
153 | /// Given a list of logs, assumed to be those since the last login |
154 | /// this function prints a short list of changes related to this module |
155 | /// If isteacher is true then perhaps additional information is printed. |
156 | /// This function is called from course/lib.php: print_recent_activity() |
730fd187 |
157 | |
158 | global $CFG, $COURSE_TEACHER_COLOR; |
159 | |
160 | return $content; // True if anything was printed, otherwise false |
161 | } |
162 | |
163 | function quiz_cron () { |
a5e1f35c |
164 | /// Function to be run periodically according to the moodle cron |
165 | /// This function searches for things that need to be done, such |
166 | /// as sending out mail, toggling flags etc ... |
730fd187 |
167 | |
168 | global $CFG; |
169 | |
170 | return true; |
171 | } |
172 | |
173 | |
174 | ////////////////////////////////////////////////////////////////////////////////////// |
a5e1f35c |
175 | /// Any other quiz functions go here. Each of them must have a name that |
176 | /// starts with quiz_ |
730fd187 |
177 | |
14d8c0b4 |
178 | function quiz_print_question($number, $questionid, $grade, $courseid) { |
a5e1f35c |
179 | /// Prints a quiz question, any format |
14d8c0b4 |
180 | |
181 | if (!$question = get_record("quiz_questions", "id", $questionid)) { |
182 | notify("Error: Question not found!"); |
183 | } |
184 | |
185 | $stranswer = get_string("answer", "quiz"); |
186 | $strmarks = get_string("marks", "quiz"); |
187 | |
188 | echo "<TABLE WIDTH=100% CELLSPACING=10><TR><TD NOWRAP WIDTH=100 VALIGN=top>"; |
189 | echo "<P ALIGN=CENTER><B>$number</B><BR><FONT SIZE=1>$grade $strmarks</FONT></P>"; |
190 | print_spacer(1,100); |
191 | echo "</TD><TD VALIGN=TOP>"; |
192 | |
193 | switch ($question->type) { |
a5e1f35c |
194 | case SHORTANSWER: |
14d8c0b4 |
195 | if (!$options = get_record("quiz_shortanswer", "question", $question->id)) { |
196 | notify("Error: Missing question options!"); |
197 | } |
2a2c9725 |
198 | echo text_to_html($question->questiontext); |
14d8c0b4 |
199 | if ($question->image) { |
200 | print_file_picture($question->image, $courseid, 200); |
201 | } |
202 | echo "<P ALIGN=RIGHT>$stranswer: <INPUT TYPE=TEXT NAME=q$question->id SIZE=20></P>"; |
203 | break; |
204 | |
a5e1f35c |
205 | case TRUEFALSE: |
14d8c0b4 |
206 | if (!$options = get_record("quiz_truefalse", "question", $question->id)) { |
207 | notify("Error: Missing question options!"); |
208 | } |
209 | if (!$true = get_record("quiz_answers", "id", $options->true)) { |
210 | notify("Error: Missing question answers!"); |
211 | } |
212 | if (!$false = get_record("quiz_answers", "id", $options->false)) { |
213 | notify("Error: Missing question answers!"); |
214 | } |
215 | if (!$true->answer) { |
216 | $true->answer = get_string("true", "quiz"); |
217 | } |
218 | if (!$false->answer) { |
219 | $false->answer = get_string("false", "quiz"); |
220 | } |
2a2c9725 |
221 | echo text_to_html($question->questiontext); |
14d8c0b4 |
222 | if ($question->image) { |
223 | print_file_picture($question->image, $courseid, 200); |
224 | } |
225 | echo "<P ALIGN=RIGHT>$stranswer: "; |
226 | echo "<INPUT TYPE=RADIO NAME=\"q$question->id\" VALUE=\"$true->id\">$true->answer"; |
227 | echo " "; |
228 | echo "<INPUT TYPE=RADIO NAME=\"q$question->id\" VALUE=\"$false->id\">$false->answer</P>"; |
229 | break; |
230 | |
a5e1f35c |
231 | case MULTICHOICE: |
14d8c0b4 |
232 | if (!$options = get_record("quiz_multichoice", "question", $question->id)) { |
233 | notify("Error: Missing question options!"); |
234 | } |
a5e1f35c |
235 | if (!$answers = get_records_list("quiz_answers", "id", $options->answers)) { |
14d8c0b4 |
236 | notify("Error: Missing question answers!"); |
237 | } |
2a2c9725 |
238 | echo text_to_html($question->questiontext); |
14d8c0b4 |
239 | if ($question->image) { |
240 | print_file_picture($question->image, $courseid, 200); |
241 | } |
242 | echo "<TABLE ALIGN=right>"; |
243 | echo "<TR><TD valign=top>$stranswer: </TD><TD>"; |
244 | echo "<TABLE ALIGN=right>"; |
245 | $answerids = explode(",", $options->answers); |
246 | foreach ($answerids as $key => $answerid) { |
247 | $answer = $answers[$answerid]; |
248 | $qnum = $key + 1; |
249 | echo "<TR><TD valign=top>"; |
a5e1f35c |
250 | if ($options->single) { |
14d8c0b4 |
251 | echo "<INPUT TYPE=RADIO NAME=q$question->id VALUE=\"$answer->id\">"; |
252 | } else { |
a5e1f35c |
253 | echo "<INPUT TYPE=CHECKBOX NAME=q$question->id"."a$answer->id VALUE=\"$answer->id\">"; |
14d8c0b4 |
254 | } |
255 | echo "</TD>"; |
256 | echo "<TD valign=top>$qnum. $answer->answer</TD>"; |
257 | echo "</TR>"; |
258 | } |
259 | echo "</TABLE>"; |
260 | echo "</TABLE>"; |
261 | break; |
262 | |
263 | default: |
264 | notify("Error: Unknown question type!"); |
265 | } |
266 | |
267 | echo "</TD></TR></TABLE>"; |
3a506ca2 |
268 | } |
269 | |
a5e1f35c |
270 | function quiz_print_quiz_questions($quiz, $results=NULL) { |
271 | // Prints a whole quiz on one page. |
272 | |
273 | if (!$quiz->questions) { |
10b9291c |
274 | notify("No questions have been defined!", "view.php?id=$cm->id"); |
275 | return false; |
a5e1f35c |
276 | } |
277 | |
278 | $questions = explode(",", $quiz->questions); |
279 | |
280 | if (!$grades = get_records_list("quiz_question_grades", "question", $quiz->questions, "", "question,grade")) { |
10b9291c |
281 | notify("No grades were found for these questions!"); |
282 | return false; |
a5e1f35c |
283 | } |
284 | |
285 | echo "<FORM METHOD=POST ACTION=attempt.php>"; |
286 | echo "<INPUT TYPE=hidden NAME=q VALUE=\"$quiz->id\">"; |
287 | foreach ($questions as $key => $questionid) { |
288 | print_simple_box_start("CENTER", "90%"); |
2a2c9725 |
289 | quiz_print_question($key+1, $questionid, $grades[$questionid]->grade, $quiz->course); |
a5e1f35c |
290 | print_simple_box_end(); |
291 | echo "<BR>"; |
292 | } |
293 | echo "<CENTER><INPUT TYPE=submit VALUE=\"".get_string("savemyanswers", "quiz")."\"></CENTER>"; |
294 | echo "</FORM>"; |
10b9291c |
295 | |
296 | return true; |
a5e1f35c |
297 | } |
6a952ce7 |
298 | |
299 | function quiz_get_default_category($courseid) { |
300 | if ($categories = get_records("quiz_categories", "course", $courseid, "id")) { |
301 | foreach ($categories as $category) { |
302 | return $category; // Return the first one (lowest id) |
303 | } |
304 | } |
305 | |
306 | // Otherwise, we need to make one |
10b9291c |
307 | $category->name = get_string("default", "quiz"); |
308 | $category->info = get_string("defaultinfo", "quiz"); |
6a952ce7 |
309 | $category->course = $courseid; |
310 | $category->publish = 0; |
311 | |
312 | if (!$category->id = insert_record("quiz_categories", $category)) { |
313 | notify("Error creating a default category!"); |
314 | return false; |
315 | } |
316 | return $category; |
317 | } |
318 | |
319 | function quiz_print_category_form($course, $current) { |
320 | // Prints a form to choose categories |
321 | |
322 | if (!$categories = get_records_sql_menu("SELECT id,name FROM quiz_categories |
323 | WHERE course='$course->id' OR publish = '1' |
324 | ORDER by name ASC")) { |
325 | if (!$category = quiz_get_default_category($course->id)) { |
326 | notify("Error creating a default category!"); |
327 | return false; |
328 | } |
329 | $categories[$category->id] = $category->name; |
330 | } |
331 | $strcategory = get_string("category", "quiz"); |
332 | $strshow = get_string("show", "quiz"); |
10b9291c |
333 | $stredit = get_string("edit"); |
6a952ce7 |
334 | $strdelete = get_string("delete"); |
335 | $strnew = get_string("new"); |
336 | |
337 | echo "<FORM METHOD=POST ACTION=edit.php>"; |
338 | echo "<B>$strcategory:</B> "; |
339 | choose_from_menu($categories, "cat", "$current"); |
340 | echo "<INPUT TYPE=submit NAME=catshow VALUE=\"$strshow\">"; |
10b9291c |
341 | echo "<INPUT TYPE=submit NAME=catedit VALUE=\"$stredit\">"; |
342 | echo "<INPUT TYPE=submit NAME=catdelete VALUE=\"$strdelete\"> "; |
6a952ce7 |
343 | echo "<INPUT TYPE=submit NAME=catnew VALUE=\"$strnew\">"; |
344 | echo "</FORM>"; |
345 | } |
346 | |
347 | |
7bd1aa1d |
348 | function quiz_get_all_question_grades($questionlist, $quizid) { |
349 | // Given a list of question IDs, finds grades or invents them to |
350 | // create an array of matching grades |
351 | |
352 | $questions = get_records_sql("SELECT * FROM quiz_question_grades |
353 | WHERE quiz = '$quizid' |
354 | AND question IN ($questionlist)"); |
355 | |
356 | $list = explode(",", $questionlist); |
357 | $grades = array(); |
358 | |
359 | foreach ($list as $qid) { |
360 | if (isset($questions[$qid])) { |
361 | $grades[$qid] = $questions[$qid]->grade; |
362 | } else { |
363 | $grades[$qid] = 1; |
364 | } |
365 | } |
366 | return $grades; |
367 | } |
368 | |
369 | |
370 | function quiz_print_question_list($questionlist, $grades) { |
6a952ce7 |
371 | // Prints a list of quiz questions in a small layout form with knobs |
7bd1aa1d |
372 | // $questionlist is comma-separated list |
373 | // $grades is an array of corresponding grades |
6a952ce7 |
374 | |
375 | global $THEME; |
376 | |
377 | if (!$questionlist) { |
378 | echo "<P align=center>"; |
379 | print_string("noquestions", "quiz"); |
380 | echo "</P>"; |
381 | return; |
382 | } |
383 | |
384 | $order = explode(",", $questionlist); |
385 | |
7bd1aa1d |
386 | if (!$questions = get_records_list("quiz_questions", "id", $questionlist)) { |
6a952ce7 |
387 | error("No questions were found!"); |
388 | } |
389 | |
390 | $strorder = get_string("order"); |
391 | $strquestionname = get_string("questionname", "quiz"); |
392 | $strgrade = get_string("grade"); |
393 | $strdelete = get_string("delete"); |
394 | $stredit = get_string("edit"); |
395 | $strmoveup = get_string("moveup"); |
396 | $strmovedown = get_string("movedown"); |
397 | $strsavegrades = get_string("savegrades", "quiz"); |
398 | |
10b9291c |
399 | for ($i=10; $i>=0; $i--) { |
7bd1aa1d |
400 | $gradesmenu[$i] = $i; |
6a952ce7 |
401 | } |
402 | $count = 0; |
403 | $sumgrade = 0; |
404 | $total = count($order); |
405 | echo "<FORM METHOD=post ACTION=edit.php>"; |
406 | echo "<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=2 WIDTH=\"100%\">"; |
10b9291c |
407 | echo "<TR><TH WIDTH=10 COLSPAN=3>$strorder</TH><TH align=left WIDTH=\"100%\">$strquestionname</TH><TH WIDTH=10>$strgrade</TH><TH WIDTH=10>$stredit</TH></TR>"; |
6a952ce7 |
408 | foreach ($order as $qnum) { |
409 | $count++; |
410 | echo "<TR BGCOLOR=\"$THEME->cellcontent\">"; |
411 | echo "<TD>$count</TD>"; |
412 | echo "<TD>"; |
413 | if ($count != 1) { |
414 | echo "<A TITLE=\"$strmoveup\" HREF=\"edit.php?up=$qnum\"><IMG |
415 | SRC=\"../../pix/t/up.gif\" BORDER=0></A>"; |
416 | } |
417 | echo "</TD>"; |
418 | echo "<TD>"; |
419 | if ($count != $total) { |
420 | echo "<A TITLE=\"$strmovedown\" HREF=\"edit.php?down=$qnum\"><IMG |
421 | SRC=\"../../pix/t/down.gif\" BORDER=0></A>"; |
422 | } |
423 | echo "</TD>"; |
424 | echo "<TD>".$questions[$qnum]->name."</TD>"; |
425 | echo "<TD>"; |
7bd1aa1d |
426 | choose_from_menu($gradesmenu, "q$qnum", $grades[$qnum], ""); |
6a952ce7 |
427 | echo "<TD>"; |
428 | echo "<A TITLE=\"$strdelete\" HREF=\"edit.php?delete=$qnum\"><IMG |
429 | SRC=\"../../pix/t/delete.gif\" BORDER=0></A> "; |
430 | echo "<A TITLE=\"$stredit\" HREF=\"question.php?id=$qnum\"><IMG |
431 | SRC=\"../../pix/t/edit.gif\" BORDER=0></A>"; |
432 | echo "</TD>"; |
433 | |
7bd1aa1d |
434 | $sumgrade += $grades[$qnum]; |
6a952ce7 |
435 | } |
436 | echo "<TR><TD COLSPAN=3><TD ALIGN=right>"; |
437 | echo "<INPUT TYPE=submit VALUE=\"$strsavegrades:\">"; |
438 | echo "<INPUT TYPE=hidden NAME=grade VALUE=\"save\">"; |
439 | echo "<TD ALIGN=LEFT BGCOLOR=\"$THEME->cellcontent\">"; |
440 | echo "<B>$sumgrade</B>"; |
441 | echo "</TD><TD></TD></TR>"; |
442 | echo "</TABLE>"; |
443 | echo "</FORM>"; |
10b9291c |
444 | |
445 | return $sumgrade; |
6a952ce7 |
446 | } |
447 | |
448 | |
449 | function quiz_print_cat_question_list($categoryid) { |
450 | // Prints a form to choose categories |
451 | |
452 | global $THEME, $QUIZ_QUESTION_TYPE; |
453 | |
10b9291c |
454 | $strcategory = get_string("category", "quiz"); |
6a952ce7 |
455 | $strquestion = get_string("question", "quiz"); |
456 | $strnoquestions = get_string("noquestions", "quiz"); |
457 | $strselect = get_string("select", "quiz"); |
458 | $strcreatenewquestion = get_string("createnewquestion", "quiz"); |
459 | $strquestionname = get_string("questionname", "quiz"); |
460 | $strdelete = get_string("delete"); |
461 | $stredit = get_string("edit"); |
462 | $straddselectedtoquiz = get_string("addselectedtoquiz", "quiz"); |
463 | |
464 | if (!$categoryid) { |
465 | echo "<P align=center>"; |
466 | print_string("selectcategoryabove", "quiz"); |
467 | echo "</P>"; |
468 | return; |
469 | } |
a5e1f35c |
470 | |
6a952ce7 |
471 | if (!$category = get_record("quiz_categories", "id", "$categoryid")) { |
472 | notify("Category not found!"); |
473 | return; |
474 | } |
10b9291c |
475 | echo "<P><B>$strcategory:</B> $category->name</P>\n"; |
476 | echo text_to_html($category->info); |
6a952ce7 |
477 | |
10b9291c |
478 | echo "<FORM METHOD=GET ACTION=question.php>"; |
6a952ce7 |
479 | echo "<B>$strquestion:</B> "; |
480 | choose_from_menu($QUIZ_QUESTION_TYPE, "type", "", ""); |
481 | echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">"; |
482 | echo "<INPUT TYPE=submit NAME=new VALUE=\"$strcreatenewquestion\">"; |
483 | echo "</FORM>"; |
484 | |
485 | if (!$questions = get_records("quiz_questions", "category", $category->id)) { |
486 | echo "<P align=center>"; |
487 | print_string("noquestions", "quiz"); |
488 | echo "</P>"; |
489 | return; |
490 | } |
491 | |
10b9291c |
492 | $canedit = isteacher($category->course); |
493 | |
6a952ce7 |
494 | echo "<FORM METHOD=post ACTION=edit.php>"; |
495 | echo "<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=2 WIDTH=\"100%\">"; |
10b9291c |
496 | echo "<TR><TH width=10>$strselect</TH><TH width=* align=left>$strquestionname</TH>"; |
497 | if ($canedit) { |
498 | echo "<TH width=10>$stredit</TH>"; |
499 | } |
500 | echo "</TR>"; |
6a952ce7 |
501 | foreach ($questions as $question) { |
502 | echo "<TR BGCOLOR=\"$THEME->cellcontent\">"; |
503 | echo "<TD ALIGN=CENTER>"; |
504 | echo "<INPUT TYPE=CHECKBOX NAME=q$question->id VALUE=\"1\">"; |
505 | echo "</TD>"; |
506 | echo "<TD>".$question->name."</TD>"; |
10b9291c |
507 | if ($canedit) { |
508 | echo "<TD>"; |
509 | echo "<A TITLE=\"$strdelete\" HREF=\"question.php?delete=$question->id\"><IMG |
510 | SRC=\"../../pix/t/delete.gif\" BORDER=0></A> "; |
511 | echo "<A TITLE=\"$stredit\" HREF=\"question.php?id=$question->id\"><IMG |
512 | SRC=\"../../pix/t/edit.gif\" BORDER=0></A>"; |
513 | echo "</TD></TR>"; |
514 | } |
515 | echo "</TR>"; |
6a952ce7 |
516 | } |
517 | echo "<TR><TD COLSPAN=3>"; |
518 | echo "<INPUT TYPE=hidden NAME=add VALUE=\"1\">"; |
519 | echo "<INPUT TYPE=submit VALUE=\"<< $straddselectedtoquiz\">"; |
520 | echo "</TD></TR>"; |
521 | echo "</TABLE>"; |
522 | echo "</FORM>"; |
523 | } |
a5e1f35c |
524 | |
3a506ca2 |
525 | |
526 | function quiz_get_user_attempts($quizid, $userid) { |
a5e1f35c |
527 | // Returns a list of all attempts by a user |
3a506ca2 |
528 | return get_records_sql("SELECT * FROM quiz_attempts WHERE quiz = '$quizid' and user = '$userid' ORDER by attempt ASC"); |
529 | } |
530 | |
a5e1f35c |
531 | function quiz_get_best_grade($quizid, $userid) { |
532 | /// Get the best current grade for a particular user in a quiz |
3a506ca2 |
533 | if (!$grade = get_record_sql("SELECT * FROM quiz_grades WHERE quiz = '$quizid' and user = '$userid'")) { |
534 | return 0; |
535 | } |
536 | |
537 | return $grade->grade; |
538 | } |
539 | |
579ddad5 |
540 | function quiz_get_grade_records($quiz) { |
541 | /// Gets all info required to display the table of quiz results |
542 | /// for report.php |
543 | |
544 | return get_records_sql("SELECT qg.*, u.firstname, u.lastname, u.picture |
545 | FROM quiz_grades qg, user u |
546 | WHERE qg.quiz = '$quiz->id' |
547 | AND qg.user = u.id"); |
548 | } |
549 | |
a5e1f35c |
550 | function quiz_save_best_grade($quiz, $user) { |
551 | /// Calculates the best grade out of all attempts at a quiz for a user, |
552 | /// and then saves that grade in the quiz_grades table. |
553 | |
554 | if (!$attempts = quiz_get_user_attempts($quiz->id, $user->id)) { |
555 | return false; |
556 | } |
557 | |
558 | $bestgrade = quiz_calculate_best_grade($quiz, $attempts); |
559 | $bestgrade = (($bestgrade / $quiz->sumgrades) * $quiz->grade); |
560 | |
561 | if ($grade = get_record_sql("SELECT * FROM quiz_grades WHERE quiz='$quiz->id' AND user='$user->id'")) { |
562 | $grade->grade = $bestgrade; |
563 | $grade->timemodified = time(); |
564 | if (!update_record("quiz_grades", $grade)) { |
565 | return false; |
566 | } |
567 | } else { |
568 | $grade->quiz = $quiz->id; |
569 | $grade->user = $user->id; |
570 | $grade->grade = $bestgrade; |
571 | $grade->timemodified = time(); |
572 | if (!insert_record("quiz_grades", $grade)) { |
573 | return false; |
574 | } |
575 | } |
576 | return true; |
577 | } |
578 | |
579 | |
2a2c9725 |
580 | function quiz_get_answers($question) { |
a5e1f35c |
581 | // Given a question, returns the correct answers and grades |
582 | switch ($question->type) { |
583 | case SHORTANSWER; // Could be multiple answers |
2a2c9725 |
584 | return get_records_sql("SELECT a.*, sa.usecase, g.grade |
a5e1f35c |
585 | FROM quiz_shortanswer sa, quiz_answers a, quiz_question_grades g |
586 | WHERE sa.question = '$question->id' |
587 | AND sa.question = a.question |
588 | AND sa.question = g.question"); |
589 | break; |
590 | |
591 | case TRUEFALSE; // Should be always two answers |
592 | return get_records_sql("SELECT a.*, g.grade |
593 | FROM quiz_answers a, quiz_question_grades g |
594 | WHERE a.question = '$question->id' |
595 | AND a.question = g.question"); |
596 | break; |
597 | |
598 | case MULTICHOICE; // Should be multiple answers |
599 | return get_records_sql("SELECT a.*, mc.single, g.grade |
600 | FROM quiz_multichoice mc, quiz_answers a, quiz_question_grades g |
601 | WHERE mc.question = '$question->id' |
602 | AND mc.question = a.question |
603 | AND mc.question = g.question"); |
604 | break; |
605 | |
606 | default: |
607 | return false; |
608 | } |
609 | } |
610 | |
3a506ca2 |
611 | function quiz_calculate_best_grade($quiz, $attempts) { |
a5e1f35c |
612 | /// Calculate the best grade for a quiz given a number of attempts by a particular user. |
3a506ca2 |
613 | |
614 | switch ($quiz->grademethod) { |
a5e1f35c |
615 | |
616 | case ATTEMPTFIRST: |
3a506ca2 |
617 | foreach ($attempts as $attempt) { |
a5e1f35c |
618 | return $attempt->sumgrades; |
3a506ca2 |
619 | } |
a5e1f35c |
620 | break; |
621 | |
622 | case ATTEMPTLAST: |
623 | foreach ($attempts as $attempt) { |
624 | $final = $attempt->sumgrades; |
625 | } |
626 | return $final; |
3a506ca2 |
627 | |
a5e1f35c |
628 | case GRADEAVERAGE: |
3a506ca2 |
629 | $sum = 0; |
630 | $count = 0; |
631 | foreach ($attempts as $attempt) { |
a5e1f35c |
632 | $sum += $attempt->sumgrades; |
3a506ca2 |
633 | $count++; |
634 | } |
635 | return (float)$sum/$count; |
636 | |
3a506ca2 |
637 | default: |
a5e1f35c |
638 | case GRADEHIGHEST: |
639 | $max = 0; |
3a506ca2 |
640 | foreach ($attempts as $attempt) { |
a5e1f35c |
641 | if ($attempt->sumgrades > $max) { |
642 | $max = $attempt->sumgrades; |
643 | } |
3a506ca2 |
644 | } |
a5e1f35c |
645 | return $max; |
646 | } |
647 | } |
648 | |
649 | function quiz_save_attempt($quiz, $questions, $result, $attemptnum) { |
650 | /// Given a quiz, a list of attempted questions and a total grade |
651 | /// this function saves EVERYTHING so it can be reconstructed later |
652 | /// if necessary. |
653 | |
654 | global $USER; |
655 | |
656 | // First let's save the attempt record itself |
657 | |
658 | $attempt->quiz = $quiz->id; |
659 | $attempt->user = $USER->id; |
660 | $attempt->attempt = $attemptnum; |
661 | $attempt->sumgrades = $result->sumgrades; |
662 | $attempt->timemodified = time(); |
663 | |
664 | if (!$attempt->id = insert_record("quiz_attempts", $attempt)) { |
665 | return false; |
666 | } |
667 | |
668 | // Now let's save all the questions for this attempt |
669 | |
670 | foreach ($questions as $question) { |
671 | $response->attempt = $attempt->id; |
672 | $response->question = $question->id; |
673 | $response->grade = $result->grades[$question->id]; |
674 | if ($question->answer) { |
675 | $response->answer = implode(",",$question->answer); |
676 | } else { |
677 | $response->answer = ""; |
678 | } |
679 | if (!insert_record("quiz_responses", $response)) { |
680 | return false; |
681 | } |
3a506ca2 |
682 | } |
a5e1f35c |
683 | return true; |
3a506ca2 |
684 | } |
730fd187 |
685 | |
a5e1f35c |
686 | |
687 | function quiz_grade_attempt_results($quiz, $questions) { |
688 | /// Given a list of questions (including answers for each one) |
689 | /// this function does all the hard work of calculating the |
690 | /// grades for each question, as well as a total grade for |
691 | /// for the whole quiz. It returns everything in a structure |
692 | /// that looks like: |
693 | /// $result->sumgrades (sum of all grades for all questions) |
694 | /// $result->percentage (Percentage of grades that were correct) |
695 | /// $result->grade (final grade result for the whole quiz) |
696 | /// $result->grades[] (array of grades, indexed by question id) |
697 | /// $result->feedback[] (array of feedback arrays, indexed by question id) |
698 | |
699 | if (!$questions) { |
700 | error("No questions!"); |
701 | } |
702 | |
703 | $result->sumgrades = 0; |
704 | |
2a2c9725 |
705 | global $db; |
706 | $db->debug=true; |
707 | |
a5e1f35c |
708 | foreach ($questions as $question) { |
2a2c9725 |
709 | if (!$answers = quiz_get_answers($question)) { |
710 | error("No answers defined for question id $question->id!"); |
a5e1f35c |
711 | } |
712 | |
713 | $grade = 0; // default |
714 | $feedback = array (); |
715 | |
716 | switch ($question->type) { |
717 | case SHORTANSWER: |
718 | if ($question->answer) { |
719 | $question->answer = $question->answer[0]; |
720 | } else { |
721 | $question->answer = NULL; |
722 | } |
723 | foreach($answers as $answer) { // There might be multiple right answers |
724 | $feedback[$answer->id] = $answer->feedback; |
2a2c9725 |
725 | if (!$answer->usecase) { // Don't compare case |
a5e1f35c |
726 | $answer->answer = strtolower($answer->answer); |
727 | $question->answer = strtolower($question->answer); |
728 | } |
729 | if ($question->answer == $answer->answer) { |
730 | $grade = (float)$answer->fraction * $answer->grade; |
731 | } |
732 | } |
733 | break; |
734 | |
735 | |
736 | case TRUEFALSE: |
737 | if ($question->answer) { |
738 | $question->answer = $question->answer[0]; |
739 | } else { |
740 | $question->answer = NULL; |
741 | } |
742 | foreach($answers as $answer) { // There should be two answers (true and false) |
743 | $feedback[$answer->id] = $answer->feedback; |
744 | if ($question->answer == $answer->id) { |
745 | $grade = (float)$answer->fraction * $answer->grade; |
746 | } |
747 | } |
748 | break; |
749 | |
750 | |
751 | case MULTICHOICE: |
752 | foreach($answers as $answer) { // There will be multiple answers, perhaps more than one is right |
753 | $feedback[$answer->id] = $answer->feedback; |
754 | if ($question->answer) { |
755 | foreach ($question->answer as $questionanswer) { |
756 | if ($questionanswer == $answer->id) { |
757 | if ($answer->single) { |
758 | $grade = (float)$answer->fraction * $answer->grade; |
759 | continue; |
760 | } else { |
761 | $grade += (float)$answer->fraction * $answer->grade; |
762 | } |
763 | } |
764 | } |
765 | } |
766 | } |
767 | break; |
768 | |
769 | |
770 | } |
771 | if ($grade < 0.0) { // No negative grades |
772 | $grade = 0.0; |
773 | } |
10b9291c |
774 | |
a5e1f35c |
775 | $result->grades[$question->id] = $grade; |
776 | $result->sumgrades += $grade; |
777 | $result->feedback[$question->id] = $feedback; |
778 | } |
779 | |
780 | $result->percentage = ($result->sumgrades / $quiz->sumgrades); |
781 | $result->grade = $result->percentage * $quiz->grade; |
782 | |
783 | return $result; |
784 | } |
785 | |
730fd187 |
786 | ?> |