MDL-57296 gradelib: Fix get_hidding_effect for grade_type_none items
[moodle.git] / grade / report / overview / lib.php
CommitLineData
e060e33d 1<?php
e060e33d 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/>.
8ad36f4c 16
aa330ebb 17/**
a153c9f2
AD
18 * Definition of the grade_overview_report class
19 *
20 * @package gradereport_overview
21 * @copyright 2007 Nicolas Connault
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
aa330ebb 23 */
24
25require_once($CFG->dirroot . '/grade/report/lib.php');
26require_once($CFG->libdir.'/tablelib.php');
27
28/**
29 * Class providing an API for the overview report building and displaying.
30 * @uses grade_report
a153c9f2 31 * @package gradereport_overview
aa330ebb 32 */
33class grade_report_overview extends grade_report {
34
35 /**
36 * The user.
37 * @var object $user
38 */
5c75a0a3 39 public $user;
aa330ebb 40
9db8d030
AD
41 /**
42 * The user's courses
43 * @var array $courses
44 */
45 public $courses;
46
aa330ebb 47 /**
48 * A flexitable to hold the data.
49 * @var object $table
50 */
5c75a0a3 51 public $table;
aa330ebb 52
60574063 53 /**
9db8d030
AD
54 * Show student ranks within each course.
55 * @var array $showrank
60574063 56 */
5c75a0a3 57 public $showrank;
60574063 58
61541a5a
AD
59 /**
60 * show course/category totals if they contain hidden items
61 */
62 var $showtotalsifcontainhidden;
63
c78dbe03
AG
64 /**
65 * An array of course ids that the user is a student in.
66 * @var array $studentcourseids
67 */
68 public $studentcourseids;
69
70 /**
71 * An array of courses that the user is a teacher in.
72 * @var array $teachercourses
73 */
74 public $teachercourses;
75
aa330ebb 76 /**
77 * Constructor. Sets local copies of user preferences and initialises grade_tree.
78 * @param int $userid
79 * @param object $gpr grade plugin return tracking object
80 * @param string $context
81 */
5c75a0a3 82 public function __construct($userid, $gpr, $context) {
83 global $CFG, $COURSE, $DB;
84 parent::__construct($COURSE->id, $gpr, $context);
f7e21436 85
9db8d030 86 // Get the user (for full name).
5c75a0a3 87 $this->user = $DB->get_record('user', array('id' => $userid));
aa330ebb 88
9db8d030
AD
89 // Load the user's courses.
90 $this->courses = enrol_get_users_courses($this->user->id, false, 'id, shortname, showgrades');
91
92 $this->showrank = array();
93 $this->showrank['any'] = false;
5df9bc39
AD
94
95 $this->showtotalsifcontainhidden = array();
96
c78dbe03
AG
97 $this->studentcourseids = array();
98 $this->teachercourses = array();
99 $roleids = explode(',', get_config('moodle', 'gradebookroles'));
100
9db8d030
AD
101 if ($this->courses) {
102 foreach ($this->courses as $course) {
103 $this->showrank[$course->id] = grade_get_setting($course->id, 'report_overview_showrank', !empty($CFG->grade_report_overview_showrank));
104 if ($this->showrank[$course->id]) {
105 $this->showrank['any'] = true;
106 }
5df9bc39
AD
107
108 $this->showtotalsifcontainhidden[$course->id] = grade_get_setting($course->id, 'report_overview_showtotalsifcontainhidden', $CFG->grade_report_overview_showtotalsifcontainhidden);
c78dbe03
AG
109
110 $coursecontext = context_course::instance($course->id);
111
112 foreach ($roleids as $roleid) {
113 if (user_has_role_assignment($userid, $roleid, $coursecontext->id)) {
114 $this->studentcourseids[$course->id] = $course->id;
115 // We only need to check if one of the roleids has been assigned.
116 break;
117 }
118 }
119
120 if (has_capability('moodle/grade:viewall', $coursecontext, $userid)) {
121 $this->teachercourses[$course->id] = $course;
122 }
9db8d030
AD
123 }
124 }
125
126
aa330ebb 127 // base url for sorting by first/last name
128 $this->baseurl = $CFG->wwwroot.'/grade/overview/index.php?id='.$userid;
129 $this->pbarurl = $this->baseurl;
130
131 $this->setup_table();
132 }
133
134 /**
135 * Prepares the headers and attributes of the flexitable.
136 */
5c75a0a3 137 public function setup_table() {
aa330ebb 138 /*
60574063 139 * Table has 3 columns
140 *| course | final grade | rank (optional) |
141 */
aa330ebb 142
143 // setting up table headers
9db8d030 144 if ($this->showrank['any']) {
60574063 145 $tablecolumns = array('coursename', 'grade', 'rank');
146 $tableheaders = array($this->get_lang_string('coursename', 'grades'),
147 $this->get_lang_string('grade'),
148 $this->get_lang_string('rank', 'grades'));
149 } else {
150 $tablecolumns = array('coursename', 'grade');
151 $tableheaders = array($this->get_lang_string('coursename', 'grades'),
152 $this->get_lang_string('grade'));
153 }
aa330ebb 154 $this->table = new flexible_table('grade-report-overview-'.$this->user->id);
155
156 $this->table->define_columns($tablecolumns);
157 $this->table->define_headers($tableheaders);
158 $this->table->define_baseurl($this->baseurl);
159
160 $this->table->set_attribute('cellspacing', '0');
161 $this->table->set_attribute('id', 'overview-grade');
162 $this->table->set_attribute('class', 'boxaligncenter generaltable');
163
164 $this->table->setup();
165 }
166
91bbfdfe
JL
167 /**
168 * Set up the courses grades data for the report.
169 *
170 * @param bool $studentcoursesonly Only show courses that the user is a student of.
171 * @return array of course grades information
172 */
173 public function setup_courses_data($studentcoursesonly) {
174 global $USER, $DB;
175
176 $coursesdata = array();
177 $numusers = $this->get_numusers(false);
178
179 foreach ($this->courses as $course) {
180 if (!$course->showgrades) {
181 continue;
182 }
183
184 // If we are only showing student courses and this course isn't part of the group, then move on.
185 if ($studentcoursesonly && !isset($this->studentcourseids[$course->id])) {
186 continue;
187 }
188
189 $coursecontext = context_course::instance($course->id);
190
191 if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
192 // The course is hidden and the user isn't allowed to see it.
193 continue;
194 }
195
196 if (!has_capability('moodle/user:viewuseractivitiesreport', context_user::instance($this->user->id)) &&
197 ((!has_capability('moodle/grade:view', $coursecontext) || $this->user->id != $USER->id) &&
198 !has_capability('moodle/grade:viewall', $coursecontext))) {
199 continue;
200 }
201
202 $coursesdata[$course->id]['course'] = $course;
203 $coursesdata[$course->id]['context'] = $coursecontext;
204
205 $canviewhidden = has_capability('moodle/grade:viewhidden', $coursecontext);
206
207 // Get course grade_item.
208 $courseitem = grade_item::fetch_course_item($course->id);
209
210 // Get the stored grade.
211 $coursegrade = new grade_grade(array('itemid' => $courseitem->id, 'userid' => $this->user->id));
212 $coursegrade->grade_item =& $courseitem;
213 $finalgrade = $coursegrade->finalgrade;
214
215 if (!$canviewhidden and !is_null($finalgrade)) {
216 if ($coursegrade->is_hidden()) {
217 $finalgrade = null;
218 } else {
219 $adjustedgrade = $this->blank_hidden_total_and_adjust_bounds($course->id,
220 $courseitem,
221 $finalgrade);
222
223 // We temporarily adjust the view of this grade item - because the min and
224 // max are affected by the hidden values in the aggregation.
225 $finalgrade = $adjustedgrade['grade'];
226 $courseitem->grademax = $adjustedgrade['grademax'];
227 $courseitem->grademin = $adjustedgrade['grademin'];
228 }
229 } else {
230 // We must use the specific max/min because it can be different for
231 // each grade_grade when items are excluded from sum of grades.
232 if (!is_null($finalgrade)) {
233 $courseitem->grademin = $coursegrade->get_grade_min();
234 $courseitem->grademax = $coursegrade->get_grade_max();
235 }
236 }
237
238 $coursesdata[$course->id]['finalgrade'] = $finalgrade;
239 $coursesdata[$course->id]['courseitem'] = $courseitem;
240
241 if ($this->showrank['any'] && $this->showrank[$course->id] && !is_null($finalgrade)) {
242 // Find the number of users with a higher grade.
243 // Please note this can not work if hidden grades involved :-( to be fixed in 2.0.
244 $params = array($finalgrade, $courseitem->id);
245 $sql = "SELECT COUNT(DISTINCT(userid))
246 FROM {grade_grades}
247 WHERE finalgrade IS NOT NULL AND finalgrade > ?
248 AND itemid = ?";
249 $rank = $DB->count_records_sql($sql, $params) + 1;
250
251 $coursesdata[$course->id]['rank'] = $rank;
252 $coursesdata[$course->id]['numusers'] = $numusers;
253 }
254 }
255 return $coursesdata;
256 }
257
c9451960
AG
258 /**
259 * Fill the table for displaying.
260 *
261 * @param bool $activitylink If this report link to the activity report or the user report.
c78dbe03 262 * @param bool $studentcoursesonly Only show courses that the user is a student of.
c9451960 263 */
c78dbe03 264 public function fill_table($activitylink = false, $studentcoursesonly = false) {
78527462 265 global $CFG, $DB, $OUTPUT, $USER;
aa330ebb 266
c78dbe03
AG
267 if ($studentcoursesonly && count($this->studentcourseids) == 0) {
268 return false;
269 }
270
9db8d030
AD
271 // Only show user's courses instead of all courses.
272 if ($this->courses) {
91bbfdfe 273 $coursesdata = $this->setup_courses_data($studentcoursesonly);
31eae0eb 274
91bbfdfe 275 foreach ($coursesdata as $coursedata) {
31eae0eb 276
91bbfdfe
JL
277 $course = $coursedata['course'];
278 $coursecontext = $coursedata['context'];
279 $finalgrade = $coursedata['finalgrade'];
280 $courseitem = $coursedata['courseitem'];
78527462 281
c9451960
AG
282 $coursename = format_string(get_course_display_name_for_list($course), true, array('context' => $coursecontext));
283 // Link to the activity report version of the user grade report.
284 if ($activitylink) {
285 $courselink = html_writer::link(new moodle_url('/course/user.php', array('mode' => 'grade', 'id' => $course->id,
286 'user' => $this->user->id)), $coursename);
287 } else {
288 $courselink = html_writer::link(new moodle_url('/grade/report/user/index.php', array('id' => $course->id,
289 'userid' => $this->user->id)), $coursename);
290 }
60574063 291
91bbfdfe 292 $data = array($courselink, grade_format_gradevalue($finalgrade, $courseitem, true));
00006755 293
91bbfdfe
JL
294 if ($this->showrank['any']) {
295 if ($this->showrank[$course->id] && !is_null($finalgrade)) {
296 $rank = $coursedata['rank'];
297 $numusers = $coursedata['numusers'];
298 $data[] = "$rank/$numusers";
00006755 299 } else {
91bbfdfe
JL
300 // No grade, no rank.
301 // Or this course wants rank hidden.
302 $data[] = '-';
5a59aeb1 303 }
60574063 304 }
305
60574063 306 $this->table->add_data($data);
aa330ebb 307 }
60574063 308
91bbfdfe 309 return true;
aa330ebb 310 } else {
c9451960 311 echo $OUTPUT->notification(get_string('notenrolled', 'grades'), 'notifymessage');
aa330ebb 312 return false;
313 }
314 }
315
316 /**
317 * Prints or returns the HTML from the flexitable.
318 * @param bool $return Whether or not to return the data instead of printing it directly.
319 * @return string
320 */
5c75a0a3 321 public function print_table($return=false) {
aa330ebb 322 ob_start();
323 $this->table->print_html();
324 $html = ob_get_clean();
325 if ($return) {
326 return $html;
327 } else {
328 echo $html;
329 }
330 }
331
c78dbe03
AG
332 /**
333 * Print a table to show courses that the user is able to grade.
334 */
335 public function print_teacher_table() {
336 $table = new html_table();
337 $table->head = array(get_string('coursename', 'grades'));
338 $table->data = null;
339 foreach ($this->teachercourses as $courseid => $course) {
340 $url = new moodle_url('/grade/report/index.php', array('id' => $courseid));
341 $table->data[] = array(html_writer::link($url, $course->fullname));
342 }
343 echo html_writer::table($table);
344 }
345
aa330ebb 346 /**
347 * Processes the data sent by the form (grades and feedbacks).
0ef6c851 348 * @param array $data
aa330ebb 349 * @return bool Success or Failure (array of errors).
350 */
653a8648 351 function process_data($data) {
5c75a0a3 352 }
653a8648 353 function process_action($target, $action) {
aa330ebb 354 }
c9451960
AG
355
356 /**
4887d152 357 * This report supports being set as the 'grades' report.
c9451960
AG
358 */
359 public static function supports_mygrades() {
360 return true;
361 }
78310c30
JL
362
363 /**
364 * Check if the user can access the report.
365 *
366 * @param stdClass $systemcontext system context
367 * @param stdClass $context course context
368 * @param stdClass $personalcontext personal context
369 * @param stdClass $course course object
370 * @param int $userid userid
371 * @return bool true if the user can access the report
372 * @since Moodle 3.2
373 */
374 public static function check_access($systemcontext, $context, $personalcontext, $course, $userid) {
375 global $USER;
376
377 $access = false;
378 if (has_capability('moodle/grade:viewall', $systemcontext)) {
379 // Ok - can view all course grades.
380 $access = true;
381
382 } else if (has_capability('moodle/grade:viewall', $context)) {
383 // Ok - can view any grades in context.
384 $access = true;
385
386 } else if ($userid == $USER->id and ((has_capability('moodle/grade:view', $context) and $course->showgrades)
387 || $course->id == SITEID)) {
388 // Ok - can view own course grades.
389 $access = true;
390
391 } else if (has_capability('moodle/grade:viewall', $personalcontext) and $course->showgrades) {
392 // Ok - can view grades of this user - parent most probably.
393 $access = true;
394 } else if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext) and $course->showgrades) {
395 // Ok - can view grades of this user - parent most probably.
396 $access = true;
397 }
398 return $access;
399 }
400
401 /**
402 * Trigger the grade_report_viewed event
403 *
404 * @param stdClass $context course context
405 * @param int $courseid course id
406 * @param int $userid user id
407 * @since Moodle 3.2
408 */
409 public static function viewed($context, $courseid, $userid) {
410 $event = \gradereport_overview\event\grade_report_viewed::create(
411 array(
412 'context' => $context,
413 'courseid' => $courseid,
414 'relateduserid' => $userid,
415 )
416 );
417 $event->trigger();
418 }
60574063 419}
aa330ebb 420
60574063 421function grade_report_overview_settings_definition(&$mform) {
422 global $CFG;
423
61541a5a 424 //show rank
60574063 425 $options = array(-1 => get_string('default', 'grades'),
426 0 => get_string('hide'),
427 1 => get_string('show'));
428
180acd64 429 if (empty($CFG->grade_report_overview_showrank)) {
60574063 430 $options[-1] = get_string('defaultprev', 'grades', $options[0]);
431 } else {
432 $options[-1] = get_string('defaultprev', 'grades', $options[1]);
433 }
434
435 $mform->addElement('select', 'report_overview_showrank', get_string('showrank', 'grades'), $options);
bf03b43f 436 $mform->addHelpButton('report_overview_showrank', 'showrank', 'grades');
61541a5a
AD
437
438 //showtotalsifcontainhidden
439 $options = array(-1 => get_string('default', 'grades'),
440 GRADE_REPORT_HIDE_TOTAL_IF_CONTAINS_HIDDEN => get_string('hide'),
441 GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowexhiddenitems', 'grades'),
442 GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowinchiddenitems', 'grades') );
443
d6bef7e7 444 if (!array_key_exists($CFG->grade_report_overview_showtotalsifcontainhidden, $options)) {
61541a5a
AD
445 $options[-1] = get_string('defaultprev', 'grades', $options[0]);
446 } else {
d6bef7e7 447 $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_overview_showtotalsifcontainhidden]);
61541a5a
AD
448 }
449
450 $mform->addElement('select', 'report_overview_showtotalsifcontainhidden', get_string('hidetotalifhiddenitems', 'grades'), $options);
0459cc4d 451 $mform->addHelpButton('report_overview_showtotalsifcontainhidden', 'hidetotalifhiddenitems', 'grades');
aa330ebb 452}
60574063 453
4d914971
AG
454/**
455 * Add nodes to myprofile page.
456 *
457 * @param \core_user\output\myprofile\tree $tree Tree object
458 * @param stdClass $user user object
459 * @param bool $iscurrentuser
460 * @param stdClass $course Course object
461 */
462function gradereport_overview_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $iscurrentuser, $course) {
463 if (empty($course)) {
464 // We want to display these reports under the site context.
465 $course = get_fast_modinfo(SITEID)->get_course();
466 }
467 $systemcontext = context_system::instance();
468 $usercontext = context_user::instance($user->id);
469 $coursecontext = context_course::instance($course->id);
470 if (grade_report_overview::check_access($systemcontext, $coursecontext, $usercontext, $course, $user->id)) {
471 $url = new moodle_url('/grade/report/overview/index.php', array('userid' => $user->id));
472 $node = new core_user\output\myprofile\node('reports', 'grades', get_string('gradesoverview', 'gradereport_overview'),
473 null, $url);
474 $tree->add_node($node);
475 }
476}