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