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