3 ///////////////////////////////////////////////////////////////////////////
5 // NOTICE OF COPYRIGHT //
7 // Moodle - Modular Object-Oriented Dynamic Learning Environment //
8 // http://moodle.com //
10 // Copyright (C) 1999 onwards Martin Dougiamas http://moodle.com //
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. //
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: //
22 // http://www.gnu.org/copyleft/gpl.html //
24 ///////////////////////////////////////////////////////////////////////////
26 * File in which the user_report class is defined.
30 require_once($CFG->dirroot
. '/grade/report/lib.php');
31 require_once($CFG->libdir
.'/tablelib.php');
34 * Class providing an API for the user report building and displaying.
38 class grade_report_user
extends grade_report
{
47 * A flexitable to hold the data.
53 * Flat structure similar to grade tree
63 * Show hidden items even when user does not have required cap
68 * Constructor. Sets local copies of user preferences and initialises grade_tree.
69 * @param int $courseid
70 * @param object $gpr grade plugin return tracking object
71 * @param string $context
72 * @param int $userid The id of the user
74 function grade_report_user($courseid, $gpr, $context, $userid) {
76 parent
::grade_report($courseid, $gpr, $context);
78 $this->showrank
= grade_get_setting($this->courseid
, 'report_user_showrank', $CFG->grade_report_user_showrank
);
79 $this->showhiddenitems
= grade_get_setting($this->courseid
, 'report_user_showhiddenitems', $CFG->grade_report_user_showhiddenitems
);
81 $switch = grade_get_setting($this->courseid
, 'aggregationposition', $CFG->grade_aggregationposition
);
83 // Grab the grade_seq for this course
84 $this->gseq
= new grade_seq($this->courseid
, $switch);
86 // get the user (for full name)
87 $this->user
= get_record('user', 'id', $userid);
89 // base url for sorting by first/last name
90 $this->baseurl
= $CFG->wwwroot
.'/grade/report?id='.$courseid.'&userid='.$userid;
91 $this->pbarurl
= $this->baseurl
;
93 // no groups on this report - rank is from all course users
98 * Prepares the headers and attributes of the flexitable.
100 function setup_table() {
103 * Table has 5-6 columns
104 *| itemname/description | final grade | percentage final grade | rank (optional) | feedback |
107 // setting up table headers
108 if ($this->showrank
) {
109 // TODO: this is broken if hidden grades present!!
110 $tablecolumns = array('itemname', 'category', 'grade', 'percentage', 'rank', 'feedback');
111 $tableheaders = array($this->get_lang_string('gradeitem', 'grades'), $this->get_lang_string('category'), $this->get_lang_string('grade'),
112 $this->get_lang_string('percent', 'grades'), $this->get_lang_string('rank', 'grades'),
113 $this->get_lang_string('feedback'));
115 $tablecolumns = array('itemname', 'category', 'grade', 'percentage', 'feedback');
116 $tableheaders = array($this->get_lang_string('gradeitem', 'grades'), $this->get_lang_string('category'), $this->get_lang_string('grade'),
117 $this->get_lang_string('percent', 'grades'), $this->get_lang_string('feedback'));
120 $this->table
= new flexible_table('grade-report-user-'.$this->courseid
);
122 $this->table
->define_columns($tablecolumns);
123 $this->table
->define_headers($tableheaders);
124 $this->table
->define_baseurl($this->baseurl
);
126 $this->table
->set_attribute('cellspacing', '0');
127 $this->table
->set_attribute('id', 'user-grade');
128 $this->table
->set_attribute('class', 'boxaligncenter generaltable');
130 // not sure tables should be sortable or not, because if we allow it then sorted results distort grade category structure and sortorder
131 $this->table
->set_control_variables(array(
132 TABLE_VAR_SORT
=> 'ssort',
133 TABLE_VAR_HIDE
=> 'shide',
134 TABLE_VAR_SHOW
=> 'sshow',
135 TABLE_VAR_IFIRST
=> 'sifirst',
136 TABLE_VAR_ILAST
=> 'silast',
137 TABLE_VAR_PAGE
=> 'spage'
140 $this->table
->setup();
143 function fill_table() {
145 $numusers = $this->get_numusers(false); // total course users
146 $items =& $this->gseq
->items
;
149 $canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE
, $this->courseid
));
151 // fetch or create all grades
152 foreach ($items as $key=>$unused) {
153 if (!$grade_grade = grade_grade
::fetch(array('itemid'=>$items[$key]->id
, 'userid'=>$this->user
->id
))) {
154 $grade_grade = new grade_grade();
155 $grade_grade->userid
= $this->user
->id
;
156 $grade_grade->itemid
= $items[$key]->id
;
158 $grades[$key] = $grade_grade;
159 $grades[$key]->grade_item
=& $items[$key];
162 if ($canviewhidden) {
166 $hiding_affected = grade_grade
::get_hiding_affected($grades, $items);
167 $altered = $hiding_affected['altered'];
168 $unknown = $hiding_affected['unknown'];
169 unset($hiding_affected);
172 foreach ($items as $itemid=>$unused) {
173 $grade_item =& $items[$itemid];
174 $grade_grade =& $grades[$itemid];
176 if (!$canviewhidden and $grade_item->is_hidden()) {
177 if ($this->showhiddenitems
== 0) {
178 // no hidden items at all
180 } else if ($this->showhiddenitems
== 1 and !$grade_item->is_hiddenuntil()) {
181 // hidden until that are still hidden are visible
186 $class = 'gradeitem';
187 if ($grade_item->is_course_item()) {
188 $class = 'courseitem';
189 } else if ($grade_item->is_category_item()) {
190 $class = 'categoryitem';
193 if (in_array($itemid, $unknown)) {
195 } else if (array_key_exists($itemid, $altered)) {
196 $gradeval = $altered[$itemid];
198 $gradeval = $grade_grade->finalgrade
;
203 // all users should know which items are still hidden
205 if ($grade_item->is_hidden()) {
206 $hidden = ' hidden ';
209 $element = $this->gseq
->locate_element($this->gseq
->get_item_eid($grade_item));
210 $header = $this->gseq
->get_element_header($element, true, true, true);
212 /// prints grade item name
213 $data[] = '<span class="'.$hidden.$class.'">'.$header.'</span>';
216 $cat = $grade_item->get_parent_category();
217 $data[] = '<span class="'.$hidden.$class.'">'.$cat->get_name().'</span>';
220 if ($grade_item->is_hidden()) {
221 // can not see grades in hidden items
222 $hidden = ' hidden ';
223 } else if ($canviewhidden and $grade_grade->is_hidden()) {
224 // if user can see hidden grades, indicate which ones are hidden
225 $hidden = ' hidden ';
229 if ($grade_grade->is_excluded()) {
230 $excluded = get_string('excluded', 'grades').' ';
235 if ($grade_item->needsupdate
) {
236 $data[] = '<span class="'.$hidden.$class.' gradingerror">'.get_string('error').'</span>';
238 } else if (!empty($CFG->grade_hiddenasdate
) and $grade_grade->get_datesubmitted() and !$canviewhidden and $grade_grade->is_hidden()
239 and !$grade_item->is_category_item() and !$grade_item->is_course_item()) {
240 // 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
241 $data[] = '<span class="'.$hidden.$class.' datesubmitted">'.$excluded.get_string('submittedon', 'grades', userdate($grade_grade->get_datesubmitted(), get_string('strftimedatetimeshort'))).'</span>';
244 $data[] = '<span class="'.$hidden.$class.'">'.$excluded.grade_format_gradevalue($gradeval, $grade_item, true).'</span>';
247 /// prints percentage
248 if ($grade_item->needsupdate
) {
249 $data[] = '<span class="'.$hidden.$class.'gradingerror">'.get_string('error').'</span>';
252 $data[] = '<span class="'.$hidden.$class.'">'.grade_format_gradevalue($gradeval, $grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE
).'</span>';
256 if ($this->showrank
) {
257 // TODO: this is broken if hidden grades present!!
258 if ($grade_item->needsupdate
) {
259 $data[] = '<span class="'.$hidden.$class.'gradingerror">'.get_string('error').'</span>';
261 } else if (is_null($gradeval)) {
263 $data[] = '<span class="'.$hidden.$class.'">-</span>';;
266 /// find the number of users with a higher grade
267 $sql = "SELECT COUNT(DISTINCT(userid))
268 FROM {$CFG->prefix}grade_grades
269 WHERE finalgrade > {$grade_grade->finalgrade}
270 AND itemid = {$grade_item->id}";
271 $rank = count_records_sql($sql) +
1;
273 $data[] = '<span class="'.$hidden.$class.'">'."$rank/$numusers".'</span>';
278 if (empty($grade_grade->feedback
) or (!$canviewhidden and $grade_grade->is_hidden())) {
279 $data[] = '<div class="'.$hidden.'feedbacktext"> </div>';
282 $data[] = '<div class="'.$hidden.'feedbacktext">'.format_text($grade_grade->feedback
, $grade_grade->feedbackformat
).'</div>';
285 $this->table
->add_data($data);
292 * Prints or returns the HTML from the flexitable.
293 * @param bool $return Whether or not to return the data instead of printing it directly.
296 function print_table($return=false) {
298 $this->table
->print_html();
299 $html = ob_get_clean();
308 * Processes the data sent by the form (grades and feedbacks).
310 * @return bool Success or Failure (array of errors).
312 function process_data($data) {
316 function grade_report_user_settings_definition(&$mform) {
319 $options = array(-1 => get_string('default', 'grades'),
320 0 => get_string('hide'),
321 1 => get_string('show'));
323 if (empty($CFG->grade_report_user_showrank
)) {
324 $options[-1] = get_string('defaultprev', 'grades', $options[0]);
326 $options[-1] = get_string('defaultprev', 'grades', $options[1]);
329 $mform->addElement('select', 'report_user_showrank', get_string('showrank', 'grades'), $options);
330 $mform->setHelpButton('report_user_showrank', array('showrank', get_string('showrank', 'grades'), 'grade'));
332 $options = array(-1 => get_string('default', 'grades'),
333 0 => get_string('hide'),
334 1 => get_string('showhiddenuntilonly', 'grades'),
335 2 => get_string('show'));
337 if (empty($CFG->grade_report_user_showhiddenitems
)) {
338 $options[-1] = get_string('defaultprev', 'grades', $options[0]);
340 $options[-1] = get_string('defaultprev', 'grades', $options[1]);
343 $mform->addElement('select', 'report_user_showhiddenitems', get_string('showhiddenitems', 'grades'), $options);
344 $mform->setHelpButton('report_user_showhiddenitems', array('showhiddenitems', get_string('showhiddenitems', 'grades'), 'grade'));
347 function grade_report_user_profilereport($course, $user) {
348 if (!empty($course->showgrades
)) {
350 $context = get_context_instance(CONTEXT_COURSE
, $course->id
);
352 //first make sure we have proper final grades - this must be done before constructing of the grade tree
353 grade_regrade_final_grades($course->id
);
355 /// return tracking object
356 $gpr = new grade_plugin_return(array('type'=>'report', 'plugin'=>'user', 'courseid'=>$course->id
, 'userid'=>$user->id
));
357 // Create a report instance
358 $report = new grade_report_user($course->id
, $gpr, $context, $user->id
);
361 echo '<div class="grade-report-user">'; // css fix to share styles with real report page
362 print_heading(get_string('modulename', 'gradereport_user'). ' - '.fullname($report->user
));
364 if ($report->fill_table()) {
365 echo $report->print_table(true);