quiz editing: MDL-18173 tidy up wording and add cursor: help.
[moodle.git] / grade / report / user / lib.php
CommitLineData
f7998fbc 1<?php // $Id$
8ad36f4c 2
3///////////////////////////////////////////////////////////////////////////
4// //
5// NOTICE OF COPYRIGHT //
6// //
7// Moodle - Modular Object-Oriented Dynamic Learning Environment //
8// http://moodle.com //
9// //
10// Copyright (C) 1999 onwards Martin Dougiamas http://moodle.com //
11// //
12// This program is free software; you can redistribute it and/or modify //
13// it under the terms of the GNU General Public License as published by //
14// the Free Software Foundation; either version 2 of the License, or //
15// (at your option) any later version. //
16// //
17// This program is distributed in the hope that it will be useful, //
18// but WITHOUT ANY WARRANTY; without even the implied warranty of //
19// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the //
20// GNU General Public License for more details: //
21// //
22// http://www.gnu.org/copyleft/gpl.html //
23// //
24///////////////////////////////////////////////////////////////////////////
f7998fbc 25/**
26 * File in which the user_report class is defined.
27 * @package gradebook
28 */
29
30require_once($CFG->dirroot . '/grade/report/lib.php');
31require_once($CFG->libdir.'/tablelib.php');
32
33/**
34 * Class providing an API for the user report building and displaying.
35 * @uses grade_report
36 * @package gradebook
37 */
38class grade_report_user extends grade_report {
39
40 /**
41 * The user.
42 * @var object $user
43 */
5c75a0a3 44 public $user;
f7998fbc 45
46 /**
47 * A flexitable to hold the data.
48 * @var object $table
49 */
5c75a0a3 50 public $table;
f7998fbc 51
e0724506 52 /**
53 * Flat structure similar to grade tree
54 */
5c75a0a3 55 public $gseq;
e0724506 56
26ed0305 57 /**
58 * show student ranks
59 */
5c75a0a3 60 public $showrank;
26ed0305 61
699da6b5 62 /**
63 * show grade percentages
64 */
65 public $showpercentage;
66
26ed0305 67 /**
68 * Show hidden items even when user does not have required cap
69 */
5c75a0a3 70 public $showhiddenitems;
26ed0305 71
f7998fbc 72 /**
73 * Constructor. Sets local copies of user preferences and initialises grade_tree.
74 * @param int $courseid
d30c4481 75 * @param object $gpr grade plugin return tracking object
f7998fbc 76 * @param string $context
77 * @param int $userid The id of the user
78 */
5c75a0a3 79 public function __construct($courseid, $gpr, $context, $userid) {
80 global $CFG, $DB;
81 parent::__construct($courseid, $gpr, $context);
f7998fbc 82
597f50e6 83 $this->showrank = grade_get_setting($this->courseid, 'report_user_showrank', $CFG->grade_report_user_showrank);
699da6b5 84 $this->showpercentage = grade_get_setting($this->courseid, 'report_user_showpercentage', $CFG->grade_report_user_showpercentage);
597f50e6 85 $this->showhiddenitems = grade_get_setting($this->courseid, 'report_user_showhiddenitems', $CFG->grade_report_user_showhiddenitems);
26ed0305 86
e0724506 87 $switch = grade_get_setting($this->courseid, 'aggregationposition', $CFG->grade_aggregationposition);
88
d1214909 89 // Grab the grade_seq for this course
e0724506 90 $this->gseq = new grade_seq($this->courseid, $switch);
4faf5f99 91
f7998fbc 92 // get the user (for full name)
5c75a0a3 93 $this->user = $DB->get_record('user', array('id' => $userid));
f7998fbc 94
95 // base url for sorting by first/last name
96 $this->baseurl = $CFG->wwwroot.'/grade/report?id='.$courseid.'&amp;userid='.$userid;
90d3960c 97 $this->pbarurl = $this->baseurl;
f7998fbc 98
d1214909 99 // no groups on this report - rank is from all course users
90d3960c 100 $this->setup_table();
f7998fbc 101 }
102
103 /**
104 * Prepares the headers and attributes of the flexitable.
105 */
5c75a0a3 106 public function setup_table() {
02973505 107 global $CFG;
f7998fbc 108 /*
d1214909 109 * Table has 5-6 columns
110 *| itemname/description | final grade | percentage final grade | rank (optional) | feedback |
111 */
f7998fbc 112
113 // setting up table headers
699da6b5 114 $tablecolumns = array('itemname', 'category', 'grade');
115 $tableheaders = array($this->get_lang_string('gradeitem', 'grades'),
116 $this->get_lang_string('category'),
117 $this->get_lang_string('grade'));
118
119 if ($this->showpercentage) {
120 $tablecolumns[] = 'percentage';
121 $tableheaders[] = $this->get_lang_string('percentage', 'grades');
122 }
123
26ed0305 124 if ($this->showrank) {
02973505 125 // TODO: this is broken if hidden grades present!!
699da6b5 126 $tablecolumns[] = 'rank';
bba9b20e 127 $tableheaders[] = $this->get_lang_string('rank', 'grades');
02973505 128 }
f7998fbc 129
699da6b5 130 $tablecolumns[] = 'feedback';
bba9b20e 131 $tableheaders[] = $this->get_lang_string('feedback', 'grades');
699da6b5 132
f7998fbc 133 $this->table = new flexible_table('grade-report-user-'.$this->courseid);
134
135 $this->table->define_columns($tablecolumns);
136 $this->table->define_headers($tableheaders);
137 $this->table->define_baseurl($this->baseurl);
138
139 $this->table->set_attribute('cellspacing', '0');
5c75a0a3 140 $this->table->set_attribute('class', 'user-grades boxaligncenter generaltable');
f7998fbc 141
cd52d909 142 // not sure tables should be sortable or not, because if we allow it then sorted results distort grade category structure and sortorder
f7998fbc 143 $this->table->set_control_variables(array(
144 TABLE_VAR_SORT => 'ssort',
145 TABLE_VAR_HIDE => 'shide',
146 TABLE_VAR_SHOW => 'sshow',
147 TABLE_VAR_IFIRST => 'sifirst',
148 TABLE_VAR_ILAST => 'silast',
149 TABLE_VAR_PAGE => 'spage'
150 ));
151
152 $this->table->setup();
153 }
154
5c75a0a3 155 public function fill_table() {
ea1e551d 156 global $CFG, $DB;
6ef84f6f 157 $numusers = $this->get_numusers(false); // total course users
6391ebe7 158 $items =& $this->gseq->items;
159 $grades = array();
f7998fbc 160
b89a70ce 161 $canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $this->courseid));
f7998fbc 162
4c8893ed 163 // fetch or create all grades
6391ebe7 164 foreach ($items as $key=>$unused) {
4c8893ed 165 if (!$grade_grade = grade_grade::fetch(array('itemid'=>$items[$key]->id, 'userid'=>$this->user->id))) {
166 $grade_grade = new grade_grade();
167 $grade_grade->userid = $this->user->id;
168 $grade_grade->itemid = $items[$key]->id;
169 }
6391ebe7 170 $grades[$key] = $grade_grade;
4c8893ed 171 $grades[$key]->grade_item =& $items[$key];
6391ebe7 172 }
173
b89a70ce 174 if ($canviewhidden) {
d297269d 175 $altered = array();
176 $unknown = array();
b89a70ce 177 } else {
178 $hiding_affected = grade_grade::get_hiding_affected($grades, $items);
d297269d 179 $altered = $hiding_affected['altered'];
180 $unknown = $hiding_affected['unknown'];
181 unset($hiding_affected);
b89a70ce 182 }
6391ebe7 183
d297269d 184 foreach ($items as $itemid=>$unused) {
185 $grade_item =& $items[$itemid];
186 $grade_grade =& $grades[$itemid];
187
597f50e6 188 if (!$canviewhidden and $grade_item->is_hidden()) {
189 if ($this->showhiddenitems == 0) {
190 // no hidden items at all
191 continue;
192 } else if ($this->showhiddenitems == 1 and !$grade_item->is_hiddenuntil()) {
193 // hidden until that are still hidden are visible
194 continue;
195 }
02973505 196 }
197
d1214909 198 $class = 'gradeitem';
199 if ($grade_item->is_course_item()) {
200 $class = 'courseitem';
201 } else if ($grade_item->is_category_item()) {
202 $class = 'categoryitem';
203 }
204
d297269d 205 if (in_array($itemid, $unknown)) {
206 $gradeval = null;
207 } else if (array_key_exists($itemid, $altered)) {
208 $gradeval = $altered[$itemid];
209 } else {
210 $gradeval = $grade_grade->finalgrade;
211 }
6391ebe7 212
213 $data = array();
f7998fbc 214
ced5ee59 215 // all users should know which items are still hidden
216 $hidden = '';
217 if ($grade_item->is_hidden()) {
218 $hidden = ' hidden ';
219 }
220
6cc3e350 221 $element = $this->gseq->locate_element($this->gseq->get_item_eid($grade_item));
222 $header = $this->gseq->get_element_header($element, true, true, true);
223
e0724506 224 /// prints grade item name
6cc3e350 225 $data[] = '<span class="'.$hidden.$class.'">'.$header.'</span>';
f7998fbc 226
e0724506 227 /// prints category
228 $cat = $grade_item->get_parent_category();
ced5ee59 229 $data[] = '<span class="'.$hidden.$class.'">'.$cat->get_name().'</span>';
230
231 $hidden = '';
232 if ($grade_item->is_hidden()) {
233 // can not see grades in hidden items
234 $hidden = ' hidden ';
235 } else if ($canviewhidden and $grade_grade->is_hidden()) {
236 // if user can see hidden grades, indicate which ones are hidden
237 $hidden = ' hidden ';
238 }
4c8d9481 239
e0724506 240 /// prints the grade
e0724506 241 if ($grade_grade->is_excluded()) {
242 $excluded = get_string('excluded', 'grades').' ';
243 } else {
244 $excluded = '';
245 }
f7998fbc 246
b89a70ce 247 if ($grade_item->needsupdate) {
ced5ee59 248 $data[] = '<span class="'.$hidden.$class.' gradingerror">'.get_string('error').'</span>';
b89a70ce 249
ced5ee59 250 } else if (!empty($CFG->grade_hiddenasdate) and $grade_grade->get_datesubmitted() and !$canviewhidden and $grade_grade->is_hidden()
d297269d 251 and !$grade_item->is_category_item() and !$grade_item->is_course_item()) {
252 // the problem here is that we do not have the time when grade value was modified, 'timemodified' is general modification date for grade_grades records
ced5ee59 253 $data[] = '<span class="'.$hidden.$class.' datesubmitted">'.$excluded.get_string('submittedon', 'grades', userdate($grade_grade->get_datesubmitted(), get_string('strftimedatetimeshort'))).'</span>';
6391ebe7 254
e0724506 255 } else {
a4a15d26 256 $data[] = '<span class="'.$hidden.$class.'">'.$excluded.grade_format_gradevalue($gradeval, $grade_item, true).'</span>';
e0724506 257 }
258
259 /// prints percentage
699da6b5 260 if ($this->showpercentage) {
261 if ($grade_item->needsupdate) {
262 $data[] = '<span class="'.$hidden.$class.'gradingerror">'.get_string('error').'</span>';
23207a1a 263
699da6b5 264 } else {
265 $data[] = '<span class="'.$hidden.$class.'">'.grade_format_gradevalue($gradeval, $grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE).'</span>';
266 }
e0724506 267 }
6391ebe7 268
e0724506 269 /// prints rank
26ed0305 270 if ($this->showrank) {
02973505 271 // TODO: this is broken if hidden grades present!!
272 if ($grade_item->needsupdate) {
ced5ee59 273 $data[] = '<span class="'.$hidden.$class.'gradingerror">'.get_string('error').'</span>';
26ed0305 274
02973505 275 } else if (is_null($gradeval)) {
276 // no grade, no rank
ced5ee59 277 $data[] = '<span class="'.$hidden.$class.'">-</span>';;
26ed0305 278
02973505 279 } else {
280 /// find the number of users with a higher grade
281 $sql = "SELECT COUNT(DISTINCT(userid))
d24832f9 282 FROM {grade_grades}
ea1e551d 283 WHERE finalgrade > ?
284 AND itemid = ?";
285 $rank = $DB->count_records_sql($sql, array($grade_grade->finalgrade, $grade_item->id)) + 1;
26ed0305 286
ced5ee59 287 $data[] = '<span class="'.$hidden.$class.'">'."$rank/$numusers".'</span>';
02973505 288 }
f7998fbc 289 }
290
d1214909 291 /// prints feedback
292 if (empty($grade_grade->feedback) or (!$canviewhidden and $grade_grade->is_hidden())) {
ced5ee59 293 $data[] = '<div class="'.$hidden.'feedbacktext">&nbsp;</div>';
6391ebe7 294
295 } else {
ced5ee59 296 $data[] = '<div class="'.$hidden.'feedbacktext">'.format_text($grade_grade->feedback, $grade_grade->feedbackformat).'</div>';
e0724506 297 }
6391ebe7 298
e0724506 299 $this->table->add_data($data);
f7998fbc 300 }
e0724506 301
302 return true;
f7998fbc 303 }
304
305 /**
306 * Prints or returns the HTML from the flexitable.
307 * @param bool $return Whether or not to return the data instead of printing it directly.
308 * @return string
309 */
5c75a0a3 310 public function print_table($return=false) {
f7998fbc 311 ob_start();
312 $this->table->print_html();
313 $html = ob_get_clean();
314 if ($return) {
315 return $html;
316 } else {
317 echo $html;
318 }
319 }
320
321 /**
322 * Processes the data sent by the form (grades and feedbacks).
323 * @var array $data
324 * @return bool Success or Failure (array of errors).
325 */
5c75a0a3 326 public function process_data($data) {
327 }
328
329 public function process_action($target, $action) {
f7998fbc 330 }
26ed0305 331}
332
333function grade_report_user_settings_definition(&$mform) {
334 global $CFG;
335
336 $options = array(-1 => get_string('default', 'grades'),
337 0 => get_string('hide'),
338 1 => get_string('show'));
339
cd52d909 340 if (empty($CFG->grade_report_user_showrank)) {
26ed0305 341 $options[-1] = get_string('defaultprev', 'grades', $options[0]);
342 } else {
343 $options[-1] = get_string('defaultprev', 'grades', $options[1]);
344 }
345
346 $mform->addElement('select', 'report_user_showrank', get_string('showrank', 'grades'), $options);
d24832f9 347 $mform->setHelpButton('report_user_showrank', array('showrank', get_string('showrank', 'grades'), 'grade'));
26ed0305 348
699da6b5 349 if (empty($CFG->grade_report_user_showpercentage)) {
699da6b5 350 $options[-1] = get_string('defaultprev', 'grades', $options[1]);
aea45e7e 351 } else {
352 $options[-1] = get_string('defaultprev', 'grades', $options[0]);
699da6b5 353 }
354
355 $mform->addElement('select', 'report_user_showpercentage', get_string('showpercentage', 'grades'), $options);
356 $mform->setHelpButton('report_user_showpercentage', array('showpercentage', get_string('showpercentage', 'grades'), 'grade'));
357
26ed0305 358 $options = array(-1 => get_string('default', 'grades'),
359 0 => get_string('hide'),
597f50e6 360 1 => get_string('showhiddenuntilonly', 'grades'),
361 2 => get_string('show'));
26ed0305 362
cd52d909 363 if (empty($CFG->grade_report_user_showhiddenitems)) {
26ed0305 364 $options[-1] = get_string('defaultprev', 'grades', $options[0]);
365 } else {
366 $options[-1] = get_string('defaultprev', 'grades', $options[1]);
367 }
368
369 $mform->addElement('select', 'report_user_showhiddenitems', get_string('showhiddenitems', 'grades'), $options);
d24832f9 370 $mform->setHelpButton('report_user_showhiddenitems', array('showhiddenitems', get_string('showhiddenitems', 'grades'), 'grade'));
0a784551 371}
372
373function grade_report_user_profilereport($course, $user) {
374 if (!empty($course->showgrades)) {
375
376 $context = get_context_instance(CONTEXT_COURSE, $course->id);
377
378 //first make sure we have proper final grades - this must be done before constructing of the grade tree
379 grade_regrade_final_grades($course->id);
380
381 /// return tracking object
382 $gpr = new grade_plugin_return(array('type'=>'report', 'plugin'=>'user', 'courseid'=>$course->id, 'userid'=>$user->id));
383 // Create a report instance
384 $report = new grade_report_user($course->id, $gpr, $context, $user->id);
f7998fbc 385
0a784551 386 // print the page
387 echo '<div class="grade-report-user">'; // css fix to share styles with real report page
388 print_heading(get_string('modulename', 'gradereport_user'). ' - '.fullname($report->user));
389
390 if ($report->fill_table()) {
391 echo $report->print_table(true);
392 }
393 echo '</div>';
394 }
f7998fbc 395}
0a784551 396
f7998fbc 397?>