Fix a possible race condition in the PaintWeb DML code.
[moodle/mihaisucan.git] / mod / lesson / report.php
bloba0f0803cfbf17cf3f7c01d22243d81319e9f60df
1 <?php // $Id$
2 /**
3 * Displays the lesson statistics.
5 * @version $Id$
6 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
7 * @package lesson
8 **/
10 require_once('../../config.php');
11 require_once('lib.php');
12 require_once('locallib.php');
14 $id = required_param('id', PARAM_INT); // Course Module ID
15 $pageid = optional_param('pageid', NULL, PARAM_INT); // Lesson Page ID
16 $action = optional_param('action', 'reportoverview', PARAM_ALPHA); // action to take
17 $nothingtodisplay = false;
19 list($cm, $course, $lesson) = lesson_get_basics($id);
21 if (!empty($CFG->enablegroupings) && !empty($cm->groupingid)) {
22 $sql = "SELECT DISTINCT u.*
23 FROM {$CFG->prefix}lesson_attempts a
24 INNER JOIN {$CFG->prefix}user u ON u.id = a.userid
25 INNER JOIN {$CFG->prefix}groups_members gm ON gm.userid = u.id
26 INNER JOIN {$CFG->prefix}groupings_groups gg ON gm.groupid = {$cm->groupingid}
27 WHERE a.lessonid = '$lesson->id'
28 ORDER BY u.lastname";
29 } else {
30 $sql = "SELECT u.*
31 FROM {$CFG->prefix}user u,
32 {$CFG->prefix}lesson_attempts a
33 WHERE a.lessonid = '$lesson->id' and
34 u.id = a.userid
35 ORDER BY u.lastname";
38 if (! $students = get_records_sql($sql)) {
39 $nothingtodisplay = true;
42 // make sure people are where they should be
43 require_login($course->id, false, $cm);
44 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
45 require_capability('mod/lesson:manage', $context);
47 /// Process any form data before fetching attempts, grades and times
48 if (has_capability('mod/lesson:edit', $context) and
49 $form = data_submitted($CFG->wwwroot.'/mod/lesson/report.php') and
50 confirm_sesskey()) {
51 /// Cycle through array of userids with nested arrays of tries
52 if (!empty($form->attempts)) {
53 foreach ($form->attempts as $userid => $tries) {
54 // Modifier IS VERY IMPORTANT! What does it do?
55 // Well, it is for when you delete multiple attempts for the same user.
56 // If you delete try 1 and 3 for a user, then after deleting try 1, try 3 then
57 // becomes try 2 (because try 1 is gone and all tries after try 1 get decremented).
58 // So, the modifier makes sure that the submitted try refers to the current try in the
59 // database - hope this all makes sense :)
60 $modifier = 0;
62 foreach ($tries as $try => $junk) {
63 $try -= $modifier;
65 /// Clean up the timer table
66 $timeid = get_field_sql("SELECT id FROM {$CFG->prefix}lesson_timer
67 WHERE userid = $userid AND lessonid = $lesson->id
68 ORDER BY starttime", $try, 1);
70 delete_records('lesson_timer', 'id', $timeid);
72 /// Remove the grade from the grades and high_scores tables
73 $gradeid = get_field_sql("SELECT id FROM {$CFG->prefix}lesson_grades
74 WHERE userid = $userid AND lessonid = $lesson->id
75 ORDER BY completed", $try, 1);
77 delete_records('lesson_grades', 'id', $gradeid);
78 delete_records('lesson_high_scores', 'gradeid', $gradeid, 'lessonid', $lesson->id, 'userid', $userid);
80 /// Remove attempts and update the retry number
81 delete_records('lesson_attempts', 'userid', $userid, 'lessonid', $lesson->id, 'retry', $try);
82 execute_sql("UPDATE {$CFG->prefix}lesson_attempts SET retry = retry - 1 WHERE userid = $userid AND lessonid = $lesson->id AND retry > $try", false);
84 /// Remove seen branches and update the retry number
85 delete_records('lesson_branch', 'userid', $userid, 'lessonid', $lesson->id, 'retry', $try);
86 execute_sql("UPDATE {$CFG->prefix}lesson_branch SET retry = retry - 1 WHERE userid = $userid AND lessonid = $lesson->id AND retry > $try", false);
88 /// update central gradebook
89 lesson_update_grades($lesson, $userid);
91 $modifier++;
94 lesson_set_message(get_string('attemptsdeleted', 'lesson'), 'notifysuccess');
98 if (! $attempts = get_records('lesson_attempts', 'lessonid', $lesson->id, 'timeseen')) {
99 $nothingtodisplay = true;
102 if (! $grades = get_records('lesson_grades', 'lessonid', $lesson->id, 'completed')) {
103 $grades = array();
106 if (! $times = get_records('lesson_timer', 'lessonid', $lesson->id, 'starttime')) {
107 $times = array();
110 lesson_print_header($cm, $course, $lesson, $action);
112 $course_context = get_context_instance(CONTEXT_COURSE, $course->id);
113 if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
114 echo '<div class="allcoursegrades"><a href="' . $CFG->wwwroot . '/grade/report/grader/index.php?id=' . $course->id . '">'
115 . get_string('seeallcoursegrades', 'grades') . '</a></div>';
118 if ($nothingtodisplay) {
119 notify(get_string('nolessonattempts', 'lesson'));
120 print_footer($course);
121 exit();
124 /**************************************************************************
125 this action is for default view and overview view
126 **************************************************************************/
127 if ($action == 'reportoverview') {
128 $studentdata = array();
130 // build an array for output
131 foreach ($attempts as $attempt) {
132 // if the user is not in the array or if the retry number is not in the sub array, add the data for that try.
133 if (!array_key_exists($attempt->userid, $studentdata) || !array_key_exists($attempt->retry, $studentdata[$attempt->userid])) {
134 // restore/setup defaults
135 $n = 0;
136 $timestart = 0;
137 $timeend = 0;
138 $usergrade = NULL;
140 // search for the grade record for this try. if not there, the nulls defined above will be used.
141 foreach($grades as $grade) {
142 // check to see if the grade matches the correct user
143 if ($grade->userid == $attempt->userid) {
144 // see if n is = to the retry
145 if ($n == $attempt->retry) {
146 // get grade info
147 $usergrade = round($grade->grade, 2); // round it here so we only have to do it once
148 break;
150 $n++; // if not equal, then increment n
153 $n = 0;
154 // search for the time record for this try. if not there, the nulls defined above will be used.
155 foreach($times as $time) {
156 // check to see if the grade matches the correct user
157 if ($time->userid == $attempt->userid) {
158 // see if n is = to the retry
159 if ($n == $attempt->retry) {
160 // get grade info
161 $timeend = $time->lessontime;
162 $timestart = $time->starttime;
163 break;
165 $n++; // if not equal, then increment n
169 // build up the array.
170 // this array represents each student and all of their tries at the lesson
171 $studentdata[$attempt->userid][$attempt->retry] = array( "timestart" => $timestart,
172 "timeend" => $timeend,
173 "grade" => $usergrade,
174 "try" => $attempt->retry,
175 "userid" => $attempt->userid);
178 // set all the stats variables
179 $numofattempts = 0;
180 $avescore = 0;
181 $avetime = 0;
182 $highscore = NULL;
183 $lowscore = NULL;
184 $hightime = NULL;
185 $lowtime = NULL;
186 $table = new stdClass;
188 // set up the table object
189 $table->head = array(get_string('studentname', 'lesson', $course->student), get_string('attempts', 'lesson'), get_string('highscore', 'lesson'));
190 $table->align = array("center", "left", "left");
191 $table->wrap = array("nowrap", "nowrap", "nowrap");
192 $table->width = "90%";
193 $table->size = array("*", "70%", "*");
195 // print out the $studentdata array
196 // going through each student that has attempted the lesson, so, each student should have something to be displayed
197 foreach ($students as $student) {
198 // check to see if the student has attempts to print out
199 if (array_key_exists($student->id, $studentdata)) {
200 // set/reset some variables
201 $attempts = array();
202 // gather the data for each user attempt
203 $bestgrade = 0;
204 $bestgradefound = false;
205 // $tries holds all the tries/retries a student has done
206 $tries = $studentdata[$student->id];
207 $studentname = "{$student->lastname},&nbsp;$student->firstname";
208 foreach ($tries as $try) {
209 // start to build up the checkbox and link
210 if (has_capability('mod/lesson:edit', $context)) {
211 $temp = '<input type="checkbox" id="attempts" name="attempts['.$try['userid'].']['.$try['try'].']" /> ';
212 } else {
213 $temp = '';
216 $temp .= "<a href=\"report.php?id=$cm->id&amp;action=reportdetail&amp;userid=".$try['userid'].'&amp;try='.$try['try'].'">';
217 if ($try["grade"] !== NULL) { // if NULL then not done yet
218 // this is what the link does when the user has completed the try
219 $timetotake = $try["timeend"] - $try["timestart"];
221 $temp .= $try["grade"]."%";
222 $bestgradefound = true;
223 if ($try["grade"] > $bestgrade) {
224 $bestgrade = $try["grade"];
226 $temp .= "&nbsp;".userdate($try["timestart"]);
227 $temp .= ",&nbsp;(".format_time($timetotake).")</a>";
228 } else {
229 // this is what the link does/looks like when the user has not completed the try
230 $temp .= get_string("notcompleted", "lesson");
231 $temp .= "&nbsp;".userdate($try["timestart"])."</a>";
232 $timetotake = NULL;
234 // build up the attempts array
235 $attempts[] = $temp;
237 // run these lines for the stats only if the user finnished the lesson
238 if ($try["grade"] !== NULL) {
239 $numofattempts++;
240 $avescore += $try["grade"];
241 $avetime += $timetotake;
242 if ($try["grade"] > $highscore || $highscore == NULL) {
243 $highscore = $try["grade"];
245 if ($try["grade"] < $lowscore || $lowscore == NULL) {
246 $lowscore = $try["grade"];
248 if ($timetotake > $hightime || $hightime == NULL) {
249 $hightime = $timetotake;
251 if ($timetotake < $lowtime || $lowtime == NULL) {
252 $lowtime = $timetotake;
256 // get line breaks in after each attempt
257 $attempts = implode("<br />\n", $attempts);
258 // add it to the table data[] object
259 $table->data[] = array($studentname, $attempts, $bestgrade."%");
262 // print it all out !
263 if (has_capability('mod/lesson:edit', $context)) {
264 echo "<form id=\"theform\" method=\"post\" action=\"report.php\">\n
265 <input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />\n
266 <input type=\"hidden\" name=\"id\" value=\"$cm->id\" />\n
267 <input type=\"hidden\" name=\"id\" value=\"$cm->id\" />\n";
269 print_table($table);
271 if (has_capability('mod/lesson:edit', $context)) {
272 echo '<br /><table width="90%" align="center"><tr><td>'.
273 '<a href="javascript: checkall();">'.get_string('selectall').'</a> / '.
274 '<a href="javascript: checknone();">'.get_string('deselectall').'</a> ';
276 $options = array();
277 $options['delete'] = get_string('deleteselected');
278 choose_from_menu($options, 'attemptaction', 0, 'choose', 'submitFormById(\'theform\')');
280 echo '</td></tr></table></form>';
283 // some stat calculations
284 if ($numofattempts == 0) {
285 $avescore = get_string("notcompleted", "lesson");
286 } else {
287 $avescore = format_float($avescore/$numofattempts, 2);
289 if ($avetime == NULL) {
290 $avetime = get_string("notcompleted", "lesson");
291 } else {
292 $avetime = format_float($avetime/$numofattempts, 0);
293 $avetime = format_time($avetime);
295 if ($hightime == NULL) {
296 $hightime = get_string("notcompleted", "lesson");
297 } else {
298 $hightime = format_time($hightime);
300 if ($lowtime == NULL) {
301 $lowtime = get_string("notcompleted", "lesson");
302 } else {
303 $lowtime = format_time($lowtime);
305 if ($highscore == NULL) {
306 $highscore = get_string("notcompleted", "lesson");
308 if ($lowscore == NULL) {
309 $lowscore = get_string("notcompleted", "lesson");
312 // output the stats
313 print_heading(get_string('lessonstats', 'lesson'));
314 $stattable = new stdClass;
315 $stattable->head = array(get_string('averagescore', 'lesson'), get_string('averagetime', 'lesson'),
316 get_string('highscore', 'lesson'), get_string('lowscore', 'lesson'),
317 get_string('hightime', 'lesson'), get_string('lowtime', 'lesson'));
318 $stattable->align = array("center", "center", "center", "center", "center", "center");
319 $stattable->wrap = array("nowrap", "nowrap", "nowrap", "nowrap", "nowrap", "nowrap");
320 $stattable->width = "90%";
321 $stattable->data[] = array($avescore.'%', $avetime, $highscore.'%', $lowscore.'%', $hightime, $lowtime);
323 print_table($stattable);
325 /**************************************************************************
326 this action is for a student detailed view and for the general detailed view
328 General flow of this section of the code
329 1. Generate a object which holds values for the statistics for each question/answer
330 2. Cycle through all the pages to create a object. Foreach page, see if the student actually answered
331 the page. Then process the page appropriatly. Display all info about the question,
332 Highlight correct answers, show how the user answered the question, and display statistics
333 about each page
334 3. Print out info about the try (if needed)
335 4. Print out the object which contains all the try info
337 **************************************************************************/
338 else if ($action == 'reportdetail') {
340 $formattextdefoptions = new stdClass;
341 $formattextdefoptions->para = false; //I'll use it widely in this page
343 $userid = optional_param('userid', NULL, PARAM_INT); // if empty, then will display the general detailed view
344 $try = optional_param('try', NULL, PARAM_INT);
346 if (! $lessonpages = get_records("lesson_pages", "lessonid", $lesson->id)) {
347 error("Could not find Lesson Pages");
349 if (! $pageid = get_field("lesson_pages", "id", "lessonid", $lesson->id, "prevpageid", 0)) {
350 error("Could not find first page");
353 // now gather the stats into an object
354 $firstpageid = $pageid;
355 $pagestats = array();
356 while ($pageid != 0) { // EOL
357 $page = $lessonpages[$pageid];
359 if ($allanswers = get_records_select("lesson_attempts", "lessonid = $lesson->id AND pageid = $page->id", "timeseen")) {
360 // get them ready for processing
361 $orderedanswers = array();
362 foreach ($allanswers as $singleanswer) {
363 // ordering them like this, will help to find the single attempt record that we want to keep.
364 $orderedanswers[$singleanswer->userid][$singleanswer->retry][] = $singleanswer;
366 // this is foreach user and for each try for that user, keep one attempt record
367 foreach ($orderedanswers as $orderedanswer) {
368 foreach($orderedanswer as $tries) {
369 if(count($tries) > $lesson->maxattempts) { // if there are more tries than the max that is allowed, grab the last "legal" attempt
370 $temp = $tries[$lesson->maxattempts - 1];
371 } else {
372 // else, user attempted the question less than the max, so grab the last one
373 $temp = end($tries);
375 // page interpretation
376 // depending on the page type, process stat info for that page
377 switch ($page->qtype) {
378 case LESSON_MULTICHOICE:
379 case LESSON_TRUEFALSE:
380 if ($page->qoption) {
381 $userresponse = explode(",", $temp->useranswer);
382 foreach ($userresponse as $response) {
383 if (isset($pagestats[$temp->pageid][$response])) {
384 $pagestats[$temp->pageid][$response]++;
385 } else {
386 $pagestats[$temp->pageid][$response] = 1;
389 } else {
390 if (isset($pagestats[$temp->pageid][$temp->answerid])) {
391 $pagestats[$temp->pageid][$temp->answerid]++;
392 } else {
393 $pagestats[$temp->pageid][$temp->answerid] = 1;
396 if (isset($pagestats[$temp->pageid]["total"])) {
397 $pagestats[$temp->pageid]["total"]++;
398 } else {
399 $pagestats[$temp->pageid]["total"] = 1;
401 break;
402 case LESSON_SHORTANSWER:
403 case LESSON_NUMERICAL:
404 if (isset($pagestats[$temp->pageid][$temp->useranswer])) {
405 $pagestats[$temp->pageid][$temp->useranswer]++;
406 } else {
407 $pagestats[$temp->pageid][$temp->useranswer] = 1;
409 if (isset($pagestats[$temp->pageid]["total"])) {
410 $pagestats[$temp->pageid]["total"]++;
411 } else {
412 $pagestats[$temp->pageid]["total"] = 1;
414 break;
415 case LESSON_MATCHING:
416 if ($temp->correct) {
417 if (isset($pagestats[$temp->pageid]["correct"])) {
418 $pagestats[$temp->pageid]["correct"]++;
419 } else {
420 $pagestats[$temp->pageid]["correct"] = 1;
423 if (isset($pagestats[$temp->pageid]["total"])) {
424 $pagestats[$temp->pageid]["total"]++;
425 } else {
426 $pagestats[$temp->pageid]["total"] = 1;
428 break;
429 case LESSON_ESSAY:
430 $essayinfo = unserialize($temp->useranswer);
431 if ($essayinfo->graded) {
432 if (isset($pagestats[$temp->pageid])) {
433 $essaystats = $pagestats[$temp->pageid];
434 $essaystats->totalscore += $essayinfo->score;
435 $essaystats->total++;
436 $pagestats[$temp->pageid] = $essaystats;
437 } else {
438 $essaystats->totalscore = $essayinfo->score;
439 $essaystats->total = 1;
440 $pagestats[$temp->pageid] = $essaystats;
443 break;
448 } else {
449 // no one answered yet...
451 //unset($orderedanswers); initialized above now
452 $pageid = $page->nextpageid;
457 $answerpages = array();
458 $answerpage = "";
459 $pageid = $firstpageid;
460 // cycle through all the pages
461 // foreach page, add to the $answerpages[] array all the data that is needed
462 // from the question, the users attempt, and the statistics
463 // grayout pages that the user did not answer and Branch, end of branch, cluster
464 // and end of cluster pages
465 while ($pageid != 0) { // EOL
466 $page = $lessonpages[$pageid];
467 $answerpage = new stdClass;
468 $data ='';
469 $answerdata = new stdClass;
471 $answerpage->title = format_string($page->title);
473 $options = new stdClass;
474 $options->noclean = true;
475 $answerpage->contents = format_text($page->contents, FORMAT_MOODLE, $options);
477 // get the page qtype
478 switch ($page->qtype) {
479 case LESSON_ESSAY :
480 case LESSON_MATCHING :
481 case LESSON_TRUEFALSE :
482 case LESSON_NUMERICAL :
483 $answerpage->qtype = $LESSON_QUESTION_TYPE[$page->qtype];
484 $answerpage->grayout = 0;
485 break;
486 case LESSON_SHORTANSWER :
487 $answerpage->qtype = $LESSON_QUESTION_TYPE[$page->qtype];
488 if ($page->qoption) {
489 $answerpage->qtype .= " - ".get_string("casesensitive", "lesson");
491 $answerpage->grayout = 0;
492 break;
493 case LESSON_MULTICHOICE :
494 $answerpage->qtype = $LESSON_QUESTION_TYPE[$page->qtype];
495 if ($page->qoption) {
496 $answerpage->qtype .= " - ".get_string("multianswer", "lesson");
498 $answerpage->grayout = 0;
499 break;
500 case LESSON_BRANCHTABLE :
501 $answerpage->qtype = get_string("branchtable", "lesson");
502 $answerpage->grayout = 1;
503 break;
504 case LESSON_ENDOFBRANCH :
505 $answerpage->qtype = get_string("endofbranch", "lesson");
506 $answerpage->grayout = 1;
507 break;
508 case LESSON_CLUSTER :
509 $answerpage->qtype = get_string("clustertitle", "lesson");
510 $answerpage->grayout = 1;
511 break;
512 case LESSON_ENDOFCLUSTER :
513 $answerpage->qtype = get_string("endofclustertitle", "lesson");
514 $answerpage->grayout = 1;
515 break;
519 if (empty($userid)) {
520 // there is no userid, so set these vars and display stats.
521 $answerpage->grayout = 0;
522 $useranswer = NULL;
523 $answerdata->score = NULL;
524 $answerdata->response = NULL;
525 } elseif ($useranswers = get_records_select("lesson_attempts",
526 "lessonid = $lesson->id AND userid = $userid AND retry = $try AND pageid = $page->id", "timeseen")) {
527 // get the user's answer for this page
528 // need to find the right one
529 $i = 0;
530 foreach ($useranswers as $userattempt) {
531 $useranswer = $userattempt;
532 $i++;
533 if ($lesson->maxattempts == $i) {
534 break; // reached maxattempts, break out
537 } else {
538 // user did not answer this page, gray it out and set some nulls
539 $answerpage->grayout = 1;
540 $useranswer = NULL;
541 $answerdata->score = NULL;
542 $answerdata->response = NULL;
545 // build up the answer data
546 if ($answers = get_records("lesson_answers", "pageid", $page->id, "id")) {
547 $i = 0;
548 $n = 0;
549 // go through each answer and display it properly with statistics, highlight if correct answer,
550 // and display what the user entered
551 foreach ($answers as $answer) {
552 switch ($page->qtype) {
553 case LESSON_MULTICHOICE:
554 case LESSON_TRUEFALSE:
555 if ($page->qoption) {
556 if ($useranswer == NULL) {
557 $userresponse = array();
558 } else {
559 $userresponse = explode(",", $useranswer->useranswer);
561 if (in_array($answer->id, $userresponse)) {
562 // make checked
563 $data = "<input readonly=\"readonly\" disabled=\"disabled\" name=\"answer[$i]\" checked=\"checked\" type=\"checkbox\" value=\"1\" />";
564 if (!isset($answerdata->response)) {
565 if ($answer->response == NULL) {
566 if ($useranswer->correct) {
567 $answerdata->response = get_string("thatsthecorrectanswer", "lesson");
568 } else {
569 $answerdata->response = get_string("thatsthewronganswer", "lesson");
571 } else {
572 $answerdata->response = $answer->response;
575 if (!isset($answerdata->score)) {
576 if ($lesson->custom) {
577 $answerdata->score = get_string("pointsearned", "lesson").": ".$answer->score;
578 } elseif ($useranswer->correct) {
579 $answerdata->score = get_string("receivedcredit", "lesson");
580 } else {
581 $answerdata->score = get_string("didnotreceivecredit", "lesson");
584 } else {
585 // unchecked
586 $data = "<input type=\"checkbox\" readonly=\"readonly\" name=\"answer[$i]\" value=\"0\" disabled=\"disabled\" />";
588 if (($answer->score > 0 && $lesson->custom) || (lesson_iscorrect($page->id, $answer->jumpto) && !$lesson->custom)) {
589 $data .= "<font class=highlight>".format_text($answer->answer,FORMAT_MOODLE,$formattextdefoptions)."</font>";
590 } else {
591 $data .= format_text($answer->answer,FORMAT_MOODLE,$formattextdefoptions);
593 } else {
594 if ($useranswer != NULL and $answer->id == $useranswer->answerid) {
595 // make checked
596 $data = "<input readonly=\"readonly\" disabled=\"disabled\" name=\"answer[$i]\" checked=\"checked\" type=\"checkbox\" value=\"1\" />";
597 if ($answer->response == NULL) {
598 if ($useranswer->correct) {
599 $answerdata->response = get_string("thatsthecorrectanswer", "lesson");
600 } else {
601 $answerdata->response = get_string("thatsthewronganswer", "lesson");
603 } else {
604 $answerdata->response = $answer->response;
606 if ($lesson->custom) {
607 $answerdata->score = get_string("pointsearned", "lesson").": ".$answer->score;
608 } elseif ($useranswer->correct) {
609 $answerdata->score = get_string("receivedcredit", "lesson");
610 } else {
611 $answerdata->score = get_string("didnotreceivecredit", "lesson");
613 } else {
614 // unchecked
615 $data = "<input type=\"checkbox\" readonly=\"readonly\" name=\"answer[$i]\" value=\"0\" disabled=\"disabled\" />";
617 if (($answer->score > 0 && $lesson->custom) || (lesson_iscorrect($page->id, $answer->jumpto) && !$lesson->custom)) {
618 $data .= "<font class=\"highlight\">".format_text($answer->answer,FORMAT_MOODLE,$formattextdefoptions)."</font>";
619 } else {
620 $data .= format_text($answer->answer,FORMAT_MOODLE,$formattextdefoptions);
623 if (isset($pagestats[$page->id][$answer->id])) {
624 $percent = $pagestats[$page->id][$answer->id] / $pagestats[$page->id]["total"] * 100;
625 $percent = round($percent, 2);
626 $percent .= "% ".get_string("checkedthisone", "lesson");
627 } else {
628 $percent = get_string("noonecheckedthis", "lesson");
631 $answerdata->answers[] = array($data, $percent);
632 break;
633 case LESSON_SHORTANSWER:
634 case LESSON_NUMERICAL:
635 if ($useranswer == NULL && $i == 0) {
636 // I have the $i == 0 because it is easier to blast through it all at once.
637 if (isset($pagestats[$page->id])) {
638 $stats = $pagestats[$page->id];
639 $total = $stats["total"];
640 unset($stats["total"]);
641 foreach ($stats as $valentered => $ntimes) {
642 $data = '<input type="text" size="50" disabled="disabled" readonly="readonly" value="'.s($valentered).'" />';
643 $percent = $ntimes / $total * 100;
644 $percent = round($percent, 2);
645 $percent .= "% ".get_string("enteredthis", "lesson");
646 $answerdata->answers[] = array($data, $percent);
648 } else {
649 $answerdata->answers[] = array(get_string("nooneansweredthisquestion", "lesson"), " ");
651 $i++;
652 } else if ($useranswer != NULL and $answer->id == $useranswer->answerid) {
653 // get in here when a user answer matches one of the answers to the page
654 $data = '<input type="text" size="50" disabled="disabled" readonly="readonly" value="'.s($useranswer->useranswer).'">';
655 if (isset($pagestats[$page->id][$useranswer->useranswer])) {
656 $percent = $pagestats[$page->id][$useranswer->useranswer] / $pagestats[$page->id]["total"] * 100;
657 $percent = round($percent, 2);
658 $percent .= "% ".get_string("enteredthis", "lesson");
659 } else {
660 $percent = get_string("nooneenteredthis", "lesson");
662 $answerdata->answers[] = array($data, $percent);
664 if ($answer->response == NULL) {
665 if ($useranswer->correct) {
666 $answerdata->response = get_string("thatsthecorrectanswer", "lesson");
667 } else {
668 $answerdata->response = get_string("thatsthewronganswer", "lesson");
670 } else {
671 $answerdata->response = $answer->response;
673 if ($lesson->custom) {
674 $answerdata->score = get_string("pointsearned", "lesson").": ".$answer->score;
675 } elseif ($useranswer->correct) {
676 $answerdata->score = get_string("receivedcredit", "lesson");
677 } else {
678 $answerdata->score = get_string("didnotreceivecredit", "lesson");
680 } elseif ($answer == end($answers) && empty($answerdata) && $useranswer != NULL) {
681 // get in here when what the user entered is not one of the answers
682 $data = '<input type="text" size="50" disabled="disabled" readonly="readonly" value="'.s($useranswer->useranswer).'">';
683 if (isset($pagestats[$page->id][$useranswer->useranswer])) {
684 $percent = $pagestats[$page->id][$useranswer->useranswer] / $pagestats[$page->id]["total"] * 100;
685 $percent = round($percent, 2);
686 $percent .= "% ".get_string("enteredthis", "lesson");
687 } else {
688 $percent = get_string("nooneenteredthis", "lesson");
690 $answerdata->answers[] = array($data, $percent);
692 $answerdata->response = get_string("thatsthewronganswer", "lesson");
693 if ($lesson->custom) {
694 $answerdata->score = get_string("pointsearned", "lesson").": 0";
695 } else {
696 $answerdata->score = get_string("didnotreceivecredit", "lesson");
699 break;
700 case LESSON_MATCHING:
701 if ($n == 0 && $useranswer != NULL && $useranswer->correct) {
702 if ($answer->response == NULL && $useranswer != NULL) {
703 $answerdata->response = get_string("thatsthecorrectanswer", "lesson");
704 } else {
705 $answerdata->response = $answer->response;
707 } elseif ($n == 1 && $useranswer != NULL && !$useranswer->correct) {
708 if ($answer->response == NULL && $useranswer != NULL) {
709 $answerdata->response = get_string("thatsthewronganswer", "lesson");
710 } else {
711 $answerdata->response = $answer->response;
713 } elseif ($n > 1) {
714 if ($n == 2 && $useranswer != NULL && $useranswer->correct) {
715 if ($lesson->custom) {
716 $answerdata->score = get_string("pointsearned", "lesson").": ".$answer->score;
717 } else {
718 $answerdata->score = get_string("receivedcredit", "lesson");
720 } elseif ($n == 3 && $useranswer != NULL && !$useranswer->correct) {
721 if ($lesson->custom) {
722 $answerdata->score = get_string("pointsearned", "lesson").": ".$answer->score;
723 } else {
724 $answerdata->score = get_string("didnotreceivecredit", "lesson");
727 $data = "<select disabled=\"disabled\"><option selected=\"selected\">".strip_tags(format_string($answer->answer))."</option></select>";
728 if ($useranswer != NULL) {
729 $userresponse = explode(",", $useranswer->useranswer);
730 $data .= "<select disabled=\"disabled\"><option selected=\"selected\">".strip_tags(format_string($answers[$userresponse[$i]]->response))."</option></select>";
731 } else {
732 $data .= "<select disabled=\"disabled\"><option selected=\"selected\">".strip_tags(format_string($answer->response))."</option></select>";
735 if ($n == 2) {
736 if (isset($pagestats[$page->id])) {
737 $percent = $pagestats[$page->id]["correct"] / $pagestats[$page->id]["total"] * 100;
738 $percent = round($percent, 2);
739 $percent .= "% ".get_string("answeredcorrectly", "lesson");
740 } else {
741 $percent = get_string("nooneansweredthisquestion", "lesson");
743 } else {
744 $percent = "";
747 $answerdata->answers[] = array($data, $percent);
748 $i++;
750 $n++;
751 break;
752 case LESSON_ESSAY :
753 if ($useranswer != NULL) {
754 $essayinfo = unserialize($useranswer->useranswer);
755 if ($essayinfo->response == NULL) {
756 $answerdata->response = get_string("nocommentyet", "lesson");
757 } else {
758 $answerdata->response = s($essayinfo->response);
760 if (isset($pagestats[$page->id])) {
761 $percent = $pagestats[$page->id]->totalscore / $pagestats[$page->id]->total * 100;
762 $percent = round($percent, 2);
763 $percent = get_string("averagescore", "lesson").": ". $percent ."%";
764 } else {
765 // dont think this should ever be reached....
766 $percent = get_string("nooneansweredthisquestion", "lesson");
768 if ($essayinfo->graded) {
769 if ($lesson->custom) {
770 $answerdata->score = get_string("pointsearned", "lesson").": ".$essayinfo->score;
771 } elseif ($essayinfo->score) {
772 $answerdata->score = get_string("receivedcredit", "lesson");
773 } else {
774 $answerdata->score = get_string("didnotreceivecredit", "lesson");
776 } else {
777 $answerdata->score = get_string("havenotgradedyet", "lesson");
779 } else {
780 $essayinfo->answer = get_string("didnotanswerquestion", "lesson");
783 if (isset($pagestats[$page->id])) {
784 $avescore = $pagestats[$page->id]->totalscore / $pagestats[$page->id]->total;
785 $avescore = round($avescore, 2);
786 $avescore = get_string("averagescore", "lesson").": ". $avescore ;
787 } else {
788 // dont think this should ever be reached....
789 $avescore = get_string("nooneansweredthisquestion", "lesson");
791 $answerdata->answers[] = array(s(stripslashes_safe($essayinfo->answer)), $avescore);
792 break;
793 case LESSON_BRANCHTABLE :
794 $data = "<input type=\"button\" name=\"$answer->id\" value=\"".strip_tags(format_text($answer->answer, FORMAT_MOODLE,$formattextdefoptions))."\" disabled=\"disabled\"> ";
795 $data .= get_string('jumpsto', 'lesson', lesson_get_jump_name($answer->jumpto));
797 $answerdata->answers[] = array($data, "");
798 $answerpage->grayout = 1; // always grayed out
799 break;
800 case LESSON_ENDOFBRANCH :
801 case LESSON_CLUSTER :
802 case LESSON_ENDOFCLUSTER :
803 $data = get_string('jumpsto', 'lesson', lesson_get_jump_name($answer->jumpto));
805 $answerdata->answers[] = array($data, "");
806 $answerpage->grayout = 1; // always grayed out
807 break;
809 if (isset($answerdata)) {
810 $answerpage->answerdata = $answerdata;
813 $answerpages[] = $answerpage;
815 $pageid = $page->nextpageid;
818 /// actually start printing something
819 $table = new stdClass;
820 $table->wrap = array();
821 $table->width = "60%";
824 if (!empty($userid)) {
825 // if looking at a students try, print out some basic stats at the top
827 // print out users name
828 //$headingobject->lastname = $students[$userid]->lastname;
829 //$headingobject->firstname = $students[$userid]->firstname;
830 //$headingobject->attempt = $try + 1;
831 //print_heading(get_string("studentattemptlesson", "lesson", $headingobject));
832 print_heading(get_string('attempt', 'lesson', $try+1));
834 $table->head = array();
835 $table->align = array("right", "left");
836 $table->class = 'generaltable userinfotable';
838 if (!$grades = get_records_select("lesson_grades", "lessonid = $lesson->id and userid = $userid", "completed", "*", $try, 1)) {
839 $grade = -1;
840 $completed = -1;
841 } else {
842 $grade = current($grades);
843 $completed = $grade->completed;
844 $grade = round($grade->grade, 2);
846 if (!$times = get_records_select("lesson_timer", "lessonid = $lesson->id and userid = $userid", "starttime", "*", $try, 1)) {
847 $timetotake = -1;
848 } else {
849 $timetotake = current($times);
850 $timetotake = $timetotake->lessontime - $timetotake->starttime;
853 if ($timetotake == -1 || $completed == -1 || $grade == -1) {
854 $table->align = array("center");
856 $table->data[] = array(get_string("notcompleted", "lesson"));
857 } else {
858 $user = $students[$userid];
860 $gradeinfo = lesson_grade($lesson, $try, $user->id);
862 $table->data[] = array($course->student.':', print_user_picture($user->id, $course->id, $user->picture, 0, true).fullname($user, true));
863 $table->data[] = array(get_string("timetaken", "lesson").":", format_time($timetotake));
864 $table->data[] = array(get_string("completed", "lesson").":", userdate($completed));
865 $table->data[] = array(get_string('rawgrade', 'lesson').':', $gradeinfo->earned.'/'.$gradeinfo->total);
866 $table->data[] = array(get_string("grade", "lesson").":", $grade."%");
868 print_table($table);
870 // Don't want this class for later tables
871 unset($table->class);
872 echo "<br />";
876 $table->align = array("left", "left");
877 $table->size = array("70%", "*");
879 foreach ($answerpages as $page) {
880 unset($table->data);
881 if ($page->grayout) { // set the color of text
882 $fontstart = "<span class=\"dimmed\">";
883 $fontend = "</font>";
884 $fontstart2 = $fontstart;
885 $fontend2 = $fontend;
886 } else {
887 $fontstart = "";
888 $fontend = "";
889 $fontstart2 = "";
890 $fontend2 = "";
893 $table->head = array($fontstart2.$page->qtype.": ".format_string($page->title).$fontend2, $fontstart2.get_string("classstats", "lesson").$fontend2);
894 $table->data[] = array($fontstart.get_string("question", "lesson").": <br />".$fontend.$fontstart2.$page->contents.$fontend2, " ");
895 $table->data[] = array($fontstart.get_string("answer", "lesson").":".$fontend);
896 // apply the font to each answer
897 foreach ($page->answerdata->answers as $answer){
898 $modified = array();
899 foreach ($answer as $single) {
900 // need to apply a font to each one
901 $modified[] = $fontstart2.$single.$fontend2;
903 $table->data[] = $modified;
905 if ($page->answerdata->response != NULL) {
906 $table->data[] = array($fontstart.get_string("response", "lesson").": <br />".$fontend.$fontstart2.format_text($page->answerdata->response,FORMAT_MOODLE,$formattextdefoptions).$fontend2, " ");
908 $table->data[] = array($page->answerdata->score, " ");
909 print_table($table);
910 echo "<br />";
914 else {
915 error("Fatal Error: Unknown Action: ".$action."\n");
918 /// Finish the page
919 print_footer($course);