4f4a3b36b0c19224feb67ac8461ff2e406e7415c
[moodle.git] / mod / lesson / report.php
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.
14 //
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.
20  *
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);
50 }
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'));
55 }
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));
84                     }
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));
94                     }
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++;
108                 }
109             }
110         }
111     }
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     if ($attempts or $branches) {
127         list($esql, $params) = get_enrolled_sql($context, '', $currentgroup, true);
128         list($sort, $sortparams) = users_order_by_sql('u');
130         $params['lessonid'] = $lesson->id;
131         $ufields = user_picture::fields('u');
132         $sql = "SELECT DISTINCT $ufields
133                 FROM {user} u
134                 JOIN (SELECT userid, lessonid FROM {lesson_attempts} a1 UNION
135                 SELECT userid, lessonid FROM {lesson_branch} b1) a ON u.id = a.userid
136                 JOIN ($esql) ue ON ue.id = a.userid
137                 WHERE a.lessonid = :lessonid
138                 ORDER BY $sort";
140         $students = $DB->get_recordset_sql($sql, $params);
141         if (!$students->valid()) {
142             $students->close();
143             $nothingtodisplay = true;
144         }
145     } else {
146         $nothingtodisplay = true;
147     }
149     if ($nothingtodisplay) {
150         echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('nolessonattempts', 'lesson'));
151         if (!empty($currentgroup)) {
152             $groupname = groups_get_group_name($currentgroup);
153             echo $OUTPUT->notification(get_string('nolessonattemptsgroup', 'lesson', $groupname));
154         } else {
155             echo $OUTPUT->notification(get_string('nolessonattempts', 'lesson'));
156         }
157         groups_print_activity_menu($cm, $url);
158         echo $OUTPUT->footer();
159         exit();
160     }
162     if (! $grades = $DB->get_records('lesson_grades', array('lessonid' => $lesson->id), 'completed')) {
163         $grades = array();
164     }
166     if (! $times = $DB->get_records('lesson_timer', array('lessonid' => $lesson->id), 'starttime')) {
167         $times = array();
168     }
170     echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('overview', 'lesson'));
171     groups_print_activity_menu($cm, $url);
173     $course_context = context_course::instance($course->id);
174     if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
175         $seeallgradeslink = new moodle_url('/grade/report/grader/index.php', array('id'=>$course->id));
176         $seeallgradeslink = html_writer::link($seeallgradeslink, get_string('seeallcoursegrades', 'grades'));
177         echo $OUTPUT->box($seeallgradeslink, 'allcoursegrades');
178     }
180     // Build an array for output.
181     $studentdata = array();
183     $attempts = $DB->get_recordset('lesson_attempts', array('lessonid' => $lesson->id), 'timeseen');
184     foreach ($attempts as $attempt) {
185         // 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.
186         if (empty($studentdata[$attempt->userid]) || empty($studentdata[$attempt->userid][$attempt->retry])) {
187             // restore/setup defaults
188             $n = 0;
189             $timestart = 0;
190             $timeend = 0;
191             $usergrade = null;
192             $eol = false;
194             // search for the grade record for this try. if not there, the nulls defined above will be used.
195             foreach($grades as $grade) {
196                 // check to see if the grade matches the correct user
197                 if ($grade->userid == $attempt->userid) {
198                     // see if n is = to the retry
199                     if ($n == $attempt->retry) {
200                         // get grade info
201                         $usergrade = round($grade->grade, 2); // round it here so we only have to do it once
202                         break;
203                     }
204                     $n++; // if not equal, then increment n
205                 }
206             }
207             $n = 0;
208             // search for the time record for this try. if not there, the nulls defined above will be used.
209             foreach($times as $time) {
210                 // check to see if the grade matches the correct user
211                 if ($time->userid == $attempt->userid) {
212                     // see if n is = to the retry
213                     if ($n == $attempt->retry) {
214                         // get grade info
215                         $timeend = $time->lessontime;
216                         $timestart = $time->starttime;
217                         $eol = $time->completed;
218                         break;
219                     }
220                     $n++; // if not equal, then increment n
221                 }
222             }
224             // build up the array.
225             // this array represents each student and all of their tries at the lesson
226             $studentdata[$attempt->userid][$attempt->retry] = array( "timestart" => $timestart,
227                                                                     "timeend" => $timeend,
228                                                                     "grade" => $usergrade,
229                                                                     "end" => $eol,
230                                                                     "try" => $attempt->retry,
231                                                                     "userid" => $attempt->userid);
232         }
233     }
234     $attempts->close();
236     $branches = $DB->get_recordset('lesson_branch', array('lessonid' => $lesson->id), 'timeseen');
237     foreach ($branches as $branch) {
238         // 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.
239         if (empty($studentdata[$branch->userid]) || empty($studentdata[$branch->userid][$branch->retry])) {
240             // Restore/setup defaults.
241             $n = 0;
242             $timestart = 0;
243             $timeend = 0;
244             $usergrade = null;
245             $eol = false;
246             // Search for the time record for this try. if not there, the nulls defined above will be used.
247             foreach ($times as $time) {
248                 // Check to see if the grade matches the correct user.
249                 if ($time->userid == $branch->userid) {
250                     // See if n is = to the retry.
251                     if ($n == $branch->retry) {
252                         // Get grade info.
253                         $timeend = $time->lessontime;
254                         $timestart = $time->starttime;
255                         $eol = $time->completed;
256                         break;
257                     }
258                     $n++; // If not equal, then increment n.
259                 }
260             }
262             // Build up the array.
263             // This array represents each student and all of their tries at the lesson.
264             $studentdata[$branch->userid][$branch->retry] = array( "timestart" => $timestart,
265                                                                     "timeend" => $timeend,
266                                                                     "grade" => $usergrade,
267                                                                     "end" => $eol,
268                                                                     "try" => $branch->retry,
269                                                                     "userid" => $branch->userid);
270         }
271     }
272     $branches->close();
274     // Determine if lesson should have a score.
275     if ($branchcount > 0 AND $questioncount == 0) {
276         // This lesson only contains content pages and is not graded.
277         $lessonscored = false;
278     } else {
279         // This lesson is graded.
280         $lessonscored = true;
281     }
282     // set all the stats variables
283     $numofattempts = 0;
284     $avescore      = 0;
285     $avetime       = 0;
286     $highscore     = null;
287     $lowscore      = null;
288     $hightime      = null;
289     $lowtime       = null;
291     $table = new html_table();
293     // Set up the table object.
294     if ($lessonscored) {
295         $table->head = array(get_string('name'), get_string('attempts', 'lesson'), get_string('highscore', 'lesson'));
296     } else {
297         $table->head = array(get_string('name'), get_string('attempts', 'lesson'));
298     }
299     $table->align = array('center', 'left', 'left');
300     $table->wrap = array('nowrap', 'nowrap', 'nowrap');
301     $table->attributes['class'] = 'standardtable generaltable';
302     $table->size = array(null, '70%', null);
304     // print out the $studentdata array
305     // going through each student that has attempted the lesson, so, each student should have something to be displayed
306     foreach ($students as $student) {
307         // check to see if the student has attempts to print out
308         if (array_key_exists($student->id, $studentdata)) {
309             // set/reset some variables
310             $attempts = array();
311             // gather the data for each user attempt
312             $bestgrade = 0;
313             $bestgradefound = false;
314             // $tries holds all the tries/retries a student has done
315             $tries = $studentdata[$student->id];
316             $studentname = fullname($student, true);
317             foreach ($tries as $try) {
318             // start to build up the checkbox and link
319                 if (has_capability('mod/lesson:edit', $context)) {
320                     $temp = '<input type="checkbox" id="attempts" name="attempts['.$try['userid'].']['.$try['try'].']" /> ';
321                 } else {
322                     $temp = '';
323                 }
325                 $temp .= "<a href=\"report.php?id=$cm->id&amp;action=reportdetail&amp;userid=".$try['userid']
326                         .'&amp;try='.$try['try'].'" class="lesson-attempt-link">';
327                 if ($try["grade"] !== null) { // if null then not done yet
328                     // this is what the link does when the user has completed the try
329                     $timetotake = $try["timeend"] - $try["timestart"];
331                     $temp .= $try["grade"]."%";
332                     $bestgradefound = true;
333                     if ($try["grade"] > $bestgrade) {
334                         $bestgrade = $try["grade"];
335                     }
336                     $temp .= "&nbsp;".userdate($try["timestart"]);
337                     $temp .= ",&nbsp;(".format_time($timetotake).")</a>";
338                 } else {
339                     if ($try["end"]) {
340                         // User finished the lesson but has no grade. (Happens when there are only content pages).
341                         $temp .= "&nbsp;".userdate($try["timestart"]);
342                         $timetotake = $try["timeend"] - $try["timestart"];
343                         $temp .= ",&nbsp;(".format_time($timetotake).")</a>";
344                     } else {
345                         // This is what the link does/looks like when the user has not completed the attempt.
346                         $temp .= get_string("notcompleted", "lesson");
347                         if ($try['timestart'] !== 0) {
348                             // Teacher previews do not track time spent.
349                             $temp .= "&nbsp;".userdate($try["timestart"]);
350                         }
351                         $temp .= "</a>";
352                         $timetotake = null;
353                     }
354                 }
355                 // build up the attempts array
356                 $attempts[] = $temp;
358                 // Run these lines for the stats only if the user finnished the lesson.
359                 if ($try["end"]) {
360                     // User has completed the lesson.
361                     $numofattempts++;
362                     $avetime += $timetotake;
363                     if ($timetotake > $hightime || $hightime == null) {
364                         $hightime = $timetotake;
365                     }
366                     if ($timetotake < $lowtime || $lowtime == null) {
367                         $lowtime = $timetotake;
368                     }
369                     if ($try["grade"] !== null) {
370                         // The lesson was scored.
371                         $avescore += $try["grade"];
372                         if ($try["grade"] > $highscore || $highscore === null) {
373                             $highscore = $try["grade"];
374                         }
375                         if ($try["grade"] < $lowscore || $lowscore === null) {
376                             $lowscore = $try["grade"];
377                         }
379                     }
380                 }
381             }
382             // get line breaks in after each attempt
383             $attempts = implode("<br />\n", $attempts);
385             if ($lessonscored) {
386                 // Add the grade if the lesson is graded.
387                 $bestgrade = $bestgrade."%";
388                 $table->data[] = array($studentname, $attempts, $bestgrade);
389             } else {
390                 // This lesson does not have a grade.
391                 $table->data[] = array($studentname, $attempts);
392             }
393         }
394     }
395     $students->close();
396     // Print it all out!
397     if (has_capability('mod/lesson:edit', $context)) {
398         echo  "<form id=\"theform\" method=\"post\" action=\"report.php\">\n
399                <input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />\n
400                <input type=\"hidden\" name=\"id\" value=\"$cm->id\" />\n";
401     }
402     echo html_writer::table($table);
403     if (has_capability('mod/lesson:edit', $context)) {
404         $checklinks  = '<a href="javascript: checkall();">'.get_string('selectall').'</a> / ';
405         $checklinks .= '<a href="javascript: checknone();">'.get_string('deselectall').'</a>';
406         $checklinks .= html_writer::label('action', 'menuaction', false, array('class' => 'accesshide'));
407         $checklinks .= html_writer::select(array('delete' => get_string('deleteselected')), 'action', 0, array(''=>'choosedots'), array('id'=>'actionid', 'class' => 'autosubmit'));
408         $PAGE->requires->yui_module('moodle-core-formautosubmit',
409             'M.core.init_formautosubmit',
410             array(array('selectid' => 'actionid', 'nothing' => false))
411         );
412         echo $OUTPUT->box($checklinks, 'center');
413         echo '</form>';
414     }
416     // Calculate the Statistics.
417     if ($avetime == null) {
418         $avetime = get_string("notcompleted", "lesson");
419     } else {
420         $avetime = format_float($avetime/$numofattempts, 0);
421         $avetime = format_time($avetime);
422     }
423     if ($hightime == null) {
424         $hightime = get_string("notcompleted", "lesson");
425     } else {
426         $hightime = format_time($hightime);
427     }
428     if ($lowtime == null) {
429         $lowtime = get_string("notcompleted", "lesson");
430     } else {
431         $lowtime = format_time($lowtime);
432     }
434     if ($lessonscored) {
435         if ($numofattempts == 0) {
436             $avescore = get_string("notcompleted", "lesson");
437         } else {
438             $avescore = format_float($avescore / $numofattempts, 2) . '%';
439         }
440         if ($highscore === null) {
441             $highscore = get_string("notcompleted", "lesson");
442         } else {
443             $highscore .= '%';
444         }
445         if ($lowscore === null) {
446             $lowscore = get_string("notcompleted", "lesson");
447         } else {
448             $lowscore .= '%';
449         }
451         // Display the full stats for the lesson.
452         echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3);
453         $stattable = new html_table();
454         $stattable->head = array(get_string('averagescore', 'lesson'), get_string('averagetime', 'lesson'),
455                                 get_string('highscore', 'lesson'), get_string('lowscore', 'lesson'),
456                                 get_string('hightime', 'lesson'), get_string('lowtime', 'lesson'));
457         $stattable->align = array('center', 'center', 'center', 'center', 'center', 'center');
458         $stattable->wrap = array('nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap');
459         $stattable->attributes['class'] = 'standardtable generaltable';
460         $stattable->data[] = array($avescore, $avetime, $highscore, $lowscore, $hightime, $lowtime);
462     } else {
463         // Display simple stats for the lesson.
464         echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3);
465         $stattable = new html_table();
466         $stattable->head = array(get_string('averagetime', 'lesson'), get_string('hightime', 'lesson'),
467                                 get_string('lowtime', 'lesson'));
468         $stattable->align = array('center', 'center', 'center');
469         $stattable->wrap = array('nowrap', 'nowrap', 'nowrap');
470         $stattable->attributes['class'] = 'standardtable generaltable';
471         $stattable->data[] = array($avetime, $hightime, $lowtime);
472     }
474     echo html_writer::table($stattable);
475 } else if ($action === 'reportdetail') {
476     /**************************************************************************
477     this action is for a student detailed view and for the general detailed view
479     General flow of this section of the code
480     1.  Generate a object which holds values for the statistics for each question/answer
481     2.  Cycle through all the pages to create a object.  Foreach page, see if the student actually answered
482         the page.  Then process the page appropriatly.  Display all info about the question,
483         Highlight correct answers, show how the user answered the question, and display statistics
484         about each page
485     3.  Print out info about the try (if needed)
486     4.  Print out the object which contains all the try info
488 **************************************************************************/
489     echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('detailedstats', 'lesson'));
490     groups_print_activity_menu($cm, $url);
492     $course_context = context_course::instance($course->id);
493     if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
494         $seeallgradeslink = new moodle_url('/grade/report/grader/index.php', array('id'=>$course->id));
495         $seeallgradeslink = html_writer::link($seeallgradeslink, get_string('seeallcoursegrades', 'grades'));
496         echo $OUTPUT->box($seeallgradeslink, 'allcoursegrades');
497     }
499     $formattextdefoptions = new stdClass;
500     $formattextdefoptions->para = false;  //I'll use it widely in this page
501     $formattextdefoptions->overflowdiv = true;
503     $userid = optional_param('userid', null, PARAM_INT); // if empty, then will display the general detailed view
504     $try    = optional_param('try', null, PARAM_INT);
506     if (!empty($userid)) {
507         // Apply overrides.
508         $lesson->update_effective_access($userid);
509     }
511     $lessonpages = $lesson->load_all_pages();
512     foreach ($lessonpages as $lessonpage) {
513         if ($lessonpage->prevpageid == 0) {
514             $pageid = $lessonpage->id;
515         }
516     }
518     // now gather the stats into an object
519     $firstpageid = $pageid;
520     $pagestats = array();
521     while ($pageid != 0) { // EOL
522         $page = $lessonpages[$pageid];
523         $params = array ("lessonid" => $lesson->id, "pageid" => $page->id);
524         if ($allanswers = $DB->get_records_select("lesson_attempts", "lessonid = :lessonid AND pageid = :pageid", $params, "timeseen")) {
525             // get them ready for processing
526             $orderedanswers = array();
527             foreach ($allanswers as $singleanswer) {
528                 // ordering them like this, will help to find the single attempt record that we want to keep.
529                 $orderedanswers[$singleanswer->userid][$singleanswer->retry][] = $singleanswer;
530             }
531             // this is foreach user and for each try for that user, keep one attempt record
532             foreach ($orderedanswers as $orderedanswer) {
533                 foreach($orderedanswer as $tries) {
534                     $page->stats($pagestats, $tries);
535                 }
536             }
537         } else {
538             // no one answered yet...
539         }
540         //unset($orderedanswers);  initialized above now
541         $pageid = $page->nextpageid;
542     }
544     $manager = lesson_page_type_manager::get($lesson);
545     $qtypes = $manager->get_page_type_strings();
547     $answerpages = array();
548     $answerpage = "";
549     $pageid = $firstpageid;
550     // cycle through all the pages
551     //  foreach page, add to the $answerpages[] array all the data that is needed
552     //  from the question, the users attempt, and the statistics
553     // grayout pages that the user did not answer and Branch, end of branch, cluster
554     // and end of cluster pages
555     while ($pageid != 0) { // EOL
556         $page = $lessonpages[$pageid];
557         $answerpage = new stdClass;
558         $data ='';
560         $answerdata = new stdClass;
561         // Set some defaults for the answer data.
562         $answerdata->score = null;
563         $answerdata->response = null;
564         $answerdata->responseformat = FORMAT_PLAIN;
566         $answerpage->title = format_string($page->title);
568         $options = new stdClass;
569         $options->noclean = true;
570         $options->overflowdiv = true;
571         $options->context = $context;
572         $answerpage->contents = format_text($page->contents, $page->contentsformat, $options);
574         $answerpage->qtype = $qtypes[$page->qtype].$page->option_description_string();
575         $answerpage->grayout = $page->grayout;
576         $answerpage->context = $context;
578         if (empty($userid)) {
579             // there is no userid, so set these vars and display stats.
580             $answerpage->grayout = 0;
581             $useranswer = null;
582         } elseif ($useranswers = $DB->get_records("lesson_attempts",array("lessonid"=>$lesson->id, "userid"=>$userid, "retry"=>$try,"pageid"=>$page->id), "timeseen")) {
583             // get the user's answer for this page
584             // need to find the right one
585             $i = 0;
586             foreach ($useranswers as $userattempt) {
587                 $useranswer = $userattempt;
588                 $i++;
589                 if ($lesson->maxattempts == $i) {
590                     break; // reached maxattempts, break out
591                 }
592             }
593         } else {
594             // user did not answer this page, gray it out and set some nulls
595             $answerpage->grayout = 1;
596             $useranswer = null;
597         }
598         $i = 0;
599         $n = 0;
600         $answerpages[] = $page->report_answers(clone($answerpage), clone($answerdata), $useranswer, $pagestats, $i, $n);
601         $pageid = $page->nextpageid;
602     }
604     /// actually start printing something
605     $table = new html_table();
606     $table->wrap = array();
607     $table->width = "60%";
608     if (!empty($userid)) {
609         // if looking at a students try, print out some basic stats at the top
611             // print out users name
612             //$headingobject->lastname = $students[$userid]->lastname;
613             //$headingobject->firstname = $students[$userid]->firstname;
614             //$headingobject->attempt = $try + 1;
615             //print_heading(get_string("studentattemptlesson", "lesson", $headingobject));
616         echo $OUTPUT->heading(get_string('attempt', 'lesson', $try+1), 3);
618         $table->head = array();
619         $table->align = array('right', 'left');
620         $table->attributes['class'] = 'compacttable generaltable';
622         $params = array("lessonid"=>$lesson->id, "userid"=>$userid);
623         if (!$grades = $DB->get_records_select("lesson_grades", "lessonid = :lessonid and userid = :userid", $params, "completed", "*", $try, 1)) {
624             $grade = -1;
625             $completed = -1;
626         } else {
627             $grade = current($grades);
628             $completed = $grade->completed;
629             $grade = round($grade->grade, 2);
630         }
631         if (!$times = $DB->get_records_select("lesson_timer", "lessonid = :lessonid and userid = :userid", $params, "starttime", "*", $try, 1)) {
632             $timetotake = -1;
633         } else {
634             $timetotake = current($times);
635             $timetotake = $timetotake->lessontime - $timetotake->starttime;
636         }
638         if ($timetotake == -1 || $completed == -1 || $grade == -1) {
639             $table->align = array("center");
641             $table->data[] = array(get_string("notcompleted", "lesson"));
642         } else {
643             $user = $DB->get_record('user', array('id' => $userid));
645             $gradeinfo = lesson_grade($lesson, $try, $user->id);
647             $table->data[] = array(get_string('name').':', $OUTPUT->user_picture($user, array('courseid'=>$course->id)).fullname($user, true));
648             $table->data[] = array(get_string("timetaken", "lesson").":", format_time($timetotake));
649             $table->data[] = array(get_string("completed", "lesson").":", userdate($completed));
650             $table->data[] = array(get_string('rawgrade', 'lesson').':', $gradeinfo->earned.'/'.$gradeinfo->total);
651             $table->data[] = array(get_string("grade", "lesson").":", $grade."%");
652         }
653         echo html_writer::table($table);
655         // Don't want this class for later tables
656         $table->attributes['class'] = '';
657     }
660     $table->align = array('left', 'left');
661     $table->size = array('70%', null);
662     $table->attributes['class'] = 'compacttable generaltable';
664     foreach ($answerpages as $page) {
665         unset($table->data);
666         if ($page->grayout) { // set the color of text
667             $fontstart = "<span class=\"dimmed\">";
668             $fontend = "</font>";
669             $fontstart2 = $fontstart;
670             $fontend2 = $fontend;
671         } else {
672             $fontstart = "";
673             $fontend = "";
674             $fontstart2 = "";
675             $fontend2 = "";
676         }
678         $table->head = array($fontstart2.$page->qtype.": ".format_string($page->title).$fontend2, $fontstart2.get_string("classstats", "lesson").$fontend2);
679         $table->data[] = array($fontstart.get_string("question", "lesson").": <br />".$fontend.$fontstart2.$page->contents.$fontend2, " ");
680         $table->data[] = array($fontstart.get_string("answer", "lesson").":".$fontend, ' ');
681         // apply the font to each answer
682         if (!empty($page->answerdata)) {
683             foreach ($page->answerdata->answers as $answer){
684                 $modified = array();
685                 foreach ($answer as $single) {
686                     // need to apply a font to each one
687                     $modified[] = $fontstart2.$single.$fontend2;
688                 }
689                 $table->data[] = $modified;
690             }
691             if (isset($page->answerdata->response)) {
692                 $table->data[] = array($fontstart.get_string("response", "lesson").": <br />".$fontend
693                         .$fontstart2.$page->answerdata->response.$fontend2, " ");
694             }
695             $table->data[] = array($page->answerdata->score, " ");
696         } else {
697             $table->data[] = array(get_string('didnotanswerquestion', 'lesson'), " ");
698         }
699         echo html_writer::start_tag('div', array('class' => 'no-overflow'));
700         echo html_writer::table($table);
701         echo html_writer::end_tag('div');
702     }
703 } else {
704     print_error('unknowaction');
707 /// Finish the page
708 echo $OUTPUT->footer();