Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 1
<?php
2
// This file is part of Moodle - http://moodle.org/
3
//
4
// Moodle is free software: you can redistribute it and/or modify
5
// it under the terms of the GNU General Public License as published by
6
// the Free Software Foundation, either version 3 of the License, or
7
// (at your option) any later version.
8
//
9
// Moodle is distributed in the hope that it will be useful,
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
// GNU General Public License for more details.
13
//
14
// You should have received a copy of the GNU General Public License
15
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
16
/**
17
 * Core Report class of basic reporting plugin
18
 * @package    scormreport
19
 * @subpackage basic
20
 * @author     Dan Marsden and Ankit Kumar Agarwal
21
 * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
22
 */
23
 
24
namespace scormreport_basic;
25
 
26
defined('MOODLE_INTERNAL') || die();
27
require_once($CFG->libdir . '/csvlib.class.php');
28
 
29
class report extends \mod_scorm\report {
30
    /**
31
     * displays the full report
32
     * @param \stdClass $scorm full SCORM object
33
     * @param \stdClass $cm - full course_module object
34
     * @param \stdClass $course - full course object
35
     * @param string $download - type of download being requested
36
     */
37
    public function display($scorm, $cm, $course, $download) {
38
        global $CFG, $DB, $OUTPUT, $PAGE;
39
 
40
        $contextmodule = \context_module::instance($cm->id);
41
        $action = optional_param('action', '', PARAM_ALPHA);
42
        $attemptids = optional_param_array('attemptid', array(), PARAM_RAW);
43
        $attemptsmode = optional_param('attemptsmode', SCORM_REPORT_ATTEMPTS_ALL_STUDENTS, PARAM_INT);
44
        $PAGE->set_url(new \moodle_url($PAGE->url, array('attemptsmode' => $attemptsmode)));
45
 
46
        // Scorm action bar for report.
47
        if ($download === '') {
48
            $actionbar = new \mod_scorm\output\actionbar($cm->id, true, $attemptsmode);
49
            $renderer = $PAGE->get_renderer('mod_scorm');
50
            echo $renderer->report_actionbar($actionbar);
51
        }
52
 
53
        if ($action == 'delete' && has_capability('mod/scorm:deleteresponses', $contextmodule) && confirm_sesskey()) {
54
            if (scorm_delete_responses($attemptids, $scorm)) { // Delete responses.
55
                echo $OUTPUT->notification(get_string('scormresponsedeleted', 'scorm'), 'notifysuccess');
56
            }
57
        }
58
        // Find out current groups mode.
59
        $currentgroup = groups_get_activity_group($cm, true);
60
 
61
        // Detailed report.
62
        $mform = new \mod_scorm_report_settings($PAGE->url, compact('currentgroup'));
63
        if ($fromform = $mform->get_data()) {
64
            $detailedrep = $fromform->detailedrep;
65
            $pagesize = $fromform->pagesize;
66
            set_user_preference('scorm_report_detailed', $detailedrep);
67
            set_user_preference('scorm_report_pagesize', $pagesize);
68
        } else {
69
            $detailedrep = get_user_preferences('scorm_report_detailed', false);
70
            $pagesize = get_user_preferences('scorm_report_pagesize', 0);
71
        }
72
        if ($pagesize < 1) {
73
            $pagesize = SCORM_REPORT_DEFAULT_PAGE_SIZE;
74
        }
75
 
76
        // Select group menu.
77
        $displayoptions = array();
78
        $displayoptions['attemptsmode'] = $attemptsmode;
79
        if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used.
80
            if (!$download) {
81
                groups_print_activity_menu($cm, new \moodle_url($PAGE->url, $displayoptions));
82
            }
83
        }
84
 
85
        // We only want to show the checkbox to delete attempts
86
        // if the user has permissions and if the report mode is showing attempts.
87
        $candelete = has_capability('mod/scorm:deleteresponses', $contextmodule)
88
                        && ($attemptsmode != SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO);
89
        // Select the students.
90
        $nostudents = false;
91
        list($allowedlistsql, $params) = get_enrolled_sql($contextmodule, 'mod/scorm:savetrack', (int) $currentgroup);
92
        if (empty($currentgroup)) {
93
            // All users who can attempt scoes.
94
            if (!$DB->record_exists_sql($allowedlistsql, $params)) {
95
                echo $OUTPUT->notification(get_string('nostudentsyet'));
96
                $nostudents = true;
97
            }
98
        } else {
99
            // All users who can attempt scoes and who are in the currently selected group.
100
            if (!$DB->record_exists_sql($allowedlistsql, $params)) {
101
                echo $OUTPUT->notification(get_string('nostudentsingroup'));
102
                $nostudents = true;
103
            }
104
        }
105
 
106
        if ( !$nostudents ) {
107
            // Now check if asked download of data.
108
            $coursecontext = \context_course::instance($course->id);
109
            if ($download) {
110
                $shortname = format_string($course->shortname, true, array('context' => $coursecontext));
111
                $filename = clean_filename("$shortname ".format_string($scorm->name, true));
112
            }
113
 
114
            // Define table columns.
115
            $columns = array();
116
            $headers = array();
117
            if (!$download && $candelete) {
118
                $columns[] = 'checkbox';
119
                $headers[] = $this->generate_master_checkbox();
120
            }
121
            if (!$download && $CFG->grade_report_showuserimage) {
122
                $columns[] = 'picture';
123
                $headers[] = '';
124
            }
125
            $columns[] = 'fullname';
126
            $headers[] = get_string('name');
127
            // TODO Does not support custom user profile fields (MDL-70456).
128
            $extrafields = \core_user\fields::get_identity_fields($coursecontext, false);
129
            foreach ($extrafields as $field) {
130
                $columns[] = $field;
131
                $headers[] = \core_user\fields::get_display_name($field);
132
            }
133
 
134
            $columns[] = 'attempt';
135
            $headers[] = get_string('attempt', 'scorm');
136
            $columns[] = 'start';
137
            $headers[] = get_string('started', 'scorm');
138
            $columns[] = 'finish';
139
            $headers[] = get_string('last', 'scorm');
140
            $columns[] = 'score';
141
            $headers[] = get_string('score', 'scorm');
142
            if ($detailedrep && $scoes = $DB->get_records('scorm_scoes', array("scorm" => $scorm->id), 'sortorder, id')) {
143
                foreach ($scoes as $sco) {
144
                    if ($sco->launch != '') {
145
                        $columns[] = 'scograde'.$sco->id;
146
                        $headers[] = format_string($sco->title);
147
                    }
148
                }
149
            } else {
150
                $scoes = null;
151
            }
152
 
153
            if (!$download) {
154
                $table = new \flexible_table('mod-scorm-report');
155
 
156
                $table->define_columns($columns);
157
                $table->define_headers($headers);
158
                $table->define_baseurl($PAGE->url);
159
 
160
                $table->sortable(true);
161
                $table->collapsible(true);
162
 
163
                // This is done to prevent redundant data, when a user has multiple attempts.
164
                $table->column_suppress('picture');
165
                $table->column_suppress('fullname');
166
                foreach ($extrafields as $field) {
167
                    $table->column_suppress($field);
168
                }
169
 
170
                $table->no_sorting('start');
171
                $table->no_sorting('finish');
172
                $table->no_sorting('score');
173
                $table->no_sorting('checkbox');
174
                $table->no_sorting('picture');
175
 
176
                if ( $scoes ) {
177
                    foreach ($scoes as $sco) {
178
                        if ($sco->launch != '') {
179
                            $table->no_sorting('scograde'.$sco->id);
180
                        }
181
                    }
182
                }
183
 
184
                $table->column_class('picture', 'picture');
185
                $table->column_class('fullname', 'bold');
186
                $table->column_class('score', 'bold');
187
 
188
                $table->set_attribute('cellspacing', '0');
189
                $table->set_attribute('id', 'attempts');
190
                $table->set_attribute('class', 'generaltable generalbox');
191
 
192
                // Start working -- this is necessary as soon as the niceties are over.
193
                $table->setup();
194
            } else if ($download == 'ODS') {
195
                require_once("$CFG->libdir/odslib.class.php");
196
 
197
                $filename .= ".ods";
198
                // Creating a workbook.
199
                $workbook = new \MoodleODSWorkbook("-");
200
                // Sending HTTP headers.
201
                $workbook->send($filename);
202
                // Creating the first worksheet.
203
                $sheettitle = get_string('report', 'scorm');
204
                $myxls = $workbook->add_worksheet($sheettitle);
205
                // Format types.
206
                $format = $workbook->add_format();
207
                $format->set_bold(0);
208
                $formatbc = $workbook->add_format();
209
                $formatbc->set_bold(1);
210
                $formatbc->set_align('center');
211
                $formatb = $workbook->add_format();
212
                $formatb->set_bold(1);
213
                $formaty = $workbook->add_format();
214
                $formaty->set_bg_color('yellow');
215
                $formatc = $workbook->add_format();
216
                $formatc->set_align('center');
217
                $formatr = $workbook->add_format();
218
                $formatr->set_bold(1);
219
                $formatr->set_color('red');
220
                $formatr->set_align('center');
221
                $formatg = $workbook->add_format();
222
                $formatg->set_bold(1);
223
                $formatg->set_color('green');
224
                $formatg->set_align('center');
225
                // Here starts workshhet headers.
226
 
227
                $colnum = 0;
228
                foreach ($headers as $item) {
229
                    $myxls->write(0, $colnum, $item, $formatbc);
230
                    $colnum++;
231
                }
232
                $rownum = 1;
233
            } else if ($download == 'Excel') {
234
                require_once("$CFG->libdir/excellib.class.php");
235
 
236
                $filename .= ".xls";
237
                // Creating a workbook.
238
                $workbook = new \MoodleExcelWorkbook("-");
239
                // Sending HTTP headers.
240
                $workbook->send($filename);
241
                // Creating the first worksheet.
242
                $sheettitle = get_string('report', 'scorm');
243
                $myxls = $workbook->add_worksheet($sheettitle);
244
                // Format types.
245
                $format = $workbook->add_format();
246
                $format->set_bold(0);
247
                $formatbc = $workbook->add_format();
248
                $formatbc->set_bold(1);
249
                $formatbc->set_align('center');
250
                $formatb = $workbook->add_format();
251
                $formatb->set_bold(1);
252
                $formaty = $workbook->add_format();
253
                $formaty->set_bg_color('yellow');
254
                $formatc = $workbook->add_format();
255
                $formatc->set_align('center');
256
                $formatr = $workbook->add_format();
257
                $formatr->set_bold(1);
258
                $formatr->set_color('red');
259
                $formatr->set_align('center');
260
                $formatg = $workbook->add_format();
261
                $formatg->set_bold(1);
262
                $formatg->set_color('green');
263
                $formatg->set_align('center');
264
 
265
                $colnum = 0;
266
                foreach ($headers as $item) {
267
                    $myxls->write(0, $colnum, $item, $formatbc);
268
                    $colnum++;
269
                }
270
                $rownum = 1;
271
            } else if ($download == 'CSV') {
272
                $csvexport = new \csv_export_writer("tab");
273
                $csvexport->set_filename($filename, ".txt");
274
                $csvexport->add_data($headers);
275
            }
276
            // Construct the SQL.
277
            $select = 'SELECT DISTINCT '.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(sa.attempt, 0)').' AS uniqueid, ';
278
            // TODO Does not support custom user profile fields (MDL-70456).
279
            $userfields = \core_user\fields::for_identity($coursecontext, false)->with_userpic()->including('idnumber');
280
            $selectfields = $userfields->get_sql('u', false, '', 'userid')->selects;
281
            $select .= 'sa.scormid AS scormid, sa.attempt AS attempt ' . $selectfields . ' ';
282
 
283
            // This part is the same for all cases - join users and user tracking tables.
284
            $from = 'FROM {user} u ';
285
            $from .= 'LEFT JOIN {scorm_attempt} sa ON sa.userid = u.id AND sa.scormid = '.$scorm->id;
286
            switch ($attemptsmode) {
287
                case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH:
288
                    // Show only students with attempts.
289
                    $where = " WHERE u.id IN ({$allowedlistsql}) AND sa.userid IS NOT NULL";
290
                    break;
291
                case SCORM_REPORT_ATTEMPTS_STUDENTS_WITH_NO:
292
                    // Show only students without attempts.
293
                    $where = " WHERE u.id IN ({$allowedlistsql}) AND sa.userid IS NULL";
294
                    break;
295
                case SCORM_REPORT_ATTEMPTS_ALL_STUDENTS:
296
                    // Show all students with or without attempts.
297
                    $where = " WHERE u.id IN ({$allowedlistsql}) AND (sa.userid IS NOT NULL OR sa.userid IS NULL)";
298
                    break;
299
            }
300
 
301
            $countsql = 'SELECT COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'COALESCE(sa.attempt, 0)').')) AS nbresults, ';
