SCORM MDL-21555 improved Report interface - now allows export as text/excel/ods...
[moodle.git] / mod / scorm / report.php
1 <?php
3 // This script uses installed report plugins to print quiz reports
5     require_once("../../config.php");
6     require_once($CFG->libdir.'/tablelib.php');
7     require_once($CFG->dirroot.'/mod/scorm/locallib.php');
8     require_once($CFG->dirroot.'/mod/scorm/reportsettings_form.php');
9     require_once($CFG->libdir.'/formslib.php');
10     define('SCORM_REPORT_DEFAULT_PAGE_SIZE', 20);
11     define('SCORM_REPORT_ATTEMPTS_ALL_STUDENTS', 0);
12     define('SCORM_REPORT_ATTEMPTS_STUDENTS_WITH', 1);
13     define('SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO', 2);
15     $id = optional_param('id', '', PARAM_INT);    // Course Module ID, or
16     $a = optional_param('a', '', PARAM_INT);     // SCORM ID
17     $b = optional_param('b', '', PARAM_INT);     // SCO ID
18     $user = optional_param('user', '', PARAM_INT);  // User ID
19     $attempt = optional_param('attempt', '1', PARAM_INT);  // attempt number
20     $action     = optional_param('action', '', PARAM_ALPHA);
21     $attemptids = optional_param('attemptid', array(), PARAM_RAW);
22     $download = optional_param('download', '', PARAM_RAW);
24     $url = new moodle_url('/mod/scorm/report.php');
25     if ($user !== '') {
26         $url->param('user', $user);
27     }
28     if ($attempt !== '1') {
29         $url->param('attempt', $attempt);
30     }
31     if ($action !== '') {
32         $url->param('action', $action);
33     }
35     if (!empty($id)) {
36         $url->param('id', $id);
37         if (! $cm = get_coursemodule_from_id('scorm', $id)) {
38             print_error('invalidcoursemodule');
39         }
40         if (! $course = $DB->get_record('course', array('id'=>$cm->course))) {
41             print_error('coursemisconf');
42         }
43         if (! $scorm = $DB->get_record('scorm', array('id'=>$cm->instance))) {
44             print_error('invalidcoursemodule');
45         }
46     } else {
47         if (!empty($b)) {
48             $url->param('b', $b);
49             if (! $sco = $DB->get_record('scorm_scoes', array('id'=>$b))) {
50                 print_error('invalidactivity', 'scorm');
51             }
52             $a = $sco->scorm;
53         }
54         if (!empty($a)) {
55             $url->param('a', $a);
56             if (! $scorm = $DB->get_record('scorm', array('id'=>$a))) {
57                 print_error('invalidcoursemodule');
58             }
59             if (! $course = $DB->get_record('course', array('id'=>$scorm->course))) {
60                 print_error('coursemisconf');
61             }
62             if (! $cm = get_coursemodule_from_instance('scorm', $scorm->id, $course->id)) {
63                 print_error('invalidcoursemodule');
64             }
65         }
66     }
67     $PAGE->set_url($url);
69     require_login($course->id, false, $cm);
71     $contextmodule = get_context_instance(CONTEXT_MODULE,$cm->id);
73     require_capability('mod/scorm:viewreport', $contextmodule);
75     add_to_log($course->id, 'scorm', 'report', 'report.php?id='.$cm->id, $scorm->id, $cm->id);
77     if (!empty($user)) {
78         $userdata = scorm_get_user_data($user);
79     } else {
80         $userdata = null;
81     }
82     if (!empty($download)) {
83         $noheader = true;
84     }
85 /// Print the page header
86     if (empty($noheader)) {
88         $strscorms = get_string('modulenameplural', 'scorm');
89         $strscorm  = get_string('modulename', 'scorm');
90         $strreport  = get_string('report', 'scorm');
91         $strattempt  = get_string('attempt', 'scorm');
92         $strname  = get_string('name');
94         $PAGE->set_title("$course->shortname: ".format_string($scorm->name));
95         $PAGE->set_heading($course->fullname);
96         $PAGE->navbar->add($strreport, new moodle_url('/mod/scorm/report.php', array('id'=>$cm->id)));
98         if (empty($b)) {
99             if (!empty($a)) {
100                 $PAGE->navbar->add("$strattempt $attempt - ".fullname($userdata));
101             }
102         } else {
103             $PAGE->navbar->add("$strattempt $attempt - ".fullname($userdata), new moodle_url('/mod/scorm/report.php', array('a'=>$a, 'user'=>$user, 'attempt'=>$attempt)));
104             $PAGE->navbar->add($sco->title);
105         }
106         echo $OUTPUT->header();
107         $currenttab = 'reports';
108         require($CFG->dirroot . '/mod/scorm/tabs.php');
109         echo $OUTPUT->heading(format_string($scorm->name));
110     }
112     if ($action == 'delete' && has_capability('mod/scorm:deleteresponses',$contextmodule) && confirm_sesskey()) {
113         if (scorm_delete_responses($attemptids, $scorm->id)) { //delete responses.
114             add_to_log($course->id, 'scorm', 'delete attempts', 'report.php?id=' . $cm->id, implode(",", $attemptids), $cm->id);
115             echo $OUTPUT->notification(get_string('scormresponsedeleted', 'scorm'), 'notifysuccess');
116         }
117     }
119     if (empty($b)) {
120         if (empty($a)) {
121             // No options, show the global scorm report
122                 $pageoptions = array();
123                 $pageoptions['id'] = $cm->id;
124                 $reporturl = new moodle_url($CFG->wwwroot.'/mod/scorm/report.php', $pageoptions);
126                 // find out current groups mode
127                 $currentgroup = groups_get_activity_group($cm, true);
129                 // detailed report
130                 $mform = new mod_scorm_report_settings( $reporturl, compact('currentgroup') );
131                 if ($fromform = $mform->get_data()) {
132                     $detailedrep = $fromform->detailedrep;
133                     $pagesize = $fromform->pagesize;
134                     $attemptsmode = $fromform->attemptsmode;
135                     set_user_preference('scorm_report_detailed', $detailedrep);
136                     set_user_preference('scorm_report_pagesize', $pagesize);
137                 } else {
138                     $detailedrep = get_user_preferences('scorm_report_detailed', false);
139                     $pagesize = get_user_preferences('scorm_report_pagesize', 0);
140                     $attemptsmode = optional_param('attemptsmode', SCORM_REPORT_ATTEMPTS_STUDENTS_WITH, PARAM_INT);
141                 }
142                 if ($pagesize < 1) {
143                     $pagesize = SCORM_REPORT_DEFAULT_PAGE_SIZE;
144                 }
146                 // select group menu
147                 $displayoptions = array();
148                 $displayoptions['id'] = $cm->id;
149                 $displayoptions['attemptsmode'] = $attemptsmode;
150                 $reporturlwithdisplayoptions = new moodle_url($CFG->wwwroot.'/mod/scorm/report.php', $displayoptions);
152                 if ($groupmode = groups_get_activity_groupmode($cm)) {   // Groups are being used
153                     if (!$download) {
154                         groups_print_activity_menu($cm, $reporturlwithdisplayoptions->out());
155                     }
156                 }
158                 // We only want to show the checkbox to delete attempts
159                 // if the user has permissions and if the report mode is showing attempts.
160                 $candelete = has_capability('mod/scorm:deleteresponses',$contextmodule) 
161                         && ($attemptsmode!= SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO);
162                 // select the students
163                 $nostudents = false;
165                 if (empty($currentgroup)) {
166                     // all users who can attempt scoes
167                     if (!$students = get_users_by_capability($contextmodule, 'mod/scorm:savetrack','','','','','','',false)){
168                         notify(get_string('nostudentsyet'));
169                         $nostudents = true;
170                         $allowedlist = '';
171                     } else {
172                         $allowedlist = join(',',array_keys($students));
173                     }
174                 } else {
175                     // all users who can attempt scoes and who are in the currently selected group
176                     if (!$groupstudents = get_users_by_capability($context, 'mod/scorm:savetrack','','','','',$currentgroup,'',false)){
177                         notify(get_string('nostudentsingroup'));
178                         $nostudents = true;
179                         $groupstudents = array();
180                     }
181                     $allowedlist = join(',', array_keys($groupstudents));
182                 }
183                 
184                 if( !$nostudents ) {
185                     
186                     // Now check if asked download of data
187                     if ($download) {
188                         $filename = clean_filename("$course->shortname ".format_string($scorm->name,true));
189                     }
190                 
191                     // Define table columns
192                     $columns = array();
193                     $headers = array();
194                     if (!$download && $candelete) {
195                         $columns[]= 'checkbox';
196                         $headers[]= NULL;
197                     }
198                     if (!$download && $CFG->grade_report_showuserimage) {
199                         $columns[]= 'picture';
200                         $headers[]= '';
201                     }
202                     $columns[]= 'fullname';
203                     $headers[]= get_string('name');
204                     if ($CFG->grade_report_showuseridnumber) {
205                         $columns[]= 'idnumber';
206                         $headers[]= get_string('idnumber');
207                     }
208                     $columns[]= 'attempt';
209                     $headers[]= get_string('attempt', 'scorm');
210                     $columns[]= 'start';
211                     $headers[]= get_string('started','scorm');
212                     $columns[]= 'finish';
213                     $headers[]= get_string('last','scorm');
214                     $columns[]= 'score';
215                     $headers[]= get_string('score','scorm');
216                     if ($detailedrep && $scoes = $DB->get_records('scorm_scoes',array("scorm"=>$scorm->id),'id')) {
217                         foreach ($scoes as $sco) {
218                             if ($sco->launch!='') {
219                                 $columns[]= 'scograde'.$sco->id;
220                                 $headers[]= format_string($sco->title);
221                                 $table->head[]= format_string($sco->title);
222                             }
223                         }
224                     } else {
225                         $scoes = NULL;
226                     }
227                     
228                     if (!$download) {
229                         $table = new flexible_table('mod-scorm-report');
230             
231                         $table->define_columns($columns);
232                         $table->define_headers($headers);
233                         $table->define_baseurl($reporturlwithdisplayoptions->out());
234             
235                         $table->sortable(true);
236                         $table->collapsible(true);
237                         
238                         $table->column_suppress('picture');
239                         $table->column_suppress('fullname');
240                         $table->column_suppress('idnumber');
241                         
242                         $table->no_sorting('start');
243                         $table->no_sorting('finish');
244                         $table->no_sorting('score');
245                         if( $scoes ) {
246                             foreach ($scoes as $sco) {
247                                 if ($sco->launch!='') {
248                                     $table->no_sorting('scograde'.$sco->id);
249                                 }
250                             }
251                         }
252                         
253                         $table->column_class('picture', 'picture');
254                         $table->column_class('fullname', 'bold');
255                         $table->column_class('score', 'bold');
256             
257                         $table->set_attribute('cellspacing', '0');
258                         $table->set_attribute('id', 'attempts');
259                         $table->set_attribute('class', 'generaltable generalbox');
260                         
261                         // Start working -- this is necessary as soon as the niceties are over
262                         $table->setup();
263                     } else if ($download =='ODS') {
264                         require_once("$CFG->libdir/odslib.class.php");
265             
266                         $filename .= ".ods";
267                         // Creating a workbook
268                         $workbook = new MoodleODSWorkbook("-");
269                         // Sending HTTP headers
270                         $workbook->send($filename);
271                         // Creating the first worksheet
272                         $sheettitle = get_string('report','scorm');
273                         $myxls =& $workbook->add_worksheet($sheettitle);
274                         // format types
275                         $format =& $workbook->add_format();
276                         $format->set_bold(0);
277                         $formatbc =& $workbook->add_format();
278                         $formatbc->set_bold(1);
279                         $formatbc->set_align('center');
280                         $formatb =& $workbook->add_format();
281                         $formatb->set_bold(1);
282                         $formaty =& $workbook->add_format();
283                         $formaty->set_bg_color('yellow');
284                         $formatc =& $workbook->add_format();
285                         $formatc->set_align('center');
286                         $formatr =& $workbook->add_format();
287                         $formatr->set_bold(1);
288                         $formatr->set_color('red');
289                         $formatr->set_align('center');
290                         $formatg =& $workbook->add_format();
291                         $formatg->set_bold(1);
292                         $formatg->set_color('green');
293                         $formatg->set_align('center');
294                         // Here starts workshhet headers
295             
296                         $colnum = 0;
297                         foreach ($headers as $item) {
298                             $myxls->write(0,$colnum,$item,$formatbc);
299                             $colnum++;
300                         }
301                         $rownum=1;
302                     } else if ($download =='Excel') {
303                         require_once("$CFG->libdir/excellib.class.php");
304             
305                         $filename .= ".xls";
306                         // Creating a workbook
307                         $workbook = new MoodleExcelWorkbook("-");
308                         // Sending HTTP headers
309                         $workbook->send($filename);
310                         // Creating the first worksheet
311                         $sheettitle = get_string('report','scorm');
312                         $myxls =& $workbook->add_worksheet($sheettitle);
313                         // format types
314                         $format =& $workbook->add_format();
315                         $format->set_bold(0);
316                         $formatbc =& $workbook->add_format();
317                         $formatbc->set_bold(1);
318                         $formatbc->set_align('center');
319                         $formatb =& $workbook->add_format();
320                         $formatb->set_bold(1);
321                         $formaty =& $workbook->add_format();
322                         $formaty->set_bg_color('yellow');
323                         $formatc =& $workbook->add_format();
324                         $formatc->set_align('center');
325                         $formatr =& $workbook->add_format();
326                         $formatr->set_bold(1);
327                         $formatr->set_color('red');
328                         $formatr->set_align('center');
329                         $formatg =& $workbook->add_format();
330                         $formatg->set_bold(1);
331                         $formatg->set_color('green');
332                         $formatg->set_align('center');
333             
334                         $colnum = 0;
335                         foreach ($headers as $item) {
336                             $myxls->write(0,$colnum,$item,$formatbc);
337                             $colnum++;
338                         }
339                         $rownum=1;
340                     } else if ($download=='CSV') {
341                         $filename .= ".txt";
342                         header("Content-Type: application/download\n");
343                         header("Content-Disposition: attachment; filename=\"$filename\"");
344                         header("Expires: 0");
345                         header("Cache-Control: must-revalidate,post-check=0,pre-check=0");
346                         header("Pragma: public");
347                         echo implode("\t", $headers)." \n";
348                     }
350                     // Construct the SQL
351                     $select = 'SELECT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').' AS uniqueid, ';
352                     $select .= 'st.scormid AS scormid, st.attempt AS attempt, ' . 
353                             'u.id AS userid, u.idnumber, u.firstname, u.lastname, u.picture, u.imagealt ';
355                     // This part is the same for all cases - join users and scorm_scoes_track tables
356                     $from = 'FROM '.$CFG->prefix.'user u ';
357                     $from .= 'LEFT JOIN '.$CFG->prefix.'scorm_scoes_track st ON st.userid = u.id AND st.scormid = '.$scorm->id;
358                     switch ($attemptsmode){
359                         case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH:
360                             // Show only students with attempts
361                             $where = ' WHERE u.id IN (' .$allowedlist. ') AND st.userid IS NOT NULL';
362                             break;
363                         case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
364                             // Show only students without attempts
365                             $where = ' WHERE u.id IN (' .$allowedlist. ') AND st.userid IS NULL';
366                             break;
367                         case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS:
368                             // Show all students with or without attempts
369                             $where = ' WHERE u.id IN (' .$allowedlist. ') AND (st.userid IS NOT NULL OR st.userid IS NULL)';
370                             break;
371                     }
372                     $groupby = ' GROUP BY uniqueid';
373                     
374                     $countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(st.attempt, 0)').')) AS nbresults, ';
375                     $countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'','st.attempt').')) AS nbattempts, ';
376                     $countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers ';
377                     $countsql .= $from.$where;
378                     
379                     if (!$download) {
380                         $sort = $table->get_sql_sort();
381                     }
382                     else {
383                         $sort = '';
384                     }
385                     // Fix some wired sorting
386                     if (empty($sort)) {
387                         $sort = ' ORDER BY uniqueid';
388                     } else {
389                         $sort = ' ORDER BY '.$sort;
390                     }
392                     if (!$download) {
393                         // Add extra limits due to initials bar
394                         if($table->get_sql_where()) {
395                             $where .= ' AND '.$table->get_sql_where();
396                         }
398                         if (!empty($countsql)) {
399                             $count = $DB->get_record_sql($countsql);
400                             $totalinitials = $count->nbresults;
401                             if ($table->get_sql_where()) {
402                                 $countsql .= ' AND '.$table->get_sql_where();
403                             }
404                             $count = $DB->get_record_sql($countsql);
405                             $total  = $count->nbresults;
406                         }
408                         $table->pagesize($pagesize, $total);
409                         
410                         echo '<div class="quizattemptcounts">';
411                         if ( $count->nbresults == $count->nbattempts ) {
412                             echo get_string('reportcountattempts','scorm', $count);
413                         } else if( $count->nbattempts>0 ) {
414                             echo get_string('reportcountallattempts','scorm', $count);
415                         } else {
416                             echo $count->nbusers.' '.get_string('users');
417                         }
418                         echo '</div>';
419                     }
421                     // Fetch the attempts
422                     if (!$download) {
423                         $attempts = $DB->get_records_sql($select.$from.$where.$groupby.$sort, array(),
424                                                 $table->get_page_start(), $table->get_page_size());
425                         echo '<div id="scormtablecontainer">';
426                         if ($candelete) {
427                             // Start form
428                             $strreallydel  = addslashes(get_string('deleteattemptcheck','scorm'));
429                             echo '<form id="attemptsform" method="post" action="' . $reporturlwithdisplayoptions->out(true) .
430                                     '" onsubmit="return confirm(\''.$strreallydel.'\');">';
431                             echo '<input type="hidden" name="action" value="delete"/>';
432                             echo '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
433                             echo '<div style="display: none;">';
434                             echo html_writer::input_hidden_params($reporturlwithdisplayoptions);
435                             echo '</div>';
436                             echo '<div>';
437                         }
438                         $table->initialbars($totalinitials>20); // Build table rows
439                     } else {
440                         $attempts = $DB->get_records_sql($select.$from.$where.$groupby.$sort);
441                     }
443                     if ($attempts) {
444                         foreach($attempts as $scouser){
445                             $row = array();
446                             if (!empty($scouser->attempt)) {
447                                 $timetracks = scorm_get_sco_runtime($scorm->id, false, $scouser->userid, $scouser->attempt);
448                             }
449                             if (in_array('checkbox', $columns)){
450                                 if ($candelete && !empty($timetracks->start)) {
451                                     $row[] = '<input type="checkbox" name="attemptid[]" value="'. $scouser->userid . ':' . $scouser->attempt . '" />';
452                                 } else if($candelete) {
453                                     $row[] = '';
454                                 }
455                             }
456                             //TODO: fetch the user details elsewhere - this is a performance problem!!
457                             if (in_array('picture', $columns)){
458                                 $user = (object)array('id'=>$scouser->userid);
459                                 $row[] = $OUTPUT->user_picture($user, array('courseid'=>$course->id));
460                             }
461                             if (!$download){
462                                 $row[] = '<a href="'.$CFG->wwwroot.'/user/view.php?id='.$scouser->userid.'&amp;course='.$course->id.'">'.fullname($scouser).'</a>';
463                             } else {
464                                 $row[] = fullname($scouser);
465                             }
466                             if (in_array('idnumber', $columns)){
467                                 $row[] = $scouser->idnumber;
468                             }
469                             if (empty($timetracks->start)) {
470                                 $row[] = '-';
471                                 $row[] = '-';
472                                 $row[] = '-';
473                                 $row[] = '-';
474                             } else {
475                                 if (!$download) $row[] = '<a href="report.php?a='.$scorm->id.'&amp;user='.$scouser->userid.'&amp;attempt='.$scouser->attempt.'">'.$scouser->attempt.'</a>';
476                                 else $row[] = $scouser->attempt;
477                                 if ($download =='ODS' || $download =='Excel' ) $row[] = userdate($timetracks->start, get_string("strftimedatetime", "langconfig"));
478                                 else $row[] = userdate($timetracks->start);
479                                 if ($download =='ODS' || $download =='Excel' ) $row[] = userdate($timetracks->finish, get_string('strftimedatetime', 'langconfig'));
480                                 else $row[] = userdate($timetracks->finish);
481                                 
482                                 $row[] = scorm_grade_user_attempt($scorm, $scouser->userid, $scouser->attempt);
483                             }
484                             // print out all scores of attempt
485                             if ($scoes) {
486                                 foreach ($scoes as $sco) {
487                                     if ($sco->launch!='') {
488                                         if ($trackdata = scorm_get_tracks($sco->id,$scouser->userid,$scouser->attempt)) {
489                                             if ($trackdata->status == '') {
490                                                 $trackdata->status = 'notattempted';
491                                             }
492                                             $strstatus = get_string($trackdata->status, 'scorm');
493                                             // if raw score exists, print it
494                                             if ($trackdata->score_raw != '') {
495                                                 $score = $trackdata->score_raw;
496                                                 // add max score if it exists
497                                                 if ($scorm->version == 'SCORM_1.3') {
498                                                     $maxkey = 'cmi.score.max';
499                                                 } else {
500                                                     $maxkey = 'cmi.core.score.max';
501                                                 }
502                                                 if (isset($trackdata->$maxkey)) {
503                                                     $score .= '/'.$trackdata->$maxkey;
504                                                 }
505                                             // else print out status
506                                             } else {
507                                                 $score = $strstatus;
508                                             }
509                                             if (!$download) {
510                                                 $row[] = '<img src="'.$OUTPUT->pix_url('pix/'.$trackdata->status, 'scorm').'" alt="'.$strstatus.'" title="'.$strstatus.'" /><br/>
511                                                           <a href="report.php?b='.$sco->id.'&amp;user='.$scouser->userid.'&amp;attempt='.$scouser->attempt.
512                                                          '" title="'.get_string('details','scorm').'">'.$score.'</a>';
513                                             } else {
514                                                 $row[] = $score;
515                                             }
516                                         } else {
517                                             // if we don't have track data, we haven't attempted yet
518                                             $strstatus = get_string('notattempted', 'scorm');
519                                             if (!$download) {
520                                                 $row[] = '<img src="'.$OUTPUT->pix_url('pix/notattempted', 'scorm').'" alt="'.$strstatus.'" title="'.$strstatus.'" /><br/>'.$strstatus;
521                                             } else {
522                                                 $row[] = $strstatus;
523                                             }
524                                         }
525                                     }
526                                 }
527                             }
528                             
529                             if (!$download) {
530                                 $table->add_data($row);
531                             } else if ($download == 'Excel' or $download == 'ODS') {
532                                 $colnum = 0;
533                                 foreach($row as $item){
534                                     $myxls->write($rownum,$colnum,$item,$format);
535                                     $colnum++;
536                                 }
537                                 $rownum++;
538                             } else if ($download=='CSV') {
539                                 $text = implode("\t", $row);
540                                 echo $text." \n";
541                             }
542                         }
543                         if (!$download) {
544                             if ($candelete) {
545                                 echo '<table id="commands">';
546                                 echo '<tr><td>';
547                                 echo '<a href="javascript:select_all_in(\'DIV\',null,\'scormtablecontainer\');">'.
548                                         get_string('selectall', 'scorm').'</a> / ';
549                                 echo '<a href="javascript:deselect_all_in(\'DIV\',null,\'scormtablecontainer\');">'.
550                                         get_string('selectnone', 'scorm').'</a> ';
551                                 echo '&nbsp;&nbsp;';
552                                 echo '<input type="submit" value="'.get_string('deleteselected', 'quiz_overview').'"/>';
553                                 echo '</td></tr></table>';
554                                 // Close form
555                                 echo '</div>';
556                                 echo '</form>';
557                             }
558                             echo '</div>';
559                             if (!empty($attempts)) {
560                                 echo '<table class="boxaligncenter"><tr>';
561                                 echo '<td>';
562                                 echo $OUTPUT->single_button(new moodle_url('/mod/scorm/report.php', $pageoptions + $displayoptions + array('download' => 'ODS')), get_string('downloadods'));
563                                 echo "</td>\n";
564                                 echo '<td>';
565                                 echo $OUTPUT->single_button(new moodle_url('/mod/scorm/report.php', $pageoptions + $displayoptions + array('download' => 'Excel')), get_string('downloadexcel'));
566                                 echo "</td>\n";
567                                 echo '<td>';
568                                 echo $OUTPUT->single_button(new moodle_url('/mod/scorm/report.php', $pageoptions + $displayoptions + array('download' => 'CSV')), get_string('downloadtext'));
569                                 echo "</td>\n";
570                                 echo "<td>";
571                                 echo "</td>\n";
572                                 echo '</tr></table>';
573                         }
574                     }
575                 } else {
576                     notify(get_string('noactivity', 'scorm'));
577                     if (!$download) {
578                         echo html_writer::table($table);
579                     }
580                 }
581                 if ($download == 'Excel' or $download == 'ODS') {
582                     $workbook->close();
583                     exit;
584                 } else if ($download == 'CSV') {
585                     exit;
586                 }
587                 if (!$download) {
588                     $mform->set_data($displayoptions + compact('detailedrep', 'pagesize'));
589                     $mform->display();
590                 }
591             } else {
592                 echo $OUTPUT->notification(get_string('noactivity', 'scorm'));
593             }
594         } else {
595             if (!empty($user)) {
596                 // User SCORM report
597                 if ($scoes = $DB->get_records_select('scorm_scoes',"scorm=? ORDER BY id", array($scorm->id))) {
598                     if (!empty($userdata)) {
599                         echo $OUTPUT->box_start('generalbox boxaligncenter');
600                         echo '<div class="mdl-align">'."\n";
601                         $userrec = (object)array('id'=>$user);
602                         echo $OUTPUT->user_picture($userrec, array('courseid'=>$course->id));
603                         echo "<a href=\"$CFG->wwwroot/user/view.php?id=$user&amp;course=$course->id\">".
604                              "$userdata->firstname $userdata->lastname</a><br />";
605                         echo get_string('attempt','scorm').': '.$attempt;
606                         echo '</div>'."\n";
607                         echo $OUTPUT->box_end();
609                         // Print general score data
610                         $table = new html_table();
611                         $table->head = array(get_string('title','scorm'),
612                                              get_string('status','scorm'),
613                                              get_string('time','scorm'),
614                                              get_string('score','scorm'),
615                                              '');
616                         $table->align = array('left', 'center','center','right','left');
617                         $table->wrap = array('nowrap', 'nowrap','nowrap','nowrap','nowrap');
618                         $table->width = '80%';
619                         $table->size = array('*', '*', '*', '*', '*');
620                         foreach ($scoes as $sco) {
621                             if ($sco->launch!='') {
622                                 $row = array();
623                                 $score = '&nbsp;';
624                                 if ($trackdata = scorm_get_tracks($sco->id,$user,$attempt)) {
625                                     if ($trackdata->score_raw != '') {
626                                         $score = $trackdata->score_raw;
627                                     }
628                                     if ($trackdata->status == '') {
629                                         $trackdata->status = 'notattempted';
630                                     }
631                                     $detailslink = '<a href="report.php?b='.$sco->id.'&amp;user='.$user.'&amp;attempt='.$attempt.'" title="'.
632                                                     get_string('details','scorm').'">'.get_string('details','scorm').'</a>';
633                                 } else {
634                                     $trackdata->status = 'notattempted';
635                                     $trackdata->total_time = '&nbsp;';
636                                     $detailslink = '&nbsp;';
637                                 }
638                                 $strstatus = get_string($trackdata->status,'scorm');
639                                 $row[] = '<img src="'.$OUTPUT->pix_url('pix/' . $trackdata->status, 'scorm').'" alt="'.$strstatus.'" title="'.
640                                          $strstatus.'" />&nbsp;'.format_string($sco->title);
641                                 $row[] = get_string($trackdata->status,'scorm');
642                                 $row[] = scorm_format_date_time($trackdata->total_time);
643                                 $row[] = $score;
644                                 $row[] = $detailslink;
645                             } else {
646                                 $row = array(format_string($sco->title), '&nbsp;', '&nbsp;', '&nbsp;', '&nbsp;');
647                             }
648                             $table->data[] = $row;
649                         }
650                         echo html_writer::table($table);
651                     }
652                 }
653             } else {
654                 notice('No users to report');
655             }
656         }
657     } else {
658         // User SCO report
659         if (!empty($userdata)) {
660             echo $OUTPUT->box_start('generalbox boxaligncenter');
661             //print_heading(format_string($sco->title));
662             echo $OUTPUT->heading('<a href="'.$CFG->wwwroot.'/mod/scorm/player.php?a='.$scorm->id.'&amp;mode=browse&amp;scoid='.$sco->id.'" target="_new">'.format_string($sco->title).'</a>');
663             echo '<div class="mdl-align">'."\n";
664             $userrec = (object)array('id'=>$user);
665             echo $OUTPUT->user_picture($userrec, array('courseid'=>$course->id));
666             echo "<a href=\"$CFG->wwwroot/user/view.php?id=$user&amp;course=$course->id\">".
667                  "$userdata->firstname $userdata->lastname</a><br />";
668             $scoreview = '';
669             if ($trackdata = scorm_get_tracks($sco->id,$user,$attempt)) {
670                 if ($trackdata->score_raw != '') {
671                     $scoreview = get_string('score','scorm').':&nbsp;'.$trackdata->score_raw;
672                 }
673                 if ($trackdata->status == '') {
674                     $trackdata->status = 'notattempted';
675                 }
676             } else {
677                 $trackdata->status = 'notattempted';
678                 $trackdata->total_time = '';
679             }
680             $strstatus = get_string($trackdata->status,'scorm');
681             echo '<img src="'.$OUTPUT->pix_url('pix/'.$trackdata->status, 'scorm').'" alt="'.$strstatus.'" title="'.
682             $strstatus.'" />&nbsp;'.scorm_format_date_time($trackdata->total_time).'<br />'.$scoreview.'<br />';
683             echo '</div>'."\n";
684             echo '<hr /><h2>'.get_string('details','scorm').'</h2>';
686             // Print general score data
687             $table = new html_table();
688             $table->head = array(get_string('element','scorm'), get_string('value','scorm'));
689             $table->align = array('left', 'left');
690             $table->wrap = array('nowrap', 'nowrap');
691             $table->width = '100%';
692             $table->size = array('*', '*');
694             $existelements = false;
695             if ($scorm->version == 'SCORM_1.3') {
696                 $elements = array('raw' => 'cmi.score.raw',
697                                   'min' => 'cmi.score.min',
698                                   'max' => 'cmi.score.max',
699                                   'status' => 'cmi.completion_status',
700                                   'time' => 'cmi.total_time');
701             } else {
702                 $elements = array('raw' => 'cmi.core.score.raw',
703                                   'min' => 'cmi.core.score.min',
704                                   'max' => 'cmi.core.score.max',
705                                   'status' => 'cmi.core.lesson_status',
706                                   'time' => 'cmi.core.total_time');
707             }
708             $printedelements = array();
709             foreach ($elements as $key => $element) {
710                 if (isset($trackdata->$element)) {
711                     $existelements = true;
712                     $printedelements[]=$element;
713                     $row = array();
714                     $row[] = get_string($key,'scorm');
715                     switch($key) {
716                         case 'status':
717                             $row[] = $strstatus;
718                         break;
719                         case 'time':
720                             $row[] = s(scorm_format_date_time($trackdata->$element));
721                         break;
722                         default:
723                             s($trackdata->$element);
724                         break;
725                     }
726                     $table->data[] = $row;
727                 }
728             }
729             if ($existelements) {
730                 echo '<h3>'.get_string('general','scorm').'</h3>';
731                 echo html_writer::table($table);
732             }
734             // Print Interactions data
735             $table = new html_table();
736             $table->head = array(get_string('identifier','scorm'),
737                                  get_string('type','scorm'),
738                                  get_string('result','scorm'),
739                                  get_string('student_response','scorm'));
740             $table->align = array('center', 'center', 'center', 'center');
741             $table->wrap = array('nowrap', 'nowrap', 'nowrap', 'nowrap');
742             $table->width = '100%';
743             $table->size = array('*', '*', '*', '*', '*');
745             $existinteraction = false;
747             $i = 0;
748             $interactionid = 'cmi.interactions.'.$i.'.id';
750             while (isset($trackdata->$interactionid)) {
751                 $existinteraction = true;
752                 $printedelements[]=$interactionid;
753                 $elements = array($interactionid,
754                                   'cmi.interactions.'.$i.'.type',
755                                   'cmi.interactions.'.$i.'.result',
756                                   'cmi.interactions.'.$i.'.learner_response');
757                 $row = array();
758                 foreach ($elements as $element) {
759                     if (isset($trackdata->$element)) {
760                         $row[] = s($trackdata->$element);
761                         $printedelements[]=$element;
762                     } else {
763                         $row[] = '&nbsp;';
764                     }
765                 }
766                 $table->data[] = $row;
768                 $i++;
769                 $interactionid = 'cmi.interactions.'.$i.'.id';
770             }
771             if ($existinteraction) {
772                 echo '<h3>'.get_string('interactions','scorm').'</h3>';
773                 echo html_writer::table($table);
774             }
776             // Print Objectives data
777             $table = new html_table();
778             $table->head = array(get_string('identifier','scorm'),
779                                  get_string('status','scorm'),
780                                  get_string('raw','scorm'),
781                                  get_string('min','scorm'),
782                                  get_string('max','scorm'));
783             $table->align = array('center', 'center', 'center', 'center', 'center');
784             $table->wrap = array('nowrap', 'nowrap', 'nowrap', 'nowrap', 'nowrap');
785             $table->width = '100%';
786             $table->size = array('*', '*', '*', '*', '*');
788             $existobjective = false;
790             $i = 0;
791             $objectiveid = 'cmi.objectives.'.$i.'.id';
793             while (isset($trackdata->$objectiveid)) {
794                 $existobjective = true;
795                 $printedelements[]=$objectiveid;
796                 $elements = array($objectiveid,
797                                   'cmi.objectives.'.$i.'.status',
798                                   'cmi.objectives.'.$i.'.score.raw',
799                                   'cmi.objectives.'.$i.'.score.min',
800                                   'cmi.objectives.'.$i.'.score.max');
801                 $row = array();
802                 foreach ($elements as $element) {
803                     if (isset($trackdata->$element)) {
804                         $row[] = s($trackdata->$element);
805                         $printedelements[]=$element;
806                     } else {
807                         $row[] = '&nbsp;';
808                     }
809                 }
810                 $table->data[] = $row;
812                 $i++;
813                 $objectiveid = 'cmi.objectives.'.$i.'.id';
814             }
815             if ($existobjective) {
816                 echo '<h3>'.get_string('objectives','scorm').'</h3>';
817                 echo html_writer::table($table);
818             }
819             $table = new html_table();
820             $table->head = array(get_string('element','scorm'), get_string('value','scorm'));
821             $table->align = array('left', 'left');
822             $table->wrap = array('nowrap', 'wrap');
823             $table->width = '100%';
824             $table->size = array('*', '*');
826             $existelements = false;
828             foreach($trackdata as $element => $value) {
829                 if (substr($element,0,3) == 'cmi') {
830                     if (!(in_array ($element, $printedelements))) {
831                         $existelements = true;
832                         $row = array();
833                         $row[] = get_string($element,'scorm') != '[['.$element.']]' ? get_string($element,'scorm') : $element;
834                         if (strpos($element, '_time') === false) {
835                             $row[] = s($value);
836                         } else {
837                             $row[] = s(scorm_format_date_time($value));
838                         }
839                         $table->data[] = $row;
840                     }
841                 }
842             }
843             if ($existelements) {
844                 echo '<h3>'.get_string('othertracks','scorm').'</h3>';
845                 echo html_writer::table($table);
846             }
847             echo $OUTPUT->box_end();
848         } else {
849             print_error('missingparameter');
850         }
851     }
854     if (empty($noheader)) {
855         echo $OUTPUT->footer();
856     }