MDL-40735 mod_lesson: fixed up a header and stripped out hardcoded formatting
[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
22  * @subpackage lesson
23  * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
24  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or late
25  **/
27 require_once('../../config.php');
28 require_once($CFG->dirroot.'/mod/lesson/locallib.php');
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 $context = context_module::instance($cm->id);
42 require_capability('mod/lesson:manage', $context);
44 $ufields = user_picture::fields('u'); // These fields are enough
45 $params = array("lessonid" => $lesson->id);
46 list($sort, $sortparams) = users_order_by_sql('u');
47 $params = array_merge($params, $sortparams);
48 // TODO: Improve this. Fetching all students always is crazy!
49 if (!empty($cm->groupingid)) {
50     $params["groupingid"] = $cm->groupingid;
51     $sql = "SELECT DISTINCT $ufields
52                 FROM {lesson_attempts} a
53                     INNER JOIN {user} u ON u.id = a.userid
54                     INNER JOIN {groups_members} gm ON gm.userid = u.id
55                     INNER JOIN {groupings_groups} gg ON gm.groupid = gg.groupid
56                 WHERE a.lessonid = :lessonid AND
57                       gg.groupingid = :groupingid
58                 ORDER BY $sort";
59 } else {
60     $sql = "SELECT DISTINCT $ufields
61             FROM {user} u,
62                  {lesson_attempts} a
63             WHERE a.lessonid = :lessonid and
64                   u.id = a.userid
65             ORDER BY $sort";
66 }
68 if (! $students = $DB->get_records_sql($sql, $params)) {
69     $nothingtodisplay = true;
70 }
72 $url = new moodle_url('/mod/lesson/report.php', array('id'=>$id));
73 if ($action !== 'reportoverview') {
74     $url->param('action', $action);
75 }
76 if ($pageid !== null) {
77     $url->param('pageid', $pageid);
78 }
79 $PAGE->set_url($url);
80 if ($action == 'reportoverview') {
81     $PAGE->navbar->add(get_string('reports', 'lesson'));
82     $PAGE->navbar->add(get_string('overview', 'lesson'));
83 }
85 $lessonoutput = $PAGE->get_renderer('mod_lesson');
87 if (! $attempts = $DB->get_records('lesson_attempts', array('lessonid' => $lesson->id), 'timeseen')) {
88     $nothingtodisplay = true;
89 }
91 if (! $grades = $DB->get_records('lesson_grades', array('lessonid' => $lesson->id), 'completed')) {
92     $grades = array();
93 }
95 if (! $times = $DB->get_records('lesson_timer', array('lessonid' => $lesson->id), 'starttime')) {
96     $times = array();
97 }
99 if ($nothingtodisplay) {
100     echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('nolessonattempts', 'lesson'));
101     echo $OUTPUT->notification(get_string('nolessonattempts', 'lesson'));
102     echo $OUTPUT->footer();
103     exit();
106 if ($action === 'delete') {
107     /// Process any form data before fetching attempts, grades and times
108     if (has_capability('mod/lesson:edit', $context) and $form = data_submitted() and confirm_sesskey()) {
109     /// Cycle through array of userids with nested arrays of tries
110         if (!empty($form->attempts)) {
111             foreach ($form->attempts as $userid => $tries) {
112                 // Modifier IS VERY IMPORTANT!  What does it do?
113                 //      Well, it is for when you delete multiple attempts for the same user.
114                 //      If you delete try 1 and 3 for a user, then after deleting try 1, try 3 then
115                 //      becomes try 2 (because try 1 is gone and all tries after try 1 get decremented).
116                 //      So, the modifier makes sure that the submitted try refers to the current try in the
117                 //      database - hope this all makes sense :)
118                 $modifier = 0;
120                 foreach ($tries as $try => $junk) {
121                     $try -= $modifier;
123                 /// Clean up the timer table by removing using the order - this is silly, it should be linked to specific attempt (skodak)
124                     $params = array ("userid" => $userid, "lessonid" => $lesson->id);
125                     $timers = $DB->get_records_sql("SELECT id FROM {lesson_timer}
126                                                      WHERE userid = :userid AND lessonid = :lessonid
127                                                   ORDER BY starttime", $params, $try, 1);
128                     if ($timers) {
129                         $timer = reset($timers);
130                         $DB->delete_records('lesson_timer', array('id' => $timer->id));
131                     }
133                 /// Remove the grade from the grades and high_scores tables - this is silly, it should be linked to specific attempt (skodak)
134                     $grades = $DB->get_records_sql("SELECT id FROM {lesson_grades}
135                                                      WHERE userid = :userid AND lessonid = :lessonid
136                                                   ORDER BY completed", $params, $try, 1);
138                     if ($grades) {
139                         $grade = reset($grades);
140                         $DB->delete_records('lesson_grades', array('id' => $grade->id));
141                         $DB->delete_records('lesson_high_scores', array('gradeid' => $grade->id, 'lessonid' => $lesson->id, 'userid' => $userid));
142                     }
144                 /// Remove attempts and update the retry number
145                     $DB->delete_records('lesson_attempts', array('userid' => $userid, 'lessonid' => $lesson->id, 'retry' => $try));
146                     $DB->execute("UPDATE {lesson_attempts} SET retry = retry - 1 WHERE userid = ? AND lessonid = ? AND retry > ?", array($userid, $lesson->id, $try));
148                 /// Remove seen branches and update the retry number
149                     $DB->delete_records('lesson_branch', array('userid' => $userid, 'lessonid' => $lesson->id, 'retry' => $try));
150                     $DB->execute("UPDATE {lesson_branch} SET retry = retry - 1 WHERE userid = ? AND lessonid = ? AND retry > ?", array($userid, $lesson->id, $try));
152                 /// update central gradebook
153                     lesson_update_grades($lesson, $userid);
155                     $modifier++;
156                 }
157             }
158         }
159     }
160     redirect(new moodle_url($PAGE->url, array('action'=>'reportoverview')));
162 } else if ($action === 'reportoverview') {
163     /**************************************************************************
164     this action is for default view and overview view
165     **************************************************************************/
166     echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('overview', 'lesson'));
168     $course_context = context_course::instance($course->id);
169     if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
170         $seeallgradeslink = new moodle_url('/grade/report/grader/index.php', array('id'=>$course->id));
171         $seeallgradeslink = html_writer::link($seeallgradeslink, get_string('seeallcoursegrades', 'grades'));
172         echo $OUTPUT->box($seeallgradeslink, 'allcoursegrades');
173     }
175     $studentdata = array();
177     // build an array for output
178     foreach ($attempts as $attempt) {
179         // 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.
180         if (!array_key_exists($attempt->userid, $studentdata) || !array_key_exists($attempt->retry, $studentdata[$attempt->userid])) {
181             // restore/setup defaults
182             $n = 0;
183             $timestart = 0;
184             $timeend = 0;
185             $usergrade = null;
187             // search for the grade record for this try. if not there, the nulls defined above will be used.
188             foreach($grades as $grade) {
189                 // check to see if the grade matches the correct user
190                 if ($grade->userid == $attempt->userid) {
191                     // see if n is = to the retry
192                     if ($n == $attempt->retry) {
193                         // get grade info
194                         $usergrade = round($grade->grade, 2); // round it here so we only have to do it once
195                         break;
196                     }
197                     $n++; // if not equal, then increment n
198                 }
199             }
200             $n = 0;
201             // search for the time record for this try. if not there, the nulls defined above will be used.
202             foreach($times as $time) {
203                 // check to see if the grade matches the correct user
204                 if ($time->userid == $attempt->userid) {
205                     // see if n is = to the retry
206                     if ($n == $attempt->retry) {
207                         // get grade info
208                         $timeend = $time->lessontime;
209                         $timestart = $time->starttime;
210                         break;
211                     }
212                     $n++; // if not equal, then increment n
213                 }
214             }
216             // build up the array.
217             // this array represents each student and all of their tries at the lesson
218             $studentdata[$attempt->userid][$attempt->retry] = array( "timestart" => $timestart,
219                                                                     "timeend" => $timeend,
220                                                                     "grade" => $usergrade,
221                                                                     "try" => $attempt->retry,
222                                                                     "userid" => $attempt->userid);
223         }
224     }
225     // set all the stats variables
226     $numofattempts = 0;
227     $avescore      = 0;
228     $avetime       = 0;
229     $highscore     = null;
230     $lowscore      = null;
231     $hightime      = null;
232     $lowtime       = null;
234     $table = new html_table();
236     // set up the table object
237     $table->head = array(get_string('name'), get_string('attempts', 'lesson'), get_string('highscore', 'lesson'));
238     $table->align = array('center', 'left', 'left');
239     $table->wrap = array('nowrap', 'nowrap', 'nowrap');
240     $table->attributes['class'] = 'standardtable generaltable';
241     $table->size = array(null, '70%', null);
243     // print out the $studentdata array
244     // going through each student that has attempted the lesson, so, each student should have something to be displayed
245     foreach ($students as $student) {
246         // check to see if the student has attempts to print out
247         if (array_key_exists($student->id, $studentdata)) {
248             // set/reset some variables
249             $attempts = array();
250             // gather the data for each user attempt
251             $bestgrade = 0;
252             $bestgradefound = false;
253             // $tries holds all the tries/retries a student has done
254             $tries = $studentdata[$student->id];
255             $studentname = "{$student->lastname},&nbsp;$student->firstname";
256             foreach ($tries as $try) {
257             // start to build up the checkbox and link
258                 if (has_capability('mod/lesson:edit', $context)) {
259                     $temp = '<input type="checkbox" id="attempts" name="attempts['.$try['userid'].']['.$try['try'].']" /> ';
260                 } else {
261                     $temp = '';
262                 }
264                 $temp .= "<a href=\"report.php?id=$cm->id&amp;action=reportdetail&amp;userid=".$try['userid'].'&amp;try='.$try['try'].'">';
265                 if ($try["grade"] !== null) { // if null then not done yet
266                     // this is what the link does when the user has completed the try
267                     $timetotake = $try["timeend"] - $try["timestart"];
269                     $temp .= $try["grade"]."%";
270                     $bestgradefound = true;
271                     if ($try["grade"] > $bestgrade) {
272                         $bestgrade = $try["grade"];
273                     }
274                     $temp .= "&nbsp;".userdate($try["timestart"]);
275                     $temp .= ",&nbsp;(".format_time($timetotake).")</a>";
276                 } else {
277                     // this is what the link does/looks like when the user has not completed the try
278                     $temp .= get_string("notcompleted", "lesson");
279                     $temp .= "&nbsp;".userdate($try["timestart"])."</a>";
280                     $timetotake = null;
281                 }
282                 // build up the attempts array
283                 $attempts[] = $temp;
285                 // run these lines for the stats only if the user finnished the lesson
286                 if ($try["grade"] !== null) {
287                     $numofattempts++;
288                     $avescore += $try["grade"];
289                     $avetime += $timetotake;
290                     if ($try["grade"] > $highscore || $highscore === null) {
291                         $highscore = $try["grade"];
292                     }
293                     if ($try["grade"] < $lowscore || $lowscore === null) {
294                         $lowscore = $try["grade"];
295                     }
296                     if ($timetotake > $hightime || $hightime == null) {
297                         $hightime = $timetotake;
298                     }
299                     if ($timetotake < $lowtime || $lowtime == null) {
300                         $lowtime = $timetotake;
301                     }
302                 }
303             }
304             // get line breaks in after each attempt
305             $attempts = implode("<br />\n", $attempts);
306             // add it to the table data[] object
307             $table->data[] = array($studentname, $attempts, $bestgrade."%");
308         }
309     }
310     // print it all out !
311     if (has_capability('mod/lesson:edit', $context)) {
312         echo  "<form id=\"theform\" method=\"post\" action=\"report.php\">\n
313                <input type=\"hidden\" name=\"sesskey\" value=\"".sesskey()."\" />\n
314                <input type=\"hidden\" name=\"id\" value=\"$cm->id\" />\n";
315     }
316     echo html_writer::table($table);
317     if (has_capability('mod/lesson:edit', $context)) {
318         $checklinks  = '<a href="javascript: checkall();">'.get_string('selectall').'</a> / ';
319         $checklinks .= '<a href="javascript: checknone();">'.get_string('deselectall').'</a>';
320         $checklinks .= html_writer::label('action', 'menuaction', false, array('class' => 'accesshide'));
321         $checklinks .= html_writer::select(array('delete' => get_string('deleteselected')), 'action', 0, array(''=>'choosedots'), array('id'=>'actionid', 'class' => 'autosubmit'));
322         $PAGE->requires->yui_module('moodle-core-formautosubmit',
323             'M.core.init_formautosubmit',
324             array(array('selectid' => 'actionid', 'nothing' => false))
325         );
326         echo $OUTPUT->box($checklinks, 'center');
327         echo '</form>';
328     }
330     // some stat calculations
331     if ($numofattempts == 0) {
332         $avescore = get_string("notcompleted", "lesson");
333     } else {
334         $avescore = format_float($avescore/$numofattempts, 2);
335     }
336     if ($avetime == null) {
337         $avetime = get_string("notcompleted", "lesson");
338     } else {
339         $avetime = format_float($avetime/$numofattempts, 0);
340         $avetime = format_time($avetime);
341     }
342     if ($hightime == null) {
343         $hightime = get_string("notcompleted", "lesson");
344     } else {
345         $hightime = format_time($hightime);
346     }
347     if ($lowtime == null) {
348         $lowtime = get_string("notcompleted", "lesson");
349     } else {
350         $lowtime = format_time($lowtime);
351     }
352     if ($highscore === null) {
353         $highscore = get_string("notcompleted", "lesson");
354     }
355     if ($lowscore === null) {
356         $lowscore = get_string("notcompleted", "lesson");
357     }
359     // output the stats
360     echo $OUTPUT->heading(get_string('lessonstats', 'lesson'), 3);
361     $stattable = new html_table();
362     $stattable->head = array(get_string('averagescore', 'lesson'), get_string('averagetime', 'lesson'),
363                             get_string('highscore', 'lesson'), get_string('lowscore', 'lesson'),
364                             get_string('hightime', 'lesson'), get_string('lowtime', 'lesson'));
365     $stattable->align = array('center', 'center', 'center', 'center', 'center', 'center');
366     $stattable->wrap = array('nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap');
367     $stattable->attributes['class'] = 'standardtable generaltable';
369     if (is_numeric($highscore)) {
370         $highscore .= '%';
371     }
372     if (is_numeric($lowscore)) {
373         $lowscore .= '%';
374     }
375     $stattable->data[] = array($avescore.'%', $avetime, $highscore, $lowscore, $hightime, $lowtime);
377     echo html_writer::table($stattable);
378 } else if ($action === 'reportdetail') {
379     /**************************************************************************
380     this action is for a student detailed view and for the general detailed view
382     General flow of this section of the code
383     1.  Generate a object which holds values for the statistics for each question/answer
384     2.  Cycle through all the pages to create a object.  Foreach page, see if the student actually answered
385         the page.  Then process the page appropriatly.  Display all info about the question,
386         Highlight correct answers, show how the user answered the question, and display statistics
387         about each page
388     3.  Print out info about the try (if needed)
389     4.  Print out the object which contains all the try info
391 **************************************************************************/
392     echo $lessonoutput->header($lesson, $cm, $action, false, null, get_string('detailedstats', 'lesson'));
394     $course_context = context_course::instance($course->id);
395     if (has_capability('gradereport/grader:view', $course_context) && has_capability('moodle/grade:viewall', $course_context)) {
396         $seeallgradeslink = new moodle_url('/grade/report/grader/index.php', array('id'=>$course->id));
397         $seeallgradeslink = html_writer::link($seeallgradeslink, get_string('seeallcoursegrades', 'grades'));
398         echo $OUTPUT->box($seeallgradeslink, 'allcoursegrades');
399     }
401     $formattextdefoptions = new stdClass;
402     $formattextdefoptions->para = false;  //I'll use it widely in this page
403     $formattextdefoptions->overflowdiv = true;
405     $userid = optional_param('userid', null, PARAM_INT); // if empty, then will display the general detailed view
406     $try    = optional_param('try', null, PARAM_INT);
408     $lessonpages = $lesson->load_all_pages();
409     foreach ($lessonpages as $lessonpage) {
410         if ($lessonpage->prevpageid == 0) {
411             $pageid = $lessonpage->id;
412         }
413     }
415     // now gather the stats into an object
416     $firstpageid = $pageid;
417     $pagestats = array();
418     while ($pageid != 0) { // EOL
419         $page = $lessonpages[$pageid];
420         $params = array ("lessonid" => $lesson->id, "pageid" => $page->id);
421         if ($allanswers = $DB->get_records_select("lesson_attempts", "lessonid = :lessonid AND pageid = :pageid", $params, "timeseen")) {
422             // get them ready for processing
423             $orderedanswers = array();
424             foreach ($allanswers as $singleanswer) {
425                 // ordering them like this, will help to find the single attempt record that we want to keep.
426                 $orderedanswers[$singleanswer->userid][$singleanswer->retry][] = $singleanswer;
427             }
428             // this is foreach user and for each try for that user, keep one attempt record
429             foreach ($orderedanswers as $orderedanswer) {
430                 foreach($orderedanswer as $tries) {
431                     $page->stats($pagestats, $tries);
432                 }
433             }
434         } else {
435             // no one answered yet...
436         }
437         //unset($orderedanswers);  initialized above now
438         $pageid = $page->nextpageid;
439     }
441     $manager = lesson_page_type_manager::get($lesson);
442     $qtypes = $manager->get_page_type_strings();
444     $answerpages = array();
445     $answerpage = "";
446     $pageid = $firstpageid;
447     // cycle through all the pages
448     //  foreach page, add to the $answerpages[] array all the data that is needed
449     //  from the question, the users attempt, and the statistics
450     // grayout pages that the user did not answer and Branch, end of branch, cluster
451     // and end of cluster pages
452     while ($pageid != 0) { // EOL
453         $page = $lessonpages[$pageid];
454         $answerpage = new stdClass;
455         $data ='';
457         $answerdata = new stdClass;
458         // Set some defaults for the answer data.
459         $answerdata->score = null;
460         $answerdata->response = null;
461         $answerdata->responseformat = FORMAT_PLAIN;
463         $answerpage->title = format_string($page->title);
465         $options = new stdClass;
466         $options->noclean = true;
467         $options->overflowdiv = true;
468         $answerpage->contents = format_text($page->contents, $page->contentsformat, $options);
470         $answerpage->qtype = $qtypes[$page->qtype].$page->option_description_string();
471         $answerpage->grayout = $page->grayout;
472         $answerpage->context = $context;
474         if (empty($userid)) {
475             // there is no userid, so set these vars and display stats.
476             $answerpage->grayout = 0;
477             $useranswer = null;
478         } elseif ($useranswers = $DB->get_records("lesson_attempts",array("lessonid"=>$lesson->id, "userid"=>$userid, "retry"=>$try,"pageid"=>$page->id), "timeseen")) {
479             // get the user's answer for this page
480             // need to find the right one
481             $i = 0;
482             foreach ($useranswers as $userattempt) {
483                 $useranswer = $userattempt;
484                 $i++;
485                 if ($lesson->maxattempts == $i) {
486                     break; // reached maxattempts, break out
487                 }
488             }
489         } else {
490             // user did not answer this page, gray it out and set some nulls
491             $answerpage->grayout = 1;
492             $useranswer = null;
493         }
494         $i = 0;
495         $n = 0;
496         $answerpages[] = $page->report_answers(clone($answerpage), clone($answerdata), $useranswer, $pagestats, $i, $n);
497         $pageid = $page->nextpageid;
498     }
500     /// actually start printing something
501     $table = new html_table();
502     $table->wrap = array();
503     $table->width = "60%";
504     if (!empty($userid)) {
505         // if looking at a students try, print out some basic stats at the top
507             // print out users name
508             //$headingobject->lastname = $students[$userid]->lastname;
509             //$headingobject->firstname = $students[$userid]->firstname;
510             //$headingobject->attempt = $try + 1;
511             //print_heading(get_string("studentattemptlesson", "lesson", $headingobject));
512         echo $OUTPUT->heading(get_string('attempt', 'lesson', $try+1), 3);
514         $table->head = array();
515         $table->align = array('right', 'left');
516         $table->attributes['class'] = 'compacttable generaltable';
518         $params = array("lessonid"=>$lesson->id, "userid"=>$userid);
519         if (!$grades = $DB->get_records_select("lesson_grades", "lessonid = :lessonid and userid = :userid", $params, "completed", "*", $try, 1)) {
520             $grade = -1;
521             $completed = -1;
522         } else {
523             $grade = current($grades);
524             $completed = $grade->completed;
525             $grade = round($grade->grade, 2);
526         }
527         if (!$times = $DB->get_records_select("lesson_timer", "lessonid = :lessonid and userid = :userid", $params, "starttime", "*", $try, 1)) {
528             $timetotake = -1;
529         } else {
530             $timetotake = current($times);
531             $timetotake = $timetotake->lessontime - $timetotake->starttime;
532         }
534         if ($timetotake == -1 || $completed == -1 || $grade == -1) {
535             $table->align = array("center");
537             $table->data[] = array(get_string("notcompleted", "lesson"));
538         } else {
539             $user = $students[$userid];
541             $gradeinfo = lesson_grade($lesson, $try, $user->id);
543             $table->data[] = array(get_string('name').':', $OUTPUT->user_picture($user, array('courseid'=>$course->id)).fullname($user, true));
544             $table->data[] = array(get_string("timetaken", "lesson").":", format_time($timetotake));
545             $table->data[] = array(get_string("completed", "lesson").":", userdate($completed));
546             $table->data[] = array(get_string('rawgrade', 'lesson').':', $gradeinfo->earned.'/'.$gradeinfo->total);
547             $table->data[] = array(get_string("grade", "lesson").":", $grade."%");
548         }
549         echo html_writer::table($table);
551         // Don't want this class for later tables
552         $table->attributes['class'] = '';
553     }
556     $table->align = array('left', 'left');
557     $table->size = array('70%', null);
558     $table->attributes['class'] = 'compacttable generaltable';
560     foreach ($answerpages as $page) {
561         unset($table->data);
562         if ($page->grayout) { // set the color of text
563             $fontstart = "<span class=\"dimmed\">";
564             $fontend = "</font>";
565             $fontstart2 = $fontstart;
566             $fontend2 = $fontend;
567         } else {
568             $fontstart = "";
569             $fontend = "";
570             $fontstart2 = "";
571             $fontend2 = "";
572         }
574         $table->head = array($fontstart2.$page->qtype.": ".format_string($page->title).$fontend2, $fontstart2.get_string("classstats", "lesson").$fontend2);
575         $table->data[] = array($fontstart.get_string("question", "lesson").": <br />".$fontend.$fontstart2.$page->contents.$fontend2, " ");
576         $table->data[] = array($fontstart.get_string("answer", "lesson").":".$fontend, ' ');
577         // apply the font to each answer
578         if (!empty($page->answerdata)) {
579             foreach ($page->answerdata->answers as $answer){
580                 $modified = array();
581                 foreach ($answer as $single) {
582                     // need to apply a font to each one
583                     $modified[] = $fontstart2.$single.$fontend2;
584                 }
585                 $table->data[] = $modified;
586             }
587             if (isset($page->answerdata->response)) {
588                 $table->data[] = array($fontstart.get_string("response", "lesson").": <br />".$fontend.$fontstart2.format_text($page->answerdata->response,$page->answerdata->responseformat,$formattextdefoptions).$fontend2, " ");
589             }
590             $table->data[] = array($page->answerdata->score, " ");
591         } else {
592             $table->data[] = array(get_string('didnotanswerquestion', 'lesson'), " ");
593         }
594         echo html_writer::table($table);
595     }
596 } else {
597     print_error('unknowaction');
600 /// Finish the page
601 echo $OUTPUT->footer();