302
            $countsql .= 'COUNT(DISTINCT('.$DB->sql_concat('u.id', '\'#\'', 'sa.attempt').')) AS nbattempts, ';
303
            $countsql .= 'COUNT(DISTINCT(u.id)) AS nbusers ';
304
            $countsql .= $from.$where;
305
 
306
            if (!$download) {
307
                $sort = $table->get_sql_sort();
308
            } else {
309
                $sort = '';
310
            }
311
            // Fix some wired sorting.
312
            if (empty($sort)) {
313
                $sort = ' ORDER BY uniqueid';
314
            } else {
315
                $sort = ' ORDER BY '.$sort;
316
            }
317
 
318
            if (!$download) {
319
                // Add extra limits due to initials bar.
320
                list($twhere, $tparams) = $table->get_sql_where();
321
                if ($twhere) {
322
                    $where .= ' AND '.$twhere; // Initial bar.
323
                    $params = array_merge($params, $tparams);
324
                }
325
 
326
                if (!empty($countsql)) {
327
                    $count = $DB->get_record_sql($countsql, $params);
328
                    $totalinitials = $count->nbresults;
329
                    if ($twhere) {
330
                        $countsql .= ' AND '.$twhere;
331
                    }
332
                    $count = $DB->get_record_sql($countsql, $params);
333
                    $total  = $count->nbresults;
334
                }
335
 
336
                $table->pagesize($pagesize, $total);
337
 
338
                echo \html_writer::start_div('scormattemptcounts');
339
                if ( $count->nbresults == $count->nbattempts ) {
340
                    echo get_string('reportcountattempts', 'scorm', $count);
341
                } else if ( $count->nbattempts > 0 ) {
342
                    echo get_string('reportcountallattempts', 'scorm', $count);
343
                } else {
344
                    echo $count->nbusers.' '.get_string('users');
345
                }
346
                echo \html_writer::end_div();
347
            }
