2 // This file is part of Moodle - http://moodle.org/
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.
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.
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/>.
18 * Definition of the grade_overview_report class
20 * @package gradereport_overview
21 * @copyright 2007 Nicolas Connault
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 require_once($CFG->dirroot . '/grade/report/lib.php');
26 require_once($CFG->libdir.'/tablelib.php');
29 * Class providing an API for the overview report building and displaying.
31 * @package gradereport_overview
33 class grade_report_overview extends grade_report {
48 * A flexitable to hold the data.
54 * Show student ranks within each course.
55 * @var array $showrank
60 * show course/category totals if they contain hidden items
62 var $showtotalsifcontainhidden;
65 * An array of course ids that the user is a student in.
66 * @var array $studentcourseids
68 public $studentcourseids;
71 * An array of courses that the user is a teacher in.
72 * @var array $teachercourses
74 public $teachercourses;
77 * Constructor. Sets local copies of user preferences and initialises grade_tree.
79 * @param object $gpr grade plugin return tracking object
80 * @param string $context
82 public function __construct($userid, $gpr, $context) {
83 global $CFG, $COURSE, $DB;
84 parent::__construct($COURSE->id, $gpr, $context);
86 // Get the user (for full name).
87 $this->user = $DB->get_record('user', array('id' => $userid));
89 // Load the user's courses.
90 $this->courses = enrol_get_users_courses($this->user->id, false, 'id, shortname, showgrades');
92 $this->showrank = array();
93 $this->showrank['any'] = false;
95 $this->showtotalsifcontainhidden = array();
97 $this->studentcourseids = array();
98 $this->teachercourses = array();
99 $roleids = explode(',', get_config('moodle', 'gradebookroles'));
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;
108 $this->showtotalsifcontainhidden[$course->id] = grade_get_setting($course->id, 'report_overview_showtotalsifcontainhidden', $CFG->grade_report_overview_showtotalsifcontainhidden);
110 $coursecontext = context_course::instance($course->id);
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.
120 if (has_capability('moodle/grade:viewall', $coursecontext, $userid)) {
121 $this->teachercourses[$course->id] = $course;
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;
131 $this->setup_table();
135 * Prepares the headers and attributes of the flexitable.
137 public function setup_table() {
139 * Table has 3 columns
140 *| course | final grade | rank (optional) |
143 // setting up table headers
144 if ($this->showrank['any']) {
145 $tablecolumns = array('coursename', 'grade', 'rank');
146 $tableheaders = array($this->get_lang_string('coursename', 'grades'),
147 $this->get_lang_string('gradenoun'),
148 $this->get_lang_string('rank', 'grades'));
150 $tablecolumns = array('coursename', 'grade');
151 $tableheaders = array($this->get_lang_string('coursename', 'grades'),
152 $this->get_lang_string('gradenoun'));
154 $this->table = new flexible_table('grade-report-overview-'.$this->user->id);
156 $this->table->define_columns($tablecolumns);
157 $this->table->define_headers($tableheaders);
158 $this->table->define_baseurl($this->baseurl);
160 $this->table->set_attribute('cellspacing', '0');
161 $this->table->set_attribute('id', 'overview-grade');
162 $this->table->set_attribute('class', 'boxaligncenter generaltable');
164 $this->table->setup();
168 * Set up the courses grades data for the report.
170 * @param bool $studentcoursesonly Only show courses that the user is a student of.
171 * @return array of course grades information
173 public function setup_courses_data($studentcoursesonly) {
176 $coursesdata = array();
177 $numusers = $this->get_numusers(false);
179 foreach ($this->courses as $course) {
180 if (!$course->showgrades) {
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])) {
189 $coursecontext = context_course::instance($course->id);
191 if (!$course->visible && !has_capability('moodle/course:viewhiddencourses', $coursecontext)) {
192 // The course is hidden and the user isn't allowed to see it.
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))) {
202 $coursesdata[$course->id]['course'] = $course;
203 $coursesdata[$course->id]['context'] = $coursecontext;
205 $canviewhidden = has_capability('moodle/grade:viewhidden', $coursecontext);
207 // Get course grade_item.
208 $courseitem = grade_item::fetch_course_item($course->id);
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;
215 if (!$canviewhidden and !is_null($finalgrade)) {
216 if ($coursegrade->is_hidden()) {
219 $adjustedgrade = $this->blank_hidden_total_and_adjust_bounds($course->id,
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'];
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();
238 $coursesdata[$course->id]['finalgrade'] = $finalgrade;
239 $coursesdata[$course->id]['courseitem'] = $courseitem;
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))
247 WHERE finalgrade IS NOT NULL AND finalgrade > ?
249 $rank = $DB->count_records_sql($sql, $params) + 1;
251 $coursesdata[$course->id]['rank'] = $rank;
252 $coursesdata[$course->id]['numusers'] = $numusers;
259 * Fill the table for displaying.
261 * @param bool $activitylink If this report link to the activity report or the user report.
262 * @param bool $studentcoursesonly Only show courses that the user is a student of.
264 public function fill_table($activitylink = false, $studentcoursesonly = false) {
265 global $CFG, $DB, $OUTPUT, $USER;
267 if ($studentcoursesonly && count($this->studentcourseids) == 0) {
271 // Only show user's courses instead of all courses.
272 if ($this->courses) {
273 $coursesdata = $this->setup_courses_data($studentcoursesonly);
275 foreach ($coursesdata as $coursedata) {
277 $course = $coursedata['course'];
278 $coursecontext = $coursedata['context'];
279 $finalgrade = $coursedata['finalgrade'];
280 $courseitem = $coursedata['courseitem'];
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.
285 $courselink = html_writer::link(new moodle_url('/course/user.php', array('mode' => 'grade', 'id' => $course->id,
286 'user' => $this->user->id)), $coursename);
288 $courselink = html_writer::link(new moodle_url('/grade/report/user/index.php', array('id' => $course->id,
289 'userid' => $this->user->id, 'group' => $this->gpr->groupid)), $coursename);
292 $data = array($courselink, grade_format_gradevalue($finalgrade, $courseitem, true));
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";
300 // No grade, no rank.
301 // Or this course wants rank hidden.
306 $this->table->add_data($data);
311 echo $OUTPUT->notification(get_string('notenrolled', 'grades'), 'notifymessage');
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.
321 public function print_table($return=false) {
323 $this->table->print_html();
324 $html = ob_get_clean();
333 * Print a table to show courses that the user is able to grade.
335 public function print_teacher_table() {
336 $table = new html_table();
337 $table->head = array(get_string('coursename', 'grades'));
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));
343 echo html_writer::table($table);
347 * Processes the data sent by the form (grades and feedbacks).
349 * @return bool Success or Failure (array of errors).
351 function process_data($data) {
353 function process_action($target, $action) {
357 * This report supports being set as the 'grades' report.
359 public static function supports_mygrades() {
364 * Check if the user can access the report.
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
374 public static function check_access($systemcontext, $context, $personalcontext, $course, $userid) {
378 if (has_capability('moodle/grade:viewall', $systemcontext)) {
379 // Ok - can view all course grades.
382 } else if (has_capability('moodle/grade:viewall', $context)) {
383 // Ok - can view any grades in context.
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.
391 } else if (has_capability('moodle/grade:viewall', $personalcontext) and $course->showgrades) {
392 // Ok - can view grades of this user - parent most probably.
394 } else if (has_capability('moodle/user:viewuseractivitiesreport', $personalcontext) and $course->showgrades) {
395 // Ok - can view grades of this user - parent most probably.
402 * Trigger the grade_report_viewed event
404 * @param stdClass $context course context
405 * @param int $courseid course id
406 * @param int $userid user id
409 public static function viewed($context, $courseid, $userid) {
410 $event = \gradereport_overview\event\grade_report_viewed::create(
412 'context' => $context,
413 'courseid' => $courseid,
414 'relateduserid' => $userid,
421 function grade_report_overview_settings_definition(&$mform) {
425 $options = array(-1 => get_string('default', 'grades'),
426 0 => get_string('hide'),
427 1 => get_string('show'));
429 if (empty($CFG->grade_report_overview_showrank)) {
430 $options[-1] = get_string('defaultprev', 'grades', $options[0]);
432 $options[-1] = get_string('defaultprev', 'grades', $options[1]);
435 $mform->addElement('select', 'report_overview_showrank', get_string('showrank', 'grades'), $options);
436 $mform->addHelpButton('report_overview_showrank', 'showrank', 'grades');
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') );
444 if (!array_key_exists($CFG->grade_report_overview_showtotalsifcontainhidden, $options)) {
445 $options[-1] = get_string('defaultprev', 'grades', $options[0]);
447 $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_overview_showtotalsifcontainhidden]);
450 $mform->addElement('select', 'report_overview_showtotalsifcontainhidden', get_string('hidetotalifhiddenitems', 'grades'), $options);
451 $mform->addHelpButton('report_overview_showtotalsifcontainhidden', 'hidetotalifhiddenitems', 'grades');
455 * Add nodes to myprofile page.
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
462 function 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();
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, 'id' => $course->id));
472 $node = new core_user\output\myprofile\node('reports', 'grades', get_string('gradesoverview', 'gradereport_overview'),
474 $tree->add_node($node);