Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
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 /** 18 * Course completion progress report 19 * 20 * @package report 21 * @subpackage completion 22 * @copyright 2009 Catalyst IT Ltd 23 * @author Aaron Barnes <aaronb@catalyst.net.nz> 24 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 25 */ 26 27 use core\report_helper; 28 29 require_once(__DIR__.'/../../config.php'); 30 require_once("{$CFG->libdir}/completionlib.php"); 31 32 /** 33 * Configuration 34 */ 35 define('COMPLETION_REPORT_PAGE', 25); 36 define('COMPLETION_REPORT_COL_TITLES', true); 37 38 /* 39 * Setup page, check permissions 40 */ 41 42 // Get course 43 $courseid = required_param('course', PARAM_INT); 44 $format = optional_param('format','',PARAM_ALPHA); 45 $sort = optional_param('sort','',PARAM_ALPHA); 46 $edituser = optional_param('edituser', 0, PARAM_INT); 47 48 49 $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); 50 $context = context_course::instance($course->id); 51 52 $url = new moodle_url('/report/completion/index.php', array('course'=>$course->id)); 53 $PAGE->set_url($url); 54 $PAGE->set_pagelayout('report'); 55 56 $firstnamesort = ($sort == 'firstname'); 57 $excel = ($format == 'excelcsv'); 58 $csv = ($format == 'csv' || $excel); 59 if ($csv) { 60 $dateformat = "%F %T"; 61 } else { 62 $dateformat = get_string('strftimedatetimeshort', 'langconfig'); 63 } 64 65 // Load CSV library 66 if ($csv) { 67 require_once("{$CFG->libdir}/csvlib.class.php"); 68 } 69 70 // Paging 71 $start = optional_param('start', 0, PARAM_INT); 72 $sifirst = optional_param('sifirst', 'all', PARAM_NOTAGS); 73 $silast = optional_param('silast', 'all', PARAM_NOTAGS); 74 75 // Whether to show extra user identity information. 76 $extrafields = \core_user\fields::get_identity_fields($context, true); 77 $leftcols = 1 + count($extrafields); 78 79 // Check permissions 80 require_login($course); 81 82 require_capability('report/completion:view', $context); 83 84 // Get group mode 85 $group = groups_get_course_group($course, true); // Supposed to verify group 86 if ($group === 0 && $course->groupmode == SEPARATEGROUPS) { 87 require_capability('moodle/site:accessallgroups',$context); 88 } 89 90 /** 91 * Load data 92 */ 93 94 // Retrieve course_module data for all modules in the course 95 $modinfo = get_fast_modinfo($course); 96 97 // Get criteria for course 98 $completion = new completion_info($course); 99 100 if (!$completion->has_criteria()) { 101 throw new \moodle_exception('nocriteriaset', 'completion', $CFG->wwwroot.'/course/report.php?id='.$course->id); 102 } 103 104 // Get criteria and put in correct order 105 $criteria = array(); 106 107 foreach ($completion->get_criteria(COMPLETION_CRITERIA_TYPE_COURSE) as $criterion) { 108 $criteria[] = $criterion; 109 } 110 111 foreach ($completion->get_criteria(COMPLETION_CRITERIA_TYPE_ACTIVITY) as $criterion) { 112 $criteria[] = $criterion; 113 } 114 115 foreach ($completion->get_criteria() as $criterion) { 116 if (!in_array($criterion->criteriatype, array( 117 COMPLETION_CRITERIA_TYPE_COURSE, COMPLETION_CRITERIA_TYPE_ACTIVITY))) { 118 $criteria[] = $criterion; 119 } 120 } 121 122 // Can logged in user mark users as complete? 123 // (if the logged in user has a role defined in the role criteria) 124 $allow_marking = false; 125 $allow_marking_criteria = null; 126 127 if (!$csv) { 128 // Get role criteria 129 $rcriteria = $completion->get_criteria(COMPLETION_CRITERIA_TYPE_ROLE); 130 131 if (!empty($rcriteria)) { 132 133 foreach ($rcriteria as $rcriterion) { 134 $users = get_role_users($rcriterion->role, $context, true); 135 136 // If logged in user has this role, allow marking complete 137 if ($users && in_array($USER->id, array_keys($users))) { 138 $allow_marking = true; 139 $allow_marking_criteria = $rcriterion->id; 140 break; 141 } 142 } 143 } 144 } 145 146 /* 147 * Setup page header 148 */ 149 if ($csv) { 150 151 $shortname = format_string($course->shortname, true, array('context' => $context)); 152 $shortname = preg_replace('/[^a-z0-9-]/', '_',core_text::strtolower(strip_tags($shortname))); 153 154 $export = new csv_export_writer('comma', '"', 'application/download', $excel); 155 $export->set_filename('completion-'.$shortname); 156 157 } else { 158 // Navigation and header 159 $strcompletion = get_string('coursecompletion'); 160 161 $PAGE->set_title($strcompletion); 162 $PAGE->set_heading($course->fullname); 163 164 echo $OUTPUT->header(); 165 // Print the selected dropdown. 166 $pluginname = get_string('pluginname', 'report_completion'); 167 report_helper::print_report_selector($pluginname); 168 169 // Handle groups (if enabled) 170 groups_print_course_menu($course, $CFG->wwwroot.'/report/completion/index.php?course='.$course->id); 171 } 172 173 if ($sifirst !== 'all') { 174 set_user_preference('ifirst', $sifirst); 175 } 176 if ($silast !== 'all') { 177 set_user_preference('ilast', $silast); 178 } 179 180 if (!empty($USER->preference['ifirst'])) { 181 $sifirst = $USER->preference['ifirst']; 182 } else { 183 $sifirst = 'all'; 184 } 185 186 if (!empty($USER->preference['ilast'])) { 187 $silast = $USER->preference['ilast']; 188 } else { 189 $silast = 'all'; 190 } 191 192 // Generate where clause 193 $where = array(); 194 $where_params = array(); 195 196 if ($sifirst !== 'all') { 197 $where[] = $DB->sql_like('u.firstname', ':sifirst', false, false); 198 $where_params['sifirst'] = $sifirst.'%'; 199 } 200 201 if ($silast !== 'all') { 202 $where[] = $DB->sql_like('u.lastname', ':silast', false, false); 203 $where_params['silast'] = $silast.'%'; 204 } 205 206 // Get user match count 207 $total = $completion->get_num_tracked_users(implode(' AND ', $where), $where_params, $group); 208 209 // Total user count 210 $grandtotal = $completion->get_num_tracked_users('', array(), $group); 211 212 // If no users in this course what-so-ever 213 if (!$grandtotal) { 214 echo $OUTPUT->container(get_string('err_nousers', 'completion'), 'errorbox errorboxcontent'); 215 echo $OUTPUT->footer(); 216 exit; 217 } 218 219 // Get user data 220 $progress = array(); 221 222 if ($total) { 223 $progress = $completion->get_progress_all( 224 implode(' AND ', $where), 225 $where_params, 226 $group, 227 $firstnamesort ? 'u.firstname ASC' : 'u.lastname ASC', 228 $csv ? 0 : COMPLETION_REPORT_PAGE, 229 $csv ? 0 : $start, 230 $context 231 ); 232 } 233 234 // Build link for paging 235 $link = $CFG->wwwroot.'/report/completion/index.php?course='.$course->id; 236 if (strlen($sort)) { 237 $link .= '&sort='.$sort; 238 } 239 $link .= '&start='; 240 241 $pagingbar = ''; 242 243 // Initials bar. 244 $prefixfirst = 'sifirst'; 245 $prefixlast = 'silast'; 246 $pagingbar .= $OUTPUT->initials_bar($sifirst, 'firstinitial', get_string('firstname'), $prefixfirst, $url); 247 $pagingbar .= $OUTPUT->initials_bar($silast, 'lastinitial', get_string('lastname'), $prefixlast, $url); 248 249 // Do we need a paging bar? 250 if ($total > COMPLETION_REPORT_PAGE) { 251 252 // Paging bar 253 $pagingbar .= '<div class="paging">'; 254 $pagingbar .= get_string('page').': '; 255 256 $sistrings = array(); 257 if ($sifirst != 'all') { 258 $sistrings[] = "sifirst={$sifirst}"; 259 } 260 if ($silast != 'all') { 261 $sistrings[] = "silast={$silast}"; 262 } 263 $sistring = !empty($sistrings) ? '&'.implode('&', $sistrings) : ''; 264 265 // Display previous link 266 if ($start > 0) { 267 $pstart = max($start - COMPLETION_REPORT_PAGE, 0); 268 $pagingbar .= "(<a class=\"previous\" href=\"{$link}{$pstart}{$sistring}\">".get_string('previous').'</a>) '; 269 } 270 271 // Create page links 272 $curstart = 0; 273 $curpage = 0; 274 while ($curstart < $total) { 275 $curpage++; 276 277 if ($curstart == $start) { 278 $pagingbar .= ' '.$curpage.' '; 279 } 280 else { 281 $pagingbar .= " <a href=\"{$link}{$curstart}{$sistring}\">$curpage</a> "; 282 } 283 284 $curstart += COMPLETION_REPORT_PAGE; 285 } 286 287 // Display next link 288 $nstart = $start + COMPLETION_REPORT_PAGE; 289 if ($nstart < $total) { 290 $pagingbar .= " (<a class=\"next\" href=\"{$link}{$nstart}{$sistring}\">".get_string('next').'</a>)'; 291 } 292 293 $pagingbar .= '</div>'; 294 } 295 296 /* 297 * Draw table header 298 */ 299 300 // Start of table 301 if (!$csv) { 302 print '<br class="clearer"/>'; // ugh 303 304 $total_header = ($total == $grandtotal) ? $total : "{$total}/{$grandtotal}"; 305 echo $OUTPUT->heading(get_string('allparticipants').": {$total_header}", 3); 306 307 print $pagingbar; 308 309 if (!$total) { 310 echo $OUTPUT->heading(get_string('nothingtodisplay'), 2); 311 echo $OUTPUT->footer(); 312 exit; 313 } 314 315 print '<table id="completion-progress" class="table table-bordered generaltable flexible boxaligncenter 316 completionreport" cellpadding="5" border="1">'; 317 318 // Print criteria group names 319 print PHP_EOL.'<thead><tr style="vertical-align: top">'; 320 echo '<th scope="row" class="rowheader" colspan="' . $leftcols . '">' . 321 get_string('criteriagroup', 'completion') . '</th>'; 322 323 $current_group = false; 324 $col_count = 0; 325 for ($i = 0; $i <= count($criteria); $i++) { 326 327 if (isset($criteria[$i])) { 328 $criterion = $criteria[$i]; 329 330 if ($current_group && $criterion->criteriatype === $current_group->criteriatype) { 331 ++$col_count; 332 continue; 333 } 334 } 335 336 // Print header cell 337 if ($col_count) { 338 print '<th scope="col" colspan="'.$col_count.'" class="colheader criteriagroup">'.$current_group->get_type_title().'</th>'; 339 } 340 341 if (isset($criteria[$i])) { 342 // Move to next criteria type 343 $current_group = $criterion; 344 $col_count = 1; 345 } 346 } 347 348 // Overall course completion status 349 print '<th style="text-align: center;">'.get_string('course').'</th>'; 350 351 print '</tr>'; 352 353 // Print aggregation methods 354 print PHP_EOL.'<tr style="vertical-align: top">'; 355 echo '<th scope="row" class="rowheader" colspan="' . $leftcols . '">' . 356 get_string('aggregationmethod', 'completion').'</th>'; 357 358 $current_group = false; 359 $col_count = 0; 360 for ($i = 0; $i <= count($criteria); $i++) { 361 362 if (isset($criteria[$i])) { 363 $criterion = $criteria[$i]; 364 365 if ($current_group && $criterion->criteriatype === $current_group->criteriatype) { 366 ++$col_count; 367 continue; 368 } 369 } 370 371 // Print header cell 372 if ($col_count) { 373 $has_agg = array( 374 COMPLETION_CRITERIA_TYPE_COURSE, 375 COMPLETION_CRITERIA_TYPE_ACTIVITY, 376 COMPLETION_CRITERIA_TYPE_ROLE, 377 ); 378 379 if (in_array($current_group->criteriatype, $has_agg)) { 380 // Try load a aggregation method 381 $method = $completion->get_aggregation_method($current_group->criteriatype); 382 383 $method = $method == 1 ? get_string('all') : get_string('any'); 384 385 } else { 386 $method = '-'; 387 } 388 389 print '<th scope="col" colspan="'.$col_count.'" class="colheader aggheader">'.$method.'</th>'; 390 } 391 392 if (isset($criteria[$i])) { 393 // Move to next criteria type 394 $current_group = $criterion; 395 $col_count = 1; 396 } 397 } 398 399 // Overall course aggregation method 400 print '<th scope="col" class="colheader aggheader aggcriteriacourse">'; 401 402 // Get course aggregation 403 $method = $completion->get_aggregation_method(); 404 405 print $method == 1 ? get_string('all') : get_string('any'); 406 print '</th>'; 407 408 print '</tr>'; 409 410 // Print criteria titles 411 if (COMPLETION_REPORT_COL_TITLES) { 412 413 print PHP_EOL.'<tr>'; 414 echo '<th scope="row" class="rowheader" colspan="' . $leftcols . '">' . 415 get_string('criteria', 'completion') . '</th>'; 416 417 foreach ($criteria as $criterion) { 418 // Get criteria details 419 $details = $criterion->get_title_detailed(); 420 print '<th scope="col" class="colheader criterianame">'; 421 print '<div class="rotated-text-container"><span class="rotated-text">'.$details.'</span></div>'; 422 print '</th>'; 423 } 424 425 // Overall course completion status 426 print '<th scope="col" class="colheader criterianame">'; 427 print '<div class="rotated-text-container"><span class="rotated-text">'.get_string('coursecomplete', 'completion').'</span></div>'; 428 print '</th></tr>'; 429 } 430 431 // Print user heading and icons 432 print '<tr>'; 433 434 // User heading / sort option 435 print '<th scope="col" class="completion-sortchoice" style="clear: both;">'; 436 437 $sistring = "&silast={$silast}&sifirst={$sifirst}"; 438 439 if ($firstnamesort) { 440 print 441 get_string('firstname')." / <a href=\"./index.php?course={$course->id}{$sistring}\">". 442 get_string('lastname').'</a>'; 443 } else { 444 print "<a href=\"./index.php?course={$course->id}&sort=firstname{$sistring}\">". 445 get_string('firstname').'</a> / '. 446 get_string('lastname'); 447 } 448 print '</th>'; 449 450 // Print user identity columns 451 foreach ($extrafields as $field) { 452 echo '<th scope="col" class="completion-identifyfield">' . 453 \core_user\fields::get_display_name($field) . '</th>'; 454 } 455 456 /// 457 /// Print criteria icons 458 /// 459 foreach ($criteria as $criterion) { 460 461 // Generate icon details 462 $iconlink = ''; 463 $iconalt = ''; // Required 464 $iconattributes = array('class' => 'icon'); 465 switch ($criterion->criteriatype) { 466 467 case COMPLETION_CRITERIA_TYPE_ACTIVITY: 468 469 // Display icon 470 $iconlink = $CFG->wwwroot.'/mod/'.$criterion->module.'/view.php?id='.$criterion->moduleinstance; 471 $iconattributes['title'] = $modinfo->cms[$criterion->moduleinstance]->get_formatted_name(); 472 $iconalt = get_string('modulename', $criterion->module); 473 break; 474 475 case COMPLETION_CRITERIA_TYPE_COURSE: 476 // Load course 477 $crs = $DB->get_record('course', array('id' => $criterion->courseinstance)); 478 479 // Display icon 480 $iconlink = $CFG->wwwroot.'/course/view.php?id='.$criterion->courseinstance; 481 $iconattributes['title'] = format_string($crs->fullname, true, array('context' => context_course::instance($crs->id, MUST_EXIST))); 482 $iconalt = format_string($crs->shortname, true, array('context' => context_course::instance($crs->id))); 483 break; 484 485 case COMPLETION_CRITERIA_TYPE_ROLE: 486 // Load role 487 $role = $DB->get_record('role', array('id' => $criterion->role)); 488 489 // Display icon 490 $iconalt = $role->name; 491 break; 492 } 493 494 // Create icon alt if not supplied 495 if (!$iconalt) { 496 $iconalt = $criterion->get_title(); 497 } 498 499 // Print icon and cell 500 print '<th class="criteriaicon">'; 501 502 print ($iconlink ? '<a href="'.$iconlink.'" title="'.$iconattributes['title'].'">' : ''); 503 print $OUTPUT->render($criterion->get_icon($iconalt, $iconattributes)); 504 print ($iconlink ? '</a>' : ''); 505 506 print '</th>'; 507 } 508 509 // Overall course completion status 510 print '<th class="criteriaicon">'; 511 print $OUTPUT->pix_icon('i/course', get_string('coursecomplete', 'completion')); 512 print '</th>'; 513 514 print '</tr></thead>'; 515 516 echo '<tbody>'; 517 } else { 518 // The CSV headers 519 $row = array(); 520 521 $row[] = get_string('id', 'report_completion'); 522 $row[] = get_string('name', 'report_completion'); 523 foreach ($extrafields as $field) { 524 $row[] = \core_user\fields::get_display_name($field); 525 } 526 527 // Add activity headers 528 foreach ($criteria as $criterion) { 529 530 // Handle activity completion differently 531 if ($criterion->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) { 532 533 // Load activity 534 $mod = $criterion->get_mod_instance(); 535 $row[] = $formattedname = format_string($mod->name, true, 536 array('context' => context_module::instance($criterion->moduleinstance))); 537 $row[] = $formattedname . ' - ' . get_string('completiondate', 'report_completion'); 538 } 539 else { 540 // Handle all other criteria 541 $row[] = strip_tags($criterion->get_title_detailed()); 542 } 543 } 544 545 $row[] = get_string('coursecomplete', 'completion'); 546 547 $export->add_data($row); 548 } 549 550 /// 551 /// Display a row for each user 552 /// 553 foreach ($progress as $user) { 554 555 // User name 556 if ($csv) { 557 $row = array(); 558 $row[] = $user->id; 559 $row[] = fullname($user, has_capability('moodle/site:viewfullnames', $context)); 560 foreach ($extrafields as $field) { 561 $row[] = $user->{$field}; 562 } 563 } else { 564 print PHP_EOL.'<tr id="user-'.$user->id.'">'; 565 566 if (completion_can_view_data($user->id, $course)) { 567 $userurl = new moodle_url('/blocks/completionstatus/details.php', array('course' => $course->id, 'user' => $user->id)); 568 } else { 569 $userurl = new moodle_url('/user/view.php', array('id' => $user->id, 'course' => $course->id)); 570 } 571 572 print '<th scope="row"><a href="' . $userurl->out() . '">' . 573 fullname($user, has_capability('moodle/site:viewfullnames', $context)) . '</a></th>'; 574 foreach ($extrafields as $field) { 575 echo '<td>'.s($user->{$field}).'</td>'; 576 } 577 } 578 579 // Progress for each course completion criteria 580 foreach ($criteria as $criterion) { 581 582 $criteria_completion = $completion->get_user_completion($user->id, $criterion); 583 $is_complete = $criteria_completion->is_complete(); 584 585 // Handle activity completion differently 586 if ($criterion->criteriatype == COMPLETION_CRITERIA_TYPE_ACTIVITY) { 587 588 // Load activity 589 $activity = $modinfo->cms[$criterion->moduleinstance]; 590 591 // Get progress information and state 592 if (array_key_exists($activity->id, $user->progress)) { 593 $state = $user->progress[$activity->id]->completionstate; 594 } else if ($is_complete) { 595 $state = COMPLETION_COMPLETE; 596 } else { 597 $state = COMPLETION_INCOMPLETE; 598 } 599 if ($is_complete) { 600 $date = userdate($criteria_completion->timecompleted, $dateformat); 601 } else { 602 $date = ''; 603 } 604 605 // Work out how it corresponds to an icon 606 switch($state) { 607 case COMPLETION_INCOMPLETE : $completiontype = 'n'; break; 608 case COMPLETION_COMPLETE : $completiontype = 'y'; break; 609 case COMPLETION_COMPLETE_PASS : $completiontype = 'pass'; break; 610 case COMPLETION_COMPLETE_FAIL : $completiontype = 'fail'; break; 611 } 612 613 $auto = $activity->completion == COMPLETION_TRACKING_AUTOMATIC; 614 $completionicon = 'completion-'.($auto ? 'auto' : 'manual').'-'.$completiontype; 615 616 $describe = get_string('completion-'.$completiontype, 'completion'); 617 $a = new StdClass(); 618 $a->state = $describe; 619 $a->date = $date; 620 $a->user = fullname($user); 621 $a->activity = $activity->get_formatted_name(); 622 $fulldescribe = get_string('progress-title', 'completion', $a); 623 624 if ($csv) { 625 $row[] = $describe; 626 $row[] = $date; 627 } else { 628 print '<td class="completion-progresscell">'; 629 630 print $OUTPUT->pix_icon('i/' . $completionicon, $fulldescribe); 631 632 print '</td>'; 633 } 634 635 continue; 636 } 637 638 // Handle all other criteria 639 $completiontype = $is_complete ? 'y' : 'n'; 640 $completionicon = 'completion-auto-'.$completiontype; 641 642 $describe = get_string('completion-'.$completiontype, 'completion'); 643 644 $a = new stdClass(); 645 $a->state = $describe; 646 647 if ($is_complete) { 648 $a->date = userdate($criteria_completion->timecompleted, $dateformat); 649 } else { 650 $a->date = ''; 651 } 652 653 $a->user = fullname($user); 654 $a->activity = strip_tags($criterion->get_title()); 655 $fulldescribe = get_string('progress-title', 'completion', $a); 656 657 if ($csv) { 658 $row[] = $a->date; 659 } else { 660 661 print '<td class="completion-progresscell">'; 662 663 if ($allow_marking_criteria === $criterion->id) { 664 $describe = get_string('completion-'.$completiontype, 'completion'); 665 666 $toggleurl = new moodle_url( 667 '/course/togglecompletion.php', 668 array( 669 'user' => $user->id, 670 'course' => $course->id, 671 'rolec' => $allow_marking_criteria, 672 'sesskey' => sesskey() 673 ) 674 ); 675 676 print '<a href="'.$toggleurl->out().'" title="'.s(get_string('clicktomarkusercomplete', 'report_completion')).'">' . 677 $OUTPUT->pix_icon('i/completion-manual-' . ($is_complete ? 'y' : 'n'), $describe) . '</a></td>'; 678 } else { 679 print $OUTPUT->pix_icon('i/' . $completionicon, $fulldescribe) . '</td>'; 680 } 681 682 print '</td>'; 683 } 684 } 685 686 // Handle overall course completion 687 688 // Load course completion 689 $params = array( 690 'userid' => $user->id, 691 'course' => $course->id 692 ); 693 694 $ccompletion = new completion_completion($params); 695 $completiontype = $ccompletion->is_complete() ? 'y' : 'n'; 696 697 $describe = get_string('completion-'.$completiontype, 'completion'); 698 699 $a = new StdClass; 700 701 if ($ccompletion->is_complete()) { 702 $a->date = userdate($ccompletion->timecompleted, $dateformat); 703 } else { 704 $a->date = ''; 705 } 706 707 $a->state = $describe; 708 $a->user = fullname($user); 709 $a->activity = strip_tags(get_string('coursecomplete', 'completion')); 710 $fulldescribe = get_string('progress-title', 'completion', $a); 711 712 if ($csv) { 713 $row[] = $a->date; 714 } else { 715 716 print '<td class="completion-progresscell">'; 717 718 // Display course completion status icon 719 print $OUTPUT->pix_icon('i/completion-auto-' . $completiontype, $fulldescribe); 720 721 print '</td>'; 722 } 723 724 if ($csv) { 725 $export->add_data($row); 726 } else { 727 print '</tr>'; 728 } 729 } 730 731 if ($csv) { 732 $export->download_file(); 733 } else { 734 echo '</tbody>'; 735 } 736 737 print '</table>'; 738 739 $csvurl = new moodle_url('/report/completion/index.php', array('course' => $course->id, 'format' => 'csv')); 740 $excelurl = new moodle_url('/report/completion/index.php', array('course' => $course->id, 'format' => 'excelcsv')); 741 742 print '<ul class="export-actions">'; 743 print '<li><a href="'.$csvurl->out().'">'.get_string('csvdownload','completion').'</a></li>'; 744 print '<li><a href="'.$excelurl->out().'">'.get_string('excelcsvdownload','completion').'</a></li>'; 745 print '</ul>'; 746 747 echo $OUTPUT->footer($course); 748 749 // Trigger a report viewed event. 750 $event = \report_completion\event\report_viewed::create(array('context' => $context)); 751 $event->trigger();
title
Description
Body
title
Description
Body
title
Description
Body
title
Body