348
 
349
            // Fetch the attempts.
350
            if (!$download) {
351
                $attempts = $DB->get_records_sql($select.$from.$where.$sort, $params,
352
                $table->get_page_start(), $table->get_page_size());
353
                echo \html_writer::start_div('', array('id' => 'scormtablecontainer'));
354
                if ($candelete) {
355
                    // Start form.
356
                    $strreallydel  = addslashes_js(get_string('deleteattemptcheck', 'scorm'));
357
                    echo \html_writer::start_tag('form', array('id' => 'attemptsform', 'method' => 'post',
358
                                                                'action' => $PAGE->url->out(false),
359
                                                                'onsubmit' => 'return confirm("'.$strreallydel.'");'));
360
                    echo \html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'delete'));
361
                    echo \html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
362
                    echo \html_writer::start_div('', array('style' => 'display: none;'));
363
                    echo \html_writer::input_hidden_params($PAGE->url);
364
                    echo \html_writer::end_div();
365
                    echo \html_writer::start_div();
366
                }
367
                $table->initialbars($totalinitials > 20); // Build table rows.
368
            } else {
369
                $attempts = $DB->get_records_sql($select.$from.$where.$sort, $params);
370
            }
371
 
372
            if ($attempts) {
373
                foreach ($attempts as $scouser) {
374
                    $row = array();
375
                    if (!empty($scouser->attempt)) {
376
                        $timetracks = scorm_get_sco_runtime($scorm->id, false, $scouser->userid, $scouser->attempt);
377
                    } else {
378
                        $timetracks = '';
379
                    }
380
                    if (in_array('checkbox', $columns)) {
381
                        if ($candelete && !empty($timetracks->start)) {
382
                            $row[] = $this->generate_row_checkbox('attemptid[]', "{$scouser->userid}:{$scouser->attempt}");
383
                        } else if ($candelete) {
384
                            $row[] = '';
385
                        }
386
                    }
387
                    if (in_array('picture', $columns)) {
388
                        $user = new \stdClass();
389
                        $additionalfields = explode(',', implode(',', \core_user\fields::get_picture_fields()));
390
                        $user = username_load_fields_from_object($user, $scouser, null, $additionalfields);
391
                        $user->id = $scouser->userid;
392
                        $row[] = $OUTPUT->user_picture($user, array('courseid' => $course->id));
393
                    }
394
                    if (!$download) {
395
                        $url = new \moodle_url('/user/view.php', array('id' => $scouser->userid, 'course' => $course->id));
396
                        $row[] = \html_writer::link($url, fullname($scouser));
397
                    } else {
398
                        $row[] = fullname($scouser);
399
                    }
400
                    foreach ($extrafields as $field) {
401
                        $row[] = s($scouser->{$field});
402
                    }
403
                    if (empty($timetracks->start)) {
404
                        $row[] = '-';
405
                        $row[] = '-';
406
                        $row[] = '-';
407
                        $row[] = '-';
408
                    } else {
409
                        if (!$download) {
410
                            $url = new \moodle_url('/mod/scorm/report/userreport.php', array('id' => $cm->id,
411
                                'user' => $scouser->userid, 'attempt' => $scouser->attempt, 'mode' => 'basic'));
412
                            $row[] = \html_writer::link($url, $scouser->attempt);
413
                        } else {
414
                            $row[] = $scouser->attempt;
415
                        }
416
                        if ($download == 'ODS' || $download == 'Excel' ) {
417
                            $row[] = userdate($timetracks->start, get_string("strftimedatetime", "langconfig"));
418
                        } else {
419
                            $row[] = userdate($timetracks->start);
420
                        }
421
                        if ($download == 'ODS' || $download == 'Excel' ) {
422
                            $row[] = userdate($timetracks->finish, get_string('strftimedatetime', 'langconfig'));
423
                        } else {
424
                            $row[] = userdate($timetracks->finish);
425
                        }
426
                        $row[] = scorm_grade_user_attempt($scorm, $scouser->userid, $scouser->attempt);
427
                    }
428
                    // Print out all scores of attempt.
429
                    if ($scoes) {
430
                        foreach ($scoes as $sco) {
431
                            if ($sco->launch != '') {
432
                                if ($trackdata = scorm_get_tracks($sco->id, $scouser->userid, $scouser->attempt)) {
433
                                    if ($trackdata->status == '') {
434
                                        $trackdata->status = 'notattempted';
435
                                    }
436
                                    $strstatus = get_string($trackdata->status, 'scorm');
437
                                    // If raw score exists, print it.
438
                                    if ($trackdata->score_raw != '') {
439
                                        $score = $trackdata->score_raw;
440
                                        // Add max score if it exists.
441
                                        if (scorm_version_check($scorm->version, SCORM_13)) {
442
                                            $maxkey = 'cmi.score.max';
443
                                        } else {
444
                                            $maxkey = 'cmi.core.score.max';
445
                                        }
446
                                        if (isset($trackdata->$maxkey)) {
447
                                            $score .= '/'.$trackdata->$maxkey;
448
                                        }
449
                                        // Else print out status.
450
                                    } else {
451
                                        $score = $strstatus;
452
                                    }
453
                                    if (!$download) {
454
                                        $url = new \moodle_url('/mod/scorm/report/userreporttracks.php', array('id' => $cm->id,
455
                                            'scoid' => $sco->id, 'user' => $scouser->userid, 'attempt' => $scouser->attempt,
456
                                            'mode' => 'basic'));
457
                                        $row[] = $OUTPUT->pix_icon($trackdata->status, $strstatus, 'scorm') . '<br>' .
458
                                           \html_writer::link($url, $score, array('title' => get_string('details', 'scorm')));
459
                                    } else {
460
                                        $row[] = $score;
461
                                    }
462
                                } else {
463
                                    // If we don't have track data, we haven't attempted yet.
464
                                    $strstatus = get_string('notattempted', 'scorm');
465
                                    if (!$download) {
466
                                        $row[] = $OUTPUT->pix_icon('notattempted', $strstatus, 'scorm') . '<br>' . $strstatus;
467
                                    } else {
468
                                        $row[] = $strstatus;
469
                                    }
470
                                }
471
                            }
472
                        }
473
                    }
474
 
475
                    if (!$download) {
476
                        $table->add_data($row);
477
                    } else if ($download == 'Excel' or $download == 'ODS') {
478
                        $colnum = 0;
479
                        foreach ($row as $item) {
480
                            $myxls->write($rownum, $colnum, $item, $format);
481
                            $colnum++;
482
                        }
483
                        $rownum++;
484
                    } else if ($download == 'CSV') {
485
                        $csvexport->add_data($row);
486
                    }
487
                }
488
                if (!$download) {
489
                    $table->finish_output();
490
                    if ($candelete) {
491
                        echo \html_writer::start_tag('table', array('id' => 'commands'));
492
                        echo \html_writer::start_tag('tr').\html_writer::start_tag('td');
493
                        echo $this->generate_delete_selected_button();
494
                        echo \html_writer::end_tag('td').\html_writer::end_tag('tr').\html_writer::end_tag('table');
495
                        // Close form.
496
                        echo \html_writer::end_tag('div');
497
                        echo \html_writer::end_tag('form');
498
                    }
499
                }
500
            } else {
501
                if ($candelete && !$download) {
502
                    echo \html_writer::end_div();
503
                    echo \html_writer::end_tag('form');
504
                    $table->finish_output();
505
                }
506
                echo \html_writer::end_div();
507
            }
508
            // Show preferences form irrespective of attempts are there to report or not.
509
            if (!$download) {
510
                $mform->set_data(compact('detailedrep', 'pagesize', 'attemptsmode'));
511
                $mform->display();
512
            }
513
            if ($download == 'Excel' or $download == 'ODS') {
514
                $workbook->close();
515
                exit;
516
            } else if ($download == 'CSV') {
517
                $csvexport->download_file();
518
                exit;
519
            }
520
        } else {
521
            echo $OUTPUT->notification(get_string('noactivity', 'scorm'));
522
        }
523
    }// Function ends.
524
}