MDL-37250 mod_lesson: All actual attempts on the lesson are displayed.
[moodle.git] / mod / lesson / report.php
blob9273e5569da759567f6ca4f648340f25d00fd262
1 <?php
3 // This file is part of Moodle - http://moodle.org/
4 //
5 // Moodle is free software: you can redistribute it and/or modify
6 // it under the terms of the GNU General Public License as published by
7 // the Free Software Foundation, either version 3 of the License, or
8 // (at your option) any later version.
9 //
10 // Moodle is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
15 // You should have received a copy of the GNU General Public License
16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 /**
19 * Displays the lesson statistics.
21 * @package mod_lesson
22 * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com}
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
24 **/
26 require_once('../../config.php');
27 require_once($CFG->dirroot.'/mod/lesson/locallib.php');
28 require_once($CFG->dirroot.'/mod/lesson/pagetypes/branchtable.php'); // Needed for constant.
30 $id = required_param('id', PARAM_INT); // Course Module ID
31 $pageid = optional_param('pageid', null, PARAM_INT); // Lesson Page ID
32 $action = optional_param('action', 'reportoverview', PARAM_ALPHA); // action to take
33 $nothingtodisplay = false;
35 $cm = get_coursemodule_from_id('lesson', $id, 0, false, MUST_EXIST);
36 $course = $DB->get_record('course', array('id' => $cm->course), '*', MUST_EXIST);
37 $lesson = new lesson($DB->get_record('lesson', array('id' => $cm->instance), '*', MUST_EXIST));
39 require_login($course, false, $cm);
41 $currentgroup = groups_get_activity_group($cm, true);
43 $context = context_module::instance($cm->id);
44 require_capability('mod/lesson:viewreports', $context);
46 $url = new moodle_url('/mod/lesson/report.php', array('id'=>$id));
47 $url->param('action', $action);
48 if ($pageid !== null) {
49 $url->param('pageid', $pageid);
51 $PAGE->set_url($url);
52 if ($action == 'reportoverview') {
53 $PAGE->navbar->add(get_string('reports', 'lesson'));
54 $PAGE->navbar->add(get_string('overview', 'lesson'));
57 $lessonoutput = $PAGE->get_renderer('mod_lesson');
59 if ($action === 'delete') {
60 /// Process any form data before fetching attempts, grades and times
61 if (has_capability('mod/lesson:edit', $context) and $form = data_submitted() and confirm_sesskey()) {
62 /// Cycle through array of userids with nested arrays of tries
63 if (!empty($form->attempts)) {
64 foreach ($form->attempts as $userid => $tries) {
65 // Modifier IS VERY IMPORTANT! What does it do?
66 // Well, it is for when you delete multiple attempts for the same user.
67 // If you delete try 1 and 3 for a user, then after deleting try 1, try 3 then
68 // becomes try 2 (because try 1 is gone and all tries after try 1 get decremented).
69 // So, the modifier makes sure that the submitted try refers to the current try in the
70 // database - hope this all makes sense :)
71 $modifier = 0;
73 foreach ($tries as $try => $junk) {
74 $try -= $modifier;
76 /// Clean up the timer table by removing using the order - this is silly, it should be linked to specific attempt (skodak)
77 $params = array ("userid" => $userid, "lessonid" => $lesson->id);
78 $timers = $DB->get_records_sql("SELECT id FROM {lesson_timer}
79 WHERE userid = :userid AND lessonid = :lessonid
80 ORDER BY starttime", $params, $try, 1);
81 if ($timers) {
82 $timer = reset($timers);
83 $DB->delete_records('lesson_timer', array('id' => $timer->id));
86 // Remove the grade from the grades tables - this is silly, it should be linked to specific attempt (skodak).
87 $grades = $DB->get_records_sql("SELECT id FROM {lesson_grades}
88 WHERE userid = :userid AND lessonid = :lessonid
89 ORDER BY completed", $params, $try, 1);
91 if ($grades) {
92 $grade = reset($grades);
93 $DB->delete_records('lesson_grades', array('id' => $grade->id));
96 /// Remove attempts and update the retry number
97 $DB->delete_records('lesson_attempts', array('userid' => $userid, 'lessonid' => $lesson->id, 'retry' => $try));
98 $DB->execute("UPDATE {lesson_attempts} SET retry = retry - 1 WHERE userid = ? AND lessonid = ? AND retry > ?", array($userid, $lesson->id, $try));
100 /// Remove seen branches and update the retry number
101 $DB->delete_records('lesson_branch', array('userid' => $userid, 'lessonid' => $lesson->id, 'retry' => $try));
102 $DB->execute("UPDATE {lesson_branch} SET retry = retry - 1 WHERE userid = ? AND lessonid = ? AND retry > ?", array($userid, $lesson->id, $try));
104 /// update central gradebook
105 lesson_update_grades($lesson, $userid);
107 $modifier++;
112 redirect(new moodle_url($PAGE->url, array('action'=>'reportoverview')));
114 } else if ($action === 'reportoverview') {
115 /**************************************************************************
116 this action is for default view and overview view
117 **************************************************************************/
119 // Count the number of branch and question pages in this lesson.
120 $branchcount = $DB->count_records('lesson_pages', array('lessonid' => $lesson->id, 'qtype' => LESSON_PAGE_BRANCHTABLE));
121 $questioncount = ($DB->count_records('lesson_pages', array('lessonid' => $lesson->id)) - $branchcount);
123 // Only load students if there attempts for this lesson.
124 $attempts = $DB->record_exists('lesson_attempts', array('lessonid' => $lesson->id));
125 $branches = $DB->record_exists('lesson_branch', array('lessonid' => $lesson->id));
126 $timer = $DB->record_exists('lesson_timer', array('lessonid' => $lesson->id));
127 if ($attempts or $branches or $timer) {
128 list($esql, $params) = get_enrolled_sql($context, '', $currentgroup, true);
129 list($sort, $sortparams) = users_order_by_sql('u');
131 $params['lessonid'] = $lesson->id;
132 $ufields = user_picture::fields('u');
133 $sql = "SELECT DISTINCT $ufields
134 FROM {user} u
135 JOIN (
136 SELECT userid, lessonid FROM {lesson_attempts} a1
137 UNION
138 SELECT userid, lessonid FROM {lesson_branch} b1
139 UNION
140 SELECT userid, lessonid FROM {lesson_timer} c1
141 ) a ON u.id = a.userid
142 JOIN ($esql) ue ON ue.id = a.userid
143 WHERE a.lessonid = :lessonid
144 ORDER BY $sort";
146 $students = $DB->get_recordset_sql($sql, $params);
147 if (!$students->valid()) {
148 $students->close();
149 $nothingtodisplay = true;
151 } else {
152 $nothingtodisplay = true;
155 if ($nothingtodisplay) {
156 echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('nolessonattempts', 'lesson'));
157 if (!empty($currentgroup)) {
158 $groupname = groups_get_group_name($currentgroup);
159 echo $OUTPUT->notification(get_string('nolessonattemptsgroup', 'lesson', $groupname));
160 } else {
161 echo $OUTPUT->notification(get_string('nolessonattempts', 'lesson'));
163 groups_print_activity_menu($cm, $url);
164 echo $OUTPUT->footer();
165 exit();
168 if (! $grades = $DB->get_records('lesson_grades', array('lessonid' => $lesson->id), 'completed')) {
169 $grades = array();
172 if (! $times = $DB->get_records('lesson_timer', array('lessonid' => $lesson->id), 'starttime')) {
173 $times = array();
176 echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('overview', 'lesson'));
177 groups_print_activity_menu($cm, $url);
179 $course_context = context_course::instance($course->id);
180 if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
181 $seeallgradeslink = new moodle_url('/grade/report/grader/index.php', array('id'=>$course->id));
182 $seeallgradeslink = html_writer::link($seeallgradeslink, get_string('seeallcoursegrades', 'grades'));
183 echo $OUTPUT->box($seeallgradeslink, 'allcoursegrades');
186 // Build an array for output.
187 $studentdata = array();
189 $attempts = $DB->get_recordset('lesson_attempts', array('lessonid' => $lesson->id), 'timeseen');
190 foreach ($attempts as $attempt) {
191 // 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.
192 if (empty($studentdata[$attempt->userid]) || empty($studentdata[$attempt->userid][$attempt->retry])) {
193 // restore/setup defaults
194 $n = 0;
195 $timestart = 0;
196 $timeend = 0;
197 $usergrade = null;
198 $eol = false;
200 // search for the grade record for this try. if not there, the nulls defined above will be used.
201 foreach($grades as $grade) {
202 // check to see if the grade matches the correct user
203 if ($grade->userid == $attempt->userid) {
204 // see if n is = to the retry
205 if ($n == $attempt->retry) {
206 // get grade info
207 $usergrade = round($grade->grade, 2); // round it here so we only have to do it once
208 break;
210 $n++; // if not equal, then increment n
213 $n = 0;
214 // search for the time record for this try. if not there, the nulls defined above will be used.
215 foreach($times as $time) {
216 // check to see if the grade matches the correct user
217 if ($time->userid == $attempt->userid) {
218 // see if n is = to the retry
219 if ($n == $attempt->retry) {
220 // get grade info
221 $timeend = $time->lessontime;
222 $timestart = $time->starttime;
223 $eol = $time->completed;
224 break;
226 $n++; // if not equal, then increment n
230 // build up the array.
231 // this array represents each student and all of their tries at the lesson
232 $studentdata[$attempt->userid][$attempt->retry] = array( "timestart" => $timestart,
233 "timeend" => $timeend,
234 "grade" => $usergrade,
235 "end" => $eol,
236 "try" => $attempt->retry,
237 "userid" => $attempt->userid);
240 $attempts->close();
242 $branches = $DB->get_recordset('lesson_branch', array('lessonid' => $lesson->id), 'timeseen');
243 foreach ($branches as $branch) {
244 // 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.
245 if (empty($studentdata[$branch->userid]) || empty($studentdata[$branch->userid][$branch->retry])) {
246 // Restore/setup defaults.
247 $n = 0;
248 $timestart = 0;
249 $timeend = 0;
250 $usergrade = null;
251 $eol = false;
252 // Search for the time record for this try. if not there, the nulls defined above will be used.
253 foreach ($times as $time) {
254 // Check to see if the grade matches the correct user.
255 if ($time->userid == $branch->userid) {
256 // See if n is = to the retry.
257 if ($n == $branch->retry) {
258 // Get grade info.
259 $timeend = $time->lessontime;
260 $timestart = $time->starttime;
261 $eol = $time->completed;
262 break;
264 $n++; // If not equal, then increment n.
268 // Build up the array.
269 // This array represents each student and all of their tries at the lesson.
270 $studentdata[$branch->userid][$branch->retry] = array( "timestart" => $timestart,
271 "timeend" => $timeend,
272 "grade" => $usergrade,
273 "end" => $eol,
274 "try" => $branch->retry,
275 "userid" => $branch->userid);
278 $branches->close();
280 // Need the same thing for timed entries that were not completed.
281 foreach ($times as $time) {
282 $endoflesson = $time->completed;
283 // If the time start is the same with another record then we shouldn't be adding another item to this array.
284 if (isset($studentdata[$time->userid])) {
285 $foundmatch = false;
286 $n = 0;
287 foreach ($studentdata[$time->userid] as $key => $value) {
288 if ($value['timestart'] == $time->starttime) {
289 // Don't add this to the array.
290 $foundmatch = true;
291 break;
294 $n = count($studentdata[$time->userid]) + 1;
295 if (!$foundmatch) {
296 // Add a record.
297 $studentdata[$time->userid][] = array(
298 "timestart" => $time->starttime,
299 "timeend" => $time->lessontime,
300 "grade" => null,
301 "end" => $endoflesson,
302 "try" => $n,
303 "userid" => $time->userid
306 } else {
307 $studentdata[$time->userid][] = array(
308 "timestart" => $time->starttime,
309 "timeend" => $time->lessontime,
310 "grade" => null,
311 "end" => $endoflesson,
312 "try" => 0,
313 "userid" => $time->userid
317 // Determine if lesson should have a score.
318 if ($branchcount > 0 AND $questioncount == 0) {
319 // This lesson only contains content pages and is not graded.
320 $lessonscored = false;
321 } else {
322 // This lesson is graded.
323 $lessonscored = true;
325 // set all the stats variables
326 $numofattempts = 0;
327 $avescore = 0;
328 $avetime = 0;
329 $highscore = null;
330 $lowscore = null;
331 $hightime = null;
332 $lowtime = null;
334 $table = new html_table();
336 // Set up the table object.
337 if ($lessonscored) {
338 $table->head = array(get_string('name'), get_string('attempts', 'lesson'), get_string('highscore', 'lesson'));
339 } else {
340 $table->head = array(get_string('name'), get_string('attempts', 'lesson'));
342 $table->align = array('center', 'left', 'left');
343 $table->wrap = array('nowrap', 'nowrap', 'nowrap');
344 $table->attributes['class'] = 'standardtable generaltable';
345 $table->size = array(null, '70%', null);
347 // print out the $studentdata array
348 // going through each student that has attempted the lesson, so, each student should have something to be displayed
349 foreach ($students as $student) {
350 // check to see if the student has attempts to print out
351 if (array_key_exists($student->id, $studentdata)) {
352 // set/reset some variables
353 $attempts = array();
354 // gather the data for each user attempt
355 $bestgrade = 0;
356 $bestgradefound = false;
357 // $tries holds all the tries/retries a student has done
358 $tries = $studentdata[$student->id];
359 $studentname = fullname($student, true);
360 foreach ($tries as $try) {
361 // start to build up the checkbox and link
362 if (has_capability('mod/lesson:edit', $context)) {
363 $temp = '<input type="checkbox" id="attempts" name="attempts['.$try['userid'].']['.$try['try'].']" /> ';
364 } else {
365 $temp = '';
368 $temp .= "<a href=\"report.php?id=$cm->id&amp;action=reportdetail&amp;userid=".$try['userid']
369 .'&amp;try='.$try['try'].'" class="lesson-attempt-link">';
370 if ($try["grade"] !== null) { // if null then not done yet
371 // this is what the link does when the user has completed the try
372 $timetotake = $try["timeend"] - $try["timestart"];
374 $temp .= $try["grade"]."%";
375 $bestgradefound = true;
376 if ($try["grade"] > $bestgrade) {
377 $bestgrade = $try["grade"];
379 $temp .= "&nbsp;".userdate($try["timestart"]);
380 $temp .= ",&nbsp;(".format_time($timetotake).")</a>";
381 } else {
382 if ($try["end"]) {
383 // User finished the lesson but has no grade. (Happens when there are only content pages).
384 $temp .= "&nbsp;".userdate($try["timestart"]);
385 $timetotake = $try["timeend"] - $try["timestart"];
386 $temp .= ",&nbsp;(".format_time($timetotake).")</a>";
387 } else {
388 // This is what the link does/looks like when the user has not completed the attempt.
389 $temp .= get_string("notcompleted", "lesson");
390 if ($try['timestart'] !== 0) {
391 // Teacher previews do not track time spent.
392 $temp .= "&nbsp;".userdate($try["timestart"]);
394 $temp .= "</a>";
395 $timetotake = null;
398 // build up the attempts array
399 $attempts[] = $temp;
401 // Run these lines for the stats only if the user finnished the lesson.
402 if ($try["end"]) {
403 // User has completed the lesson.
404 $numofattempts++;
405 $avetime += $timetotake;
406 if ($timetotake > $hightime || $hightime == null) {
407 $hightime = $timetotake;
409 if ($timetotake < $lowtime || $lowtime == null) {
410 $lowtime = $timetotake;
412 if ($try["grade"] !== null) {
413 // The lesson was scored.
414 $avescore += $try["grade"];
415 if ($try["grade"] > $highscore || $highscore === null) {
416 $highscore = $try["grade"];
418 if ($try["grade"] < $lowscore || $lowscore === null) {
419 $lowscore = $try["grade"];
425 // get line breaks in after each attempt
426 $attempts = implode("<br />\n", $attempts);
428 if ($lessonscored) {
429 // Add the grade if the lesson is graded.
430 $bestgrade = $bestgrade."%";
431 $table->data[] = array($studentname, $attempts, $bestgrade);
432 } else {
433 // This lesson does not have a grade.
434 $table->data[] = array($studentname, $attempts);
438 $students->close();
439 // Print it all out!
440 if (has_capability('mod/lesson:edit', $context)) {
441 echo "<form id=\"theform\" method=\"post\" action=\"report.php\">\n
442 <input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />\n
443 <input type=\"hidden\" name=\"id\" value=\"$cm->id\" />\n";
445 echo html_writer::table($table);
446 if (has_capability('mod/lesson:edit', $context)) {
447 $checklinks = '<a href="javascript: checkall();">'.get_string('selectall').'</a> / ';
448 $checklinks .= '<a href="javascript: checknone();">'.get_string('deselectall').'</a>';
449 $checklinks .= html_writer::label('action', 'menuaction', false, array('class' => 'accesshide'));
450 $checklinks .= html_writer::select(array('delete' => get_string('deleteselected')), 'action', 0, array(''=>'choosedots'), array('id'=>'actionid', 'class' => 'autosubmit'));
451 $PAGE->requires->yui_module('moodle-core-formautosubmit',
452 'M.core.init_formautosubmit',
453 array(array('selectid' => 'actionid', 'nothing' => false))
455 echo $OUTPUT->box($checklinks, 'center');
456 echo '</form>';
459 // Calculate the Statistics.
460 if ($avetime == null) {
461 $avetime = get_string("notcompleted", "lesson");
462 } else {
463 $avetime = format_float($avetime/$numofattempts, 0);
464 $avetime = format_time($avetime);
466 if ($hightime == null) {
467 $hightime = get_string("notcompleted", "lesson");
468 } else {
469 $hightime = format_time($hightime);
471 if ($lowtime == null) {
472 $lowtime = get_string("notcompleted", "lesson");
473 } else {
474 $lowtime = format_time($lowtime);
477 if ($lessonscored) {
478 if ($numofattempts == 0) {
479 $avescore = get_string("notcompleted", "lesson");
480 } else {
481 $avescore = format_float($avescore / $numofattempts, 2) . '%';
483 if ($highscore === null) {
484 $highscore = get_string("notcompleted", "lesson");
485 } else {
486 $highscore .= '%';
488 if ($lowscore === null) {
489 $lowscore = get_string("notcompleted", "lesson");
490 } else {
491 $lowscore .= '%';
494 // Display the full stats for the lesson.
495 echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3);
496 $stattable = new html_table();
497 $stattable->head = array(get_string('averagescore', 'lesson'), get_string('averagetime', 'lesson'),
498 get_string('highscore', 'lesson'), get_string('lowscore', 'lesson'),
499 get_string('hightime', 'lesson'), get_string('lowtime', 'lesson'));
500 $stattable->align = array('center', 'center', 'center', 'center', 'center', 'center');
501 $stattable->wrap = array('nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap');
502 $stattable->attributes['class'] = 'standardtable generaltable';
503 $stattable->data[] = array($avescore, $avetime, $highscore, $lowscore, $hightime, $lowtime);
505 } else {
506 // Display simple stats for the lesson.
507 echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3);
508 $stattable = new html_table();
509 $stattable->head = array(get_string('averagetime', 'lesson'), get_string('hightime', 'lesson'),
510 get_string('lowtime', 'lesson'));
511 $stattable->align = array('center', 'center', 'center');
512 $stattable->wrap = array('nowrap', 'nowrap', 'nowrap');
513 $stattable->attributes['class'] = 'standardtable generaltable';
514 $stattable->data[] = array($avetime, $hightime, $lowtime);
517 echo html_writer::table($stattable);
518 } else if ($action === 'reportdetail') {
519 /**************************************************************************
520 this action is for a student detailed view and for the general detailed view
522 General flow of this section of the code
523 1. Generate a object which holds values for the statistics for each question/answer
524 2. Cycle through all the pages to create a object. Foreach page, see if the student actually answered
525 the page. Then process the page appropriatly. Display all info about the question,
526 Highlight correct answers, show how the user answered the question, and display statistics
527 about each page
528 3. Print out info about the try (if needed)
529 4. Print out the object which contains all the try info
531 **************************************************************************/
532 echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('detailedstats', 'lesson'));
533 groups_print_activity_menu($cm, $url);
535 $course_context = context_course::instance($course->id);
536 if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
537 $seeallgradeslink = new moodle_url('/grade/report/grader/index.php', array('id'=>$course->id));
538 $seeallgradeslink = html_writer::link($seeallgradeslink, get_string('seeallcoursegrades', 'grades'));
539 echo $OUTPUT->box($seeallgradeslink, 'allcoursegrades');
542 $formattextdefoptions = new stdClass;
543 $formattextdefoptions->para = false; //I'll use it widely in this page
544 $formattextdefoptions->overflowdiv = true;
546 $userid = optional_param('userid', null, PARAM_INT); // if empty, then will display the general detailed view
547 $try = optional_param('try', null, PARAM_INT);
549 if (!empty($userid)) {
550 // Apply overrides.
551 $lesson->update_effective_access($userid);
554 $lessonpages = $lesson->load_all_pages();
555 foreach ($lessonpages as $lessonpage) {
556 if ($lessonpage->prevpageid == 0) {
557 $pageid = $lessonpage->id;
561 // now gather the stats into an object
562 $firstpageid = $pageid;
563 $pagestats = array();
564 while ($pageid != 0) { // EOL
565 $page = $lessonpages[$pageid];
566 $params = array ("lessonid" => $lesson->id, "pageid" => $page->id);
567 if ($allanswers = $DB->get_records_select("lesson_attempts", "lessonid = :lessonid AND pageid = :pageid", $params, "timeseen")) {
568 // get them ready for processing
569 $orderedanswers = array();
570 foreach ($allanswers as $singleanswer) {
571 // ordering them like this, will help to find the single attempt record that we want to keep.
572 $orderedanswers[$singleanswer->userid][$singleanswer->retry][] = $singleanswer;
574 // this is foreach user and for each try for that user, keep one attempt record
575 foreach ($orderedanswers as $orderedanswer) {
576 foreach($orderedanswer as $tries) {
577 $page->stats($pagestats, $tries);
580 } else {
581 // no one answered yet...
583 //unset($orderedanswers); initialized above now
584 $pageid = $page->nextpageid;
587 $manager = lesson_page_type_manager::get($lesson);
588 $qtypes = $manager->get_page_type_strings();
590 $answerpages = array();
591 $answerpage = "";
592 $pageid = $firstpageid;
593 // cycle through all the pages
594 // foreach page, add to the $answerpages[] array all the data that is needed
595 // from the question, the users attempt, and the statistics
596 // grayout pages that the user did not answer and Branch, end of branch, cluster
597 // and end of cluster pages
598 while ($pageid != 0) { // EOL
599 $page = $lessonpages[$pageid];
600 $answerpage = new stdClass;
601 $data ='';
603 $answerdata = new stdClass;
604 // Set some defaults for the answer data.
605 $answerdata->score = null;
606 $answerdata->response = null;
607 $answerdata->responseformat = FORMAT_PLAIN;
609 $answerpage->title = format_string($page->title);
611 $options = new stdClass;
612 $options->noclean = true;
613 $options->overflowdiv = true;
614 $options->context = $context;
615 $answerpage->contents = format_text($page->contents, $page->contentsformat, $options);
617 $answerpage->qtype = $qtypes[$page->qtype].$page->option_description_string();
618 $answerpage->grayout = $page->grayout;
619 $answerpage->context = $context;
621 if (empty($userid)) {
622 // there is no userid, so set these vars and display stats.
623 $answerpage->grayout = 0;
624 $useranswer = null;
625 } elseif ($useranswers = $DB->get_records("lesson_attempts",array("lessonid"=>$lesson->id, "userid"=>$userid, "retry"=>$try,"pageid"=>$page->id), "timeseen")) {
626 // get the user's answer for this page
627 // need to find the right one
628 $i = 0;
629 foreach ($useranswers as $userattempt) {
630 $useranswer = $userattempt;
631 $i++;
632 if ($lesson->maxattempts == $i) {
633 break; // reached maxattempts, break out
636 } else {
637 // user did not answer this page, gray it out and set some nulls
638 $answerpage->grayout = 1;
639 $useranswer = null;
641 $i = 0;
642 $n = 0;
643 $answerpages[] = $page->report_answers(clone($answerpage), clone($answerdata), $useranswer, $pagestats, $i, $n);
644 $pageid = $page->nextpageid;
647 /// actually start printing something
648 $table = new html_table();
649 $table->wrap = array();
650 $table->width = "60%";
651 if (!empty($userid)) {
652 // if looking at a students try, print out some basic stats at the top
654 // print out users name
655 //$headingobject->lastname = $students[$userid]->lastname;
656 //$headingobject->firstname = $students[$userid]->firstname;
657 //$headingobject->attempt = $try + 1;
658 //print_heading(get_string("studentattemptlesson", "lesson", $headingobject));
659 echo $OUTPUT->heading(get_string('attempt', 'lesson', $try+1), 3);
661 $table->head = array();
662 $table->align = array('right', 'left');
663 $table->attributes['class'] = 'compacttable generaltable';
665 $params = array("lessonid"=>$lesson->id, "userid"=>$userid);
666 if (!$grades = $DB->get_records_select("lesson_grades", "lessonid = :lessonid and userid = :userid", $params, "completed", "*", $try, 1)) {
667 $grade = -1;
668 $completed = -1;
669 } else {
670 $grade = current($grades);
671 $completed = $grade->completed;
672 $grade = round($grade->grade, 2);
674 if (!$times = $DB->get_records_select("lesson_timer", "lessonid = :lessonid and userid = :userid", $params, "starttime", "*", $try, 1)) {
675 $timetotake = -1;
676 } else {
677 $timetotake = current($times);
678 $timetotake = $timetotake->lessontime - $timetotake->starttime;
681 if ($timetotake == -1 || $completed == -1 || $grade == -1) {
682 $table->align = array("center");
684 $table->data[] = array(get_string("notcompleted", "lesson"));
685 } else {
686 $user = $DB->get_record('user', array('id' => $userid));
688 $gradeinfo = lesson_grade($lesson, $try, $user->id);
690 $table->data[] = array(get_string('name').':', $OUTPUT->user_picture($user, array('courseid'=>$course->id)).fullname($user, true));
691 $table->data[] = array(get_string("timetaken", "lesson").":", format_time($timetotake));
692 $table->data[] = array(get_string("completed", "lesson").":", userdate($completed));
693 $table->data[] = array(get_string('rawgrade', 'lesson').':', $gradeinfo->earned.'/'.$gradeinfo->total);
694 $table->data[] = array(get_string("grade", "lesson").":", $grade."%");
696 echo html_writer::table($table);
698 // Don't want this class for later tables
699 $table->attributes['class'] = '';
703 $table->align = array('left', 'left');
704 $table->size = array('70%', null);
705 $table->attributes['class'] = 'compacttable generaltable';
707 foreach ($answerpages as $page) {
708 unset($table->data);
709 if ($page->grayout) { // set the color of text
710 $fontstart = "<span class=\"dimmed\">";
711 $fontend = "</font>";
712 $fontstart2 = $fontstart;
713 $fontend2 = $fontend;
714 } else {
715 $fontstart = "";
716 $fontend = "";
717 $fontstart2 = "";
718 $fontend2 = "";
721 $table->head = array($fontstart2.$page->qtype.": ".format_string($page->title).$fontend2, $fontstart2.get_string("classstats", "lesson").$fontend2);
722 $table->data[] = array($fontstart.get_string("question", "lesson").": <br />".$fontend.$fontstart2.$page->contents.$fontend2, " ");
723 $table->data[] = array($fontstart.get_string("answer", "lesson").":".$fontend, ' ');
724 // apply the font to each answer
725 if (!empty($page->answerdata)) {
726 foreach ($page->answerdata->answers as $answer){
727 $modified = array();
728 foreach ($answer as $single) {
729 // need to apply a font to each one
730 $modified[] = $fontstart2.$single.$fontend2;
732 $table->data[] = $modified;
734 if (isset($page->answerdata->response)) {
735 $table->data[] = array($fontstart.get_string("response", "lesson").": <br />".$fontend
736 .$fontstart2.$page->answerdata->response.$fontend2, " ");
738 $table->data[] = array($page->answerdata->score, " ");
739 } else {
740 $table->data[] = array(get_string('didnotanswerquestion', 'lesson'), " ");
742 echo html_writer::start_tag('div', array('class' => 'no-overflow'));
743 echo html_writer::table($table);
744 echo html_writer::end_tag('div');
746 } else {
747 print_error('unknowaction');
750 /// Finish the page
751 echo $OUTPUT->footer();