|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00026 require('../../config.php'); 00027 require_once($CFG->libdir . '/completionlib.php'); 00028 00029 define('COMPLETION_REPORT_PAGE', 25); 00030 00031 // Get course 00032 $id = required_param('course',PARAM_INT); 00033 $course = $DB->get_record('course',array('id'=>$id)); 00034 if (!$course) { 00035 print_error('invalidcourseid'); 00036 } 00037 $context = context_course::instance($course->id); 00038 00039 // Sort (default lastname, optionally firstname) 00040 $sort = optional_param('sort','',PARAM_ALPHA); 00041 $firstnamesort = $sort == 'firstname'; 00042 00043 // CSV format 00044 $format = optional_param('format','',PARAM_ALPHA); 00045 $excel = $format == 'excelcsv'; 00046 $csv = $format == 'csv' || $excel; 00047 00048 // Paging 00049 $start = optional_param('start', 0, PARAM_INT); 00050 $sifirst = optional_param('sifirst', 'all', PARAM_ALPHA); 00051 $silast = optional_param('silast', 'all', PARAM_ALPHA); 00052 $start = optional_param('start', 0, PARAM_INT); 00053 00054 // Whether to show extra user identity information 00055 $extrafields = get_extra_user_fields($context); 00056 $leftcols = 1 + count($extrafields); 00057 00058 function csv_quote($value) { 00059 global $excel; 00060 if ($excel) { 00061 $tl = textlib_get_instance(); 00062 return $tl->convert('"'.str_replace('"',"'",$value).'"','UTF-8','UTF-16LE'); 00063 } else { 00064 return '"'.str_replace('"',"'",$value).'"'; 00065 } 00066 } 00067 00068 $url = new moodle_url('/report/progress/index.php', array('course'=>$id)); 00069 if ($sort !== '') { 00070 $url->param('sort', $sort); 00071 } 00072 if ($format !== '') { 00073 $url->param('format', $format); 00074 } 00075 if ($start !== 0) { 00076 $url->param('start', $start); 00077 } 00078 $PAGE->set_url($url); 00079 $PAGE->set_pagelayout('report'); 00080 00081 require_login($course); 00082 00083 // Check basic permission 00084 require_capability('report/progress:view',$context); 00085 00086 // Get group mode 00087 $group = groups_get_course_group($course,true); // Supposed to verify group 00088 if ($group===0 && $course->groupmode==SEPARATEGROUPS) { 00089 require_capability('moodle/site:accessallgroups',$context); 00090 } 00091 00092 // Get data on activities and progress of all users, and give error if we've 00093 // nothing to display (no users or no activities) 00094 $reportsurl = $CFG->wwwroot.'/course/report.php?id='.$course->id; 00095 $completion = new completion_info($course); 00096 $activities = $completion->get_activities(); 00097 00098 // Generate where clause 00099 $where = array(); 00100 $where_params = array(); 00101 00102 if ($sifirst !== 'all') { 00103 $where[] = $DB->sql_like('u.firstname', ':sifirst', false); 00104 $where_params['sifirst'] = $sifirst.'%'; 00105 } 00106 00107 if ($silast !== 'all') { 00108 $where[] = $DB->sql_like('u.lastname', ':silast', false); 00109 $where_params['silast'] = $silast.'%'; 00110 } 00111 00112 // Get user match count 00113 $total = $completion->get_num_tracked_users(implode(' AND ', $where), $where_params, $group); 00114 00115 // Total user count 00116 $grandtotal = $completion->get_num_tracked_users('', array(), $group); 00117 00118 // Get user data 00119 $progress = array(); 00120 00121 if ($total) { 00122 $progress = $completion->get_progress_all( 00123 implode(' AND ', $where), 00124 $where_params, 00125 $group, 00126 $firstnamesort ? 'u.firstname ASC' : 'u.lastname ASC', 00127 $csv ? 0 : COMPLETION_REPORT_PAGE, 00128 $csv ? 0 : $start, 00129 $context 00130 ); 00131 } 00132 00133 if ($csv && $grandtotal && count($activities)>0) { // Only show CSV if there are some users/actvs 00134 00135 $shortname = format_string($course->shortname, true, array('context' => $context)); 00136 $textlib = textlib_get_instance(); 00137 header('Content-Disposition: attachment; filename=progress.'. 00138 preg_replace('/[^a-z0-9-]/','_',$textlib->strtolower(strip_tags($shortname))).'.csv'); 00139 // Unicode byte-order mark for Excel 00140 if ($excel) { 00141 header('Content-Type: text/csv; charset=UTF-16LE'); 00142 print chr(0xFF).chr(0xFE); 00143 $sep="\t".chr(0); 00144 $line="\n".chr(0); 00145 } else { 00146 header('Content-Type: text/csv; charset=UTF-8'); 00147 $sep=","; 00148 $line="\n"; 00149 } 00150 } else { 00151 // Use SVG to draw sideways text if supported 00152 $svgcleverness = can_use_rotated_text(); 00153 00154 // Navigation and header 00155 $strreports = get_string("reports"); 00156 $strcompletion = get_string('activitycompletion', 'completion'); 00157 00158 $PAGE->set_title($strcompletion); 00159 $PAGE->set_heading($course->fullname); 00160 echo $OUTPUT->header(); 00161 00162 if ($svgcleverness) { 00163 $PAGE->requires->yui2_lib('event'); 00164 $PAGE->requires->js('/report/progress/textrotate.js'); 00165 } 00166 00167 // Handle groups (if enabled) 00168 groups_print_course_menu($course,$CFG->wwwroot.'/report/progress/?course='.$course->id); 00169 } 00170 00171 if (count($activities)==0) { 00172 echo $OUTPUT->container(get_string('err_noactivities', 'completion'), 'errorbox errorboxcontent'); 00173 echo $OUTPUT->footer(); 00174 exit; 00175 } 00176 00177 // If no users in this course what-so-ever 00178 if (!$grandtotal) { 00179 echo $OUTPUT->container(get_string('err_nousers', 'completion'), 'errorbox errorboxcontent'); 00180 echo $OUTPUT->footer(); 00181 exit; 00182 } 00183 00184 // Build link for paging 00185 $link = $CFG->wwwroot.'/report/progress/?course='.$course->id; 00186 if (strlen($sort)) { 00187 $link .= '&sort='.$sort; 00188 } 00189 $link .= '&start='; 00190 00191 // Build the the page by Initial bar 00192 $initials = array('first', 'last'); 00193 $alphabet = explode(',', get_string('alphabet', 'langconfig')); 00194 00195 $pagingbar = ''; 00196 foreach ($initials as $initial) { 00197 $var = 'si'.$initial; 00198 00199 $othervar = $initial == 'first' ? 'silast' : 'sifirst'; 00200 $othervar = $$othervar != 'all' ? "&{$othervar}={$$othervar}" : ''; 00201 00202 $pagingbar .= ' <div class="initialbar '.$initial.'initial">'; 00203 $pagingbar .= get_string($initial.'name').': '; 00204 00205 if ($$var == 'all') { 00206 $pagingbar .= '<strong>'.get_string('all').'</strong> '; 00207 } 00208 else { 00209 $pagingbar .= "<a href=\"{$link}{$othervar}\">".get_string('all').'</a> '; 00210 } 00211 00212 foreach ($alphabet as $letter) { 00213 if ($$var === $letter) { 00214 $pagingbar .= '<strong>'.$letter.'</strong> '; 00215 } 00216 else { 00217 $pagingbar .= "<a href=\"$link&$var={$letter}{$othervar}\">$letter</a> "; 00218 } 00219 } 00220 00221 $pagingbar .= '</div>'; 00222 } 00223 00224 // Do we need a paging bar? 00225 if ($total > COMPLETION_REPORT_PAGE) { 00226 00227 // Paging bar 00228 $pagingbar .= '<div class="paging">'; 00229 $pagingbar .= get_string('page').': '; 00230 00231 $sistrings = array(); 00232 if ($sifirst != 'all') { 00233 $sistrings[] = "sifirst={$sifirst}"; 00234 } 00235 if ($silast != 'all') { 00236 $sistrings[] = "silast={$silast}"; 00237 } 00238 $sistring = !empty($sistrings) ? '&'.implode('&', $sistrings) : ''; 00239 00240 // Display previous link 00241 if ($start > 0) { 00242 $pstart = max($start - COMPLETION_REPORT_PAGE, 0); 00243 $pagingbar .= "(<a class=\"previous\" href=\"{$link}{$pstart}{$sistring}\">".get_string('previous').'</a>) '; 00244 } 00245 00246 // Create page links 00247 $curstart = 0; 00248 $curpage = 0; 00249 while ($curstart < $total) { 00250 $curpage++; 00251 00252 if ($curstart == $start) { 00253 $pagingbar .= ' '.$curpage.' '; 00254 } else { 00255 $pagingbar .= " <a href=\"{$link}{$curstart}{$sistring}\">$curpage</a> "; 00256 } 00257 00258 $curstart += COMPLETION_REPORT_PAGE; 00259 } 00260 00261 // Display next link 00262 $nstart = $start + COMPLETION_REPORT_PAGE; 00263 if ($nstart < $total) { 00264 $pagingbar .= " (<a class=\"next\" href=\"{$link}{$nstart}{$sistring}\">".get_string('next').'</a>)'; 00265 } 00266 00267 $pagingbar .= '</div>'; 00268 } 00269 00270 // Okay, let's draw the table of progress info, 00271 00272 // Start of table 00273 if (!$csv) { 00274 print '<br class="clearer"/>'; // ugh 00275 00276 print $pagingbar; 00277 00278 if (!$total) { 00279 echo $OUTPUT->heading(get_string('nothingtodisplay')); 00280 echo $OUTPUT->footer(); 00281 exit; 00282 } 00283 00284 print '<table id="completion-progress" class="generaltable flexible boxaligncenter" style="text-align:left"><tr style="vertical-align:top">'; 00285 00286 // User heading / sort option 00287 print '<th scope="col" class="completion-sortchoice">'; 00288 00289 $sistring = "&silast={$silast}&sifirst={$sifirst}"; 00290 00291 if ($firstnamesort) { 00292 print 00293 get_string('firstname')." / <a href=\"./?course={$course->id}{$sistring}\">". 00294 get_string('lastname').'</a>'; 00295 } else { 00296 print "<a href=\"./?course={$course->id}&sort=firstname{$sistring}\">". 00297 get_string('firstname').'</a> / '. 00298 get_string('lastname'); 00299 } 00300 print '</th>'; 00301 00302 // Print user identity columns 00303 foreach ($extrafields as $field) { 00304 echo '<th scope="col" class="completion-identifyfield">' . 00305 get_user_field_name($field) . '</th>'; 00306 } 00307 } else { 00308 foreach ($extrafields as $field) { 00309 echo $sep . csv_quote(get_user_field_name($field)); 00310 } 00311 } 00312 00313 // Activities 00314 foreach($activities as $activity) { 00315 $activity->datepassed = $activity->completionexpected && $activity->completionexpected <= time(); 00316 $activity->datepassedclass=$activity->datepassed ? 'completion-expired' : ''; 00317 00318 if ($activity->completionexpected) { 00319 $datetext=userdate($activity->completionexpected,get_string('strftimedate','langconfig')); 00320 } else { 00321 $datetext=''; 00322 } 00323 00324 // Some names (labels) come URL-encoded and can be very long, so shorten them 00325 $activity->name = shorten_text($activity->name); 00326 00327 if ($csv) { 00328 print $sep.csv_quote(strip_tags($activity->name)).$sep.csv_quote($datetext); 00329 } else { 00330 print '<th scope="col" class="'.$activity->datepassedclass.'">'. 00331 '<a href="'.$CFG->wwwroot.'/mod/'.$activity->modname. 00332 '/view.php?id='.$activity->id.'">'. 00333 '<img src="'.$OUTPUT->pix_url('icon', $activity->modname).'" alt="'. 00334 get_string('modulename',$activity->modname).'" /> <span class="completion-activityname">'. 00335 format_string($activity->name).'</span></a>'; 00336 if ($activity->completionexpected) { 00337 print '<div class="completion-expected"><span>'.$datetext.'</span></div>'; 00338 } 00339 print '</th>'; 00340 } 00341 } 00342 00343 if ($csv) { 00344 print $line; 00345 } else { 00346 print '</tr>'; 00347 } 00348 00349 // Row for each user 00350 foreach($progress as $user) { 00351 // User name 00352 if ($csv) { 00353 print csv_quote(fullname($user)); 00354 foreach ($extrafields as $field) { 00355 echo $sep . csv_quote($user->{$field}); 00356 } 00357 } else { 00358 print '<tr><th scope="row"><a href="'.$CFG->wwwroot.'/user/view.php?id='. 00359 $user->id.'&course='.$course->id.'">'.fullname($user).'</a></th>'; 00360 foreach ($extrafields as $field) { 00361 echo '<td>' . s($user->{$field}) . '</td>'; 00362 } 00363 } 00364 00365 // Progress for each activity 00366 foreach($activities as $activity) { 00367 00368 // Get progress information and state 00369 if (array_key_exists($activity->id,$user->progress)) { 00370 $thisprogress=$user->progress[$activity->id]; 00371 $state=$thisprogress->completionstate; 00372 $date=userdate($thisprogress->timemodified); 00373 } else { 00374 $state=COMPLETION_INCOMPLETE; 00375 $date=''; 00376 } 00377 00378 // Work out how it corresponds to an icon 00379 switch($state) { 00380 case COMPLETION_INCOMPLETE : $completiontype='n'; break; 00381 case COMPLETION_COMPLETE : $completiontype='y'; break; 00382 case COMPLETION_COMPLETE_PASS : $completiontype='pass'; break; 00383 case COMPLETION_COMPLETE_FAIL : $completiontype='fail'; break; 00384 } 00385 00386 $completionicon='completion-'. 00387 ($activity->completion==COMPLETION_TRACKING_AUTOMATIC ? 'auto' : 'manual'). 00388 '-'.$completiontype; 00389 00390 $describe=get_string('completion-alt-auto-'.$completiontype,'completion'); 00391 $a=new StdClass; 00392 $a->state=$describe; 00393 $a->date=$date; 00394 $a->user=fullname($user); 00395 $a->activity=strip_tags($activity->name); 00396 $fulldescribe=get_string('progress-title','completion',$a); 00397 00398 if ($csv) { 00399 print $sep.csv_quote($describe).$sep.csv_quote($date); 00400 } else { 00401 print '<td class="completion-progresscell '.$activity->datepassedclass.'">'. 00402 '<img src="'.$OUTPUT->pix_url('i/'.$completionicon). 00403 '" alt="'.$describe.'" title="'.$fulldescribe.'" /></td>'; 00404 } 00405 } 00406 00407 if ($csv) { 00408 print $line; 00409 } else { 00410 print '</tr>'; 00411 } 00412 } 00413 00414 if ($csv) { 00415 exit; 00416 } 00417 print '</table>'; 00418 print $pagingbar; 00419 00420 print '<ul class="progress-actions"><li><a href="index.php?course='.$course->id. 00421 '&format=csv">'.get_string('csvdownload','completion').'</a></li> 00422 <li><a href="index.php?course='.$course->id.'&format=excelcsv">'. 00423 get_string('excelcsvdownload','completion').'</a></li></ul>'; 00424 00425 echo $OUTPUT->footer(); 00426