Differences Between: [Versions 310 and 400] [Versions 311 and 400] [Versions 39 and 400] [Versions 400 and 401] [Versions 400 and 402] [Versions 400 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_user_report class is defined 19 * 20 * @package gradereport_user 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 //showhiddenitems values 29 define("GRADE_REPORT_USER_HIDE_HIDDEN", 0); 30 define("GRADE_REPORT_USER_HIDE_UNTIL", 1); 31 define("GRADE_REPORT_USER_SHOW_HIDDEN", 2); 32 33 define("GRADE_REPORT_USER_VIEW_SELF", 1); 34 define("GRADE_REPORT_USER_VIEW_USER", 2); 35 36 /** 37 * Class providing an API for the user report building and displaying. 38 * @uses grade_report 39 * @package gradereport_user 40 */ 41 class grade_report_user extends grade_report { 42 43 /** 44 * The user. 45 * @var object $user 46 */ 47 public $user; 48 49 /** 50 * A flexitable to hold the data. 51 * @var object $table 52 */ 53 public $table; 54 55 /** 56 * An array of table headers 57 * @var array 58 */ 59 public $tableheaders = array(); 60 61 /** 62 * An array of table columns 63 * @var array 64 */ 65 public $tablecolumns = array(); 66 67 /** 68 * An array containing rows of data for the table. 69 * @var type 70 */ 71 public $tabledata = array(); 72 73 /** 74 * An array containing the grade items data for external usage (web services, ajax, etc...) 75 * @var array 76 */ 77 public $gradeitemsdata = array(); 78 79 /** 80 * The grade tree structure 81 * @var grade_tree 82 */ 83 public $gtree; 84 85 /** 86 * Flat structure similar to grade tree 87 */ 88 public $gseq; 89 90 /** 91 * show student ranks 92 */ 93 public $showrank; 94 95 /** 96 * show grade percentages 97 */ 98 public $showpercentage; 99 100 /** 101 * Show range 102 */ 103 public $showrange = true; 104 105 /** 106 * Show grades in the report, default true 107 * @var bool 108 */ 109 public $showgrade = true; 110 111 /** 112 * Decimal points to use for values in the report, default 2 113 * @var int 114 */ 115 public $decimals = 2; 116 117 /** 118 * The number of decimal places to round range to, default 0 119 * @var int 120 */ 121 public $rangedecimals = 0; 122 123 /** 124 * Show grade feedback in the report, default true 125 * @var bool 126 */ 127 public $showfeedback = true; 128 129 /** 130 * Show grade weighting in the report, default true. 131 * @var bool 132 */ 133 public $showweight = true; 134 135 /** 136 * Show letter grades in the report, default false 137 * @var bool 138 */ 139 public $showlettergrade = false; 140 141 /** 142 * Show the calculated contribution to the course total column. 143 * @var bool 144 */ 145 public $showcontributiontocoursetotal = true; 146 147 /** 148 * Show average grades in the report, default false. 149 * @var false 150 */ 151 public $showaverage = false; 152 153 public $maxdepth; 154 public $evenodd; 155 156 public $canviewhidden; 157 158 public $switch; 159 160 /** 161 * Show hidden items even when user does not have required cap 162 */ 163 public $showhiddenitems; 164 public $showtotalsifcontainhidden; 165 166 public $baseurl; 167 public $pbarurl; 168 169 /** 170 * The modinfo object to be used. 171 * 172 * @var course_modinfo 173 */ 174 protected $modinfo = null; 175 176 /** 177 * View as user. 178 * 179 * When this is set to true, the visibility checks, and capability checks will be 180 * applied to the user whose grades are being displayed. This is very useful when 181 * a mentor/parent is viewing the report of their mentee because they need to have 182 * access to the same information, but not more, not less. 183 * 184 * @var boolean 185 */ 186 protected $viewasuser = false; 187 188 /** 189 * An array that collects the aggregationhints for every 190 * grade_item. The hints contain grade, grademin, grademax 191 * status, weight and parent. 192 * 193 * @var array 194 */ 195 protected $aggregationhints = array(); 196 197 /** 198 * Constructor. Sets local copies of user preferences and initialises grade_tree. 199 * @param int $courseid 200 * @param object $gpr grade plugin return tracking object 201 * @param string $context 202 * @param int $userid The id of the user 203 * @param bool $viewasuser Set this to true when the current user is a mentor/parent of the targetted user. 204 */ 205 public function __construct($courseid, $gpr, $context, $userid, $viewasuser = null) { 206 global $DB, $CFG; 207 parent::__construct($courseid, $gpr, $context); 208 209 $this->showrank = grade_get_setting($this->courseid, 'report_user_showrank', $CFG->grade_report_user_showrank); 210 $this->showpercentage = grade_get_setting($this->courseid, 'report_user_showpercentage', $CFG->grade_report_user_showpercentage); 211 $this->showhiddenitems = grade_get_setting($this->courseid, 'report_user_showhiddenitems', $CFG->grade_report_user_showhiddenitems); 212 $this->showtotalsifcontainhidden = array($this->courseid => grade_get_setting($this->courseid, 'report_user_showtotalsifcontainhidden', $CFG->grade_report_user_showtotalsifcontainhidden)); 213 214 $this->showgrade = grade_get_setting($this->courseid, 'report_user_showgrade', !empty($CFG->grade_report_user_showgrade)); 215 $this->showrange = grade_get_setting($this->courseid, 'report_user_showrange', !empty($CFG->grade_report_user_showrange)); 216 $this->showfeedback = grade_get_setting($this->courseid, 'report_user_showfeedback', !empty($CFG->grade_report_user_showfeedback)); 217 218 $this->showweight = grade_get_setting($this->courseid, 'report_user_showweight', 219 !empty($CFG->grade_report_user_showweight)); 220 221 $this->showcontributiontocoursetotal = grade_get_setting($this->courseid, 'report_user_showcontributiontocoursetotal', 222 !empty($CFG->grade_report_user_showcontributiontocoursetotal)); 223 224 $this->showlettergrade = grade_get_setting($this->courseid, 'report_user_showlettergrade', !empty($CFG->grade_report_user_showlettergrade)); 225 $this->showaverage = grade_get_setting($this->courseid, 'report_user_showaverage', !empty($CFG->grade_report_user_showaverage)); 226 227 $this->viewasuser = $viewasuser; 228 229 // The default grade decimals is 2 230 $defaultdecimals = 2; 231 if (property_exists($CFG, 'grade_decimalpoints')) { 232 $defaultdecimals = $CFG->grade_decimalpoints; 233 } 234 $this->decimals = grade_get_setting($this->courseid, 'decimalpoints', $defaultdecimals); 235 236 // The default range decimals is 0 237 $defaultrangedecimals = 0; 238 if (property_exists($CFG, 'grade_report_user_rangedecimals')) { 239 $defaultrangedecimals = $CFG->grade_report_user_rangedecimals; 240 } 241 $this->rangedecimals = grade_get_setting($this->courseid, 'report_user_rangedecimals', $defaultrangedecimals); 242 243 $this->switch = grade_get_setting($this->courseid, 'aggregationposition', $CFG->grade_aggregationposition); 244 245 // Grab the grade_tree for this course 246 $this->gtree = new grade_tree($this->courseid, false, $this->switch, null, !$CFG->enableoutcomes); 247 248 // Get the user (for full name). 249 $this->user = $DB->get_record('user', array('id' => $userid)); 250 251 // What user are we viewing this as? 252 $coursecontext = context_course::instance($this->courseid); 253 if ($viewasuser) { 254 $this->modinfo = new course_modinfo($this->course, $this->user->id); 255 $this->canviewhidden = has_capability('moodle/grade:viewhidden', $coursecontext, $this->user->id); 256 } else { 257 $this->modinfo = $this->gtree->modinfo; 258 $this->canviewhidden = has_capability('moodle/grade:viewhidden', $coursecontext); 259 } 260 261 // Determine the number of rows and indentation. 262 $this->maxdepth = 1; 263 $this->inject_rowspans($this->gtree->top_element); 264 $this->maxdepth++; // Need to account for the lead column that spans all children. 265 for ($i = 1; $i <= $this->maxdepth; $i++) { 266 $this->evenodd[$i] = 0; 267 } 268 269 $this->tabledata = array(); 270 271 // base url for sorting by first/last name 272 $this->baseurl = $CFG->wwwroot.'/grade/report?id='.$courseid.'&userid='.$userid; 273 $this->pbarurl = $this->baseurl; 274 275 // no groups on this report - rank is from all course users 276 $this->setup_table(); 277 278 //optionally calculate grade item averages 279 $this->calculate_averages(); 280 } 281 282 /** 283 * Recurses through a tree of elements setting the rowspan property on each element 284 * 285 * @param array $element Either the top element or, during recursion, the current element 286 * @return int The number of elements processed 287 */ 288 function inject_rowspans(&$element) { 289 290 if ($element['depth'] > $this->maxdepth) { 291 $this->maxdepth = $element['depth']; 292 } 293 if (empty($element['children'])) { 294 return 1; 295 } 296 $count = 1; 297 298 foreach ($element['children'] as $key=>$child) { 299 // If category is hidden then do not include it in the rowspan. 300 if ($child['type'] == 'category' && $child['object']->is_hidden() && !$this->canviewhidden 301 && ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN 302 || ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$child['object']->is_hiddenuntil()))) { 303 // Just calculate the rowspans for children of this category, don't add them to the count. 304 $this->inject_rowspans($element['children'][$key]); 305 } else { 306 $count += $this->inject_rowspans($element['children'][$key]); 307 } 308 } 309 310 $element['rowspan'] = $count; 311 return $count; 312 } 313 314 315 /** 316 * Prepares the headers and attributes of the flexitable. 317 */ 318 public function setup_table() { 319 /* 320 * Table has 1-8 columns 321 *| All columns except for itemname/description are optional 322 */ 323 324 // setting up table headers 325 326 $this->tablecolumns = array('itemname'); 327 $this->tableheaders = array($this->get_lang_string('gradeitem', 'grades')); 328 329 if ($this->showweight) { 330 $this->tablecolumns[] = 'weight'; 331 $this->tableheaders[] = $this->get_lang_string('weightuc', 'grades'); 332 } 333 334 if ($this->showgrade) { 335 $this->tablecolumns[] = 'grade'; 336 $this->tableheaders[] = $this->get_lang_string('grade', 'grades'); 337 } 338 339 if ($this->showrange) { 340 $this->tablecolumns[] = 'range'; 341 $this->tableheaders[] = $this->get_lang_string('range', 'grades'); 342 } 343 344 if ($this->showpercentage) { 345 $this->tablecolumns[] = 'percentage'; 346 $this->tableheaders[] = $this->get_lang_string('percentage', 'grades'); 347 } 348 349 if ($this->showlettergrade) { 350 $this->tablecolumns[] = 'lettergrade'; 351 $this->tableheaders[] = $this->get_lang_string('lettergrade', 'grades'); 352 } 353 354 if ($this->showrank) { 355 $this->tablecolumns[] = 'rank'; 356 $this->tableheaders[] = $this->get_lang_string('rank', 'grades'); 357 } 358 359 if ($this->showaverage) { 360 $this->tablecolumns[] = 'average'; 361 $this->tableheaders[] = $this->get_lang_string('average', 'grades'); 362 } 363 364 if ($this->showfeedback) { 365 $this->tablecolumns[] = 'feedback'; 366 $this->tableheaders[] = $this->get_lang_string('feedback', 'grades'); 367 } 368 369 if ($this->showcontributiontocoursetotal) { 370 $this->tablecolumns[] = 'contributiontocoursetotal'; 371 $this->tableheaders[] = $this->get_lang_string('contributiontocoursetotal', 'grades'); 372 } 373 } 374 375 function fill_table() { 376 //print "<pre>"; 377 //print_r($this->gtree->top_element); 378 $this->fill_table_recursive($this->gtree->top_element); 379 //print_r($this->tabledata); 380 //print "</pre>"; 381 return true; 382 } 383 384 /** 385 * Fill the table with data. 386 * 387 * @param $element - An array containing the table data for the current row. 388 */ 389 private function fill_table_recursive(&$element) { 390 global $DB, $CFG, $OUTPUT; 391 392 $type = $element['type']; 393 $depth = $element['depth']; 394 $grade_object = $element['object']; 395 $eid = $grade_object->id; 396 $element['userid'] = $this->user->id; 397 $fullname = $this->gtree->get_element_header($element, true, true, true, true, true); 398 $data = array(); 399 $gradeitemdata = array(); 400 $hidden = ''; 401 $excluded = ''; 402 $itemlevel = ($type == 'categoryitem' || $type == 'category' || $type == 'courseitem') ? $depth : ($depth + 1); 403 $class = 'level' . $itemlevel . ' level' . ($itemlevel % 2 ? 'odd' : 'even'); 404 $classfeedback = ''; 405 406 // If this is a hidden grade category, hide it completely from the user 407 if ($type == 'category' && $grade_object->is_hidden() && !$this->canviewhidden && ( 408 $this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN || 409 ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_object->is_hiddenuntil()))) { 410 return false; 411 } 412 413 if ($type == 'category') { 414 $this->evenodd[$depth] = (($this->evenodd[$depth] + 1) % 2); 415 } 416 $alter = ($this->evenodd[$depth] == 0) ? 'even' : 'odd'; 417 418 /// Process those items that have scores associated 419 if ($type == 'item' or $type == 'categoryitem' or $type == 'courseitem') { 420 $header_row = "row_{$eid}_{$this->user->id}"; 421 $header_cat = "cat_{$grade_object->categoryid}_{$this->user->id}"; 422 423 if (! $grade_grade = grade_grade::fetch(array('itemid'=>$grade_object->id,'userid'=>$this->user->id))) { 424 $grade_grade = new grade_grade(); 425 $grade_grade->userid = $this->user->id; 426 $grade_grade->itemid = $grade_object->id; 427 } 428 429 $grade_grade->load_grade_item(); 430 431 /// Hidden Items 432 if ($grade_grade->grade_item->is_hidden()) { 433 $hidden = ' dimmed_text'; 434 } 435 436 $hide = false; 437 // If this is a hidden grade item, hide it completely from the user. 438 if ($grade_grade->is_hidden() && !$this->canviewhidden && ( 439 $this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN || 440 ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_grade->is_hiddenuntil()))) { 441 $hide = true; 442 } else if (!empty($grade_object->itemmodule) && !empty($grade_object->iteminstance)) { 443 // The grade object can be marked visible but still be hidden if 444 // the student cannot see the activity due to conditional access 445 // and it's set to be hidden entirely. 446 $instances = $this->modinfo->get_instances_of($grade_object->itemmodule); 447 if (!empty($instances[$grade_object->iteminstance])) { 448 $cm = $instances[$grade_object->iteminstance]; 449 $gradeitemdata['cmid'] = $cm->id; 450 if (!$cm->uservisible) { 451 // If there is 'availableinfo' text then it is only greyed 452 // out and not entirely hidden. 453 if (!$cm->availableinfo) { 454 $hide = true; 455 } 456 } 457 } 458 } 459 460 // Actual Grade - We need to calculate this whether the row is hidden or not. 461 $gradeval = $grade_grade->finalgrade; 462 $hint = $grade_grade->get_aggregation_hint(); 463 if (!$this->canviewhidden) { 464 /// Virtual Grade (may be calculated excluding hidden items etc). 465 $adjustedgrade = $this->blank_hidden_total_and_adjust_bounds($this->courseid, 466 $grade_grade->grade_item, 467 $gradeval); 468 469 $gradeval = $adjustedgrade['grade']; 470 471 // We temporarily adjust the view of this grade item - because the min and 472 // max are affected by the hidden values in the aggregation. 473 $grade_grade->grade_item->grademax = $adjustedgrade['grademax']; 474 $grade_grade->grade_item->grademin = $adjustedgrade['grademin']; 475 $hint['status'] = $adjustedgrade['aggregationstatus']; 476 $hint['weight'] = $adjustedgrade['aggregationweight']; 477 } else { 478 // The max and min for an aggregation may be different to the grade_item. 479 if (!is_null($gradeval)) { 480 $grade_grade->grade_item->grademax = $grade_grade->get_grade_max(); 481 $grade_grade->grade_item->grademin = $grade_grade->get_grade_min(); 482 } 483 } 484 485 486 if (!$hide) { 487 /// Excluded Item 488 /** 489 if ($grade_grade->is_excluded()) { 490 $fullname .= ' ['.get_string('excluded', 'grades').']'; 491 $excluded = ' excluded'; 492 } 493 **/ 494 $canviewall = has_capability('moodle/grade:viewall', $this->context); 495 /// Other class information 496 $class .= $hidden . $excluded; 497 if ($this->switch) { // alter style based on whether aggregation is first or last 498 $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " ".$alter."d$depth baggt b2b" : " item b1b"; 499 } else { 500 $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " ".$alter."d$depth baggb" : " item b1b"; 501 } 502 if ($type == 'categoryitem' or $type == 'courseitem') { 503 $header_cat = "cat_{$grade_object->iteminstance}_{$this->user->id}"; 504 } 505 506 /// Name 507 $data['itemname']['content'] = $fullname; 508 $data['itemname']['class'] = $class; 509 $data['itemname']['colspan'] = ($this->maxdepth - $depth); 510 $data['itemname']['celltype'] = 'th'; 511 $data['itemname']['id'] = $header_row; 512 513 // Basic grade item information. 514 $gradeitemdata['id'] = $grade_object->id; 515 $gradeitemdata['itemname'] = $grade_object->itemname; 516 $gradeitemdata['itemtype'] = $grade_object->itemtype; 517 $gradeitemdata['itemmodule'] = $grade_object->itemmodule; 518 $gradeitemdata['iteminstance'] = $grade_object->iteminstance; 519 $gradeitemdata['itemnumber'] = $grade_object->itemnumber; 520 $gradeitemdata['idnumber'] = $grade_object->idnumber; 521 $gradeitemdata['categoryid'] = $grade_object->categoryid; 522 $gradeitemdata['outcomeid'] = $grade_object->outcomeid; 523 $gradeitemdata['scaleid'] = $grade_object->outcomeid; 524 $gradeitemdata['locked'] = $canviewall ? $grade_grade->grade_item->is_locked() : null; 525 526 if ($this->showfeedback) { 527 // Copy $class before appending itemcenter as feedback should not be centered 528 $classfeedback = $class; 529 } 530 $class .= " itemcenter "; 531 if ($this->showweight) { 532 $data['weight']['class'] = $class; 533 $data['weight']['content'] = '-'; 534 $data['weight']['headers'] = "$header_cat $header_row weight"; 535 // has a weight assigned, might be extra credit 536 537 // This obliterates the weight because it provides a more informative description. 538 if (is_numeric($hint['weight'])) { 539 $data['weight']['content'] = format_float($hint['weight'] * 100.0, 2) . ' %'; 540 $gradeitemdata['weightraw'] = $hint['weight']; 541 $gradeitemdata['weightformatted'] = $data['weight']['content']; 542 } 543 if ($hint['status'] != 'used' && $hint['status'] != 'unknown') { 544 $data['weight']['content'] .= '<br>' . get_string('aggregationhint' . $hint['status'], 'grades'); 545 $gradeitemdata['status'] = $hint['status']; 546 } 547 } 548 549 if ($this->showgrade) { 550 $gradeitemdata['graderaw'] = null; 551 $gradeitemdata['gradehiddenbydate'] = false; 552 $gradeitemdata['gradeneedsupdate'] = $grade_grade->grade_item->needsupdate; 553 $gradeitemdata['gradeishidden'] = $grade_grade->is_hidden(); 554 $gradeitemdata['gradedatesubmitted'] = $grade_grade->get_datesubmitted(); 555 $gradeitemdata['gradedategraded'] = $grade_grade->get_dategraded(); 556 $gradeitemdata['gradeislocked'] = $canviewall ? $grade_grade->is_locked() : null; 557 $gradeitemdata['gradeisoverridden'] = $canviewall ? $grade_grade->is_overridden() : null; 558 559 if ($grade_grade->grade_item->needsupdate) { 560 $data['grade']['class'] = $class.' gradingerror'; 561 $data['grade']['content'] = get_string('error'); 562 } else if (!empty($CFG->grade_hiddenasdate) and $grade_grade->get_datesubmitted() and !$this->canviewhidden and $grade_grade->is_hidden() 563 and !$grade_grade->grade_item->is_category_item() and !$grade_grade->grade_item->is_course_item()) { 564 // 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 565 $class .= ' datesubmitted'; 566 $data['grade']['class'] = $class; 567 $data['grade']['content'] = get_string('submittedon', 'grades', userdate($grade_grade->get_datesubmitted(), get_string('strftimedatetimeshort'))); 568 $gradeitemdata['gradehiddenbydate'] = true; 569 } else if ($grade_grade->is_hidden()) { 570 $data['grade']['class'] = $class.' dimmed_text'; 571 $data['grade']['content'] = '-'; 572 573 if ($this->canviewhidden) { 574 $gradeitemdata['graderaw'] = $gradeval; 575 $data['grade']['content'] = grade_format_gradevalue($gradeval, 576 $grade_grade->grade_item, 577 true); 578 } 579 } else { 580 $gradestatusclass = ''; 581 $gradepassicon = ''; 582 $ispassinggrade = $grade_grade->is_passed($grade_grade->grade_item); 583 if (!is_null($ispassinggrade)) { 584 $gradestatusclass = $ispassinggrade ? 'gradepass' : 'gradefail'; 585 if ($ispassinggrade) { 586 $gradepassicon = $OUTPUT->pix_icon('i/valid', get_string('pass', 'grades'), null, 587 array('class' => 'inline')); 588 } else { 589 $gradepassicon = $OUTPUT->pix_icon('i/invalid', get_string('fail', 'grades'), null, 590 array('class' => 'inline')); 591 } 592 } 593 594 $data['grade']['class'] = "{$class} {$gradestatusclass}"; 595 $data['grade']['content'] = $gradepassicon . grade_format_gradevalue($gradeval, 596 $grade_grade->grade_item, true); 597 $gradeitemdata['graderaw'] = $gradeval; 598 } 599 $data['grade']['headers'] = "$header_cat $header_row grade"; 600 $gradeitemdata['gradeformatted'] = $data['grade']['content']; 601 } 602 603 // Range 604 if ($this->showrange) { 605 $data['range']['class'] = $class; 606 $data['range']['content'] = $grade_grade->grade_item->get_formatted_range(GRADE_DISPLAY_TYPE_REAL, $this->rangedecimals); 607 $data['range']['headers'] = "$header_cat $header_row range"; 608 609 $gradeitemdata['rangeformatted'] = $data['range']['content']; 610 $gradeitemdata['grademin'] = $grade_grade->grade_item->grademin; 611 $gradeitemdata['grademax'] = $grade_grade->grade_item->grademax; 612 } 613 614 // Percentage 615 if ($this->showpercentage) { 616 if ($grade_grade->grade_item->needsupdate) { 617 $data['percentage']['class'] = $class.' gradingerror'; 618 $data['percentage']['content'] = get_string('error'); 619 } else if ($grade_grade->is_hidden()) { 620 $data['percentage']['class'] = $class.' dimmed_text'; 621 $data['percentage']['content'] = '-'; 622 if ($this->canviewhidden) { 623 $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE); 624 } 625 } else { 626 $data['percentage']['class'] = $class; 627 $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE); 628 } 629 $data['percentage']['headers'] = "$header_cat $header_row percentage"; 630 $gradeitemdata['percentageformatted'] = $data['percentage']['content']; 631 } 632 633 // Lettergrade 634 if ($this->showlettergrade) { 635 if ($grade_grade->grade_item->needsupdate) { 636 $data['lettergrade']['class'] = $class.' gradingerror'; 637 $data['lettergrade']['content'] = get_string('error'); 638 } else if ($grade_grade->is_hidden()) { 639 $data['lettergrade']['class'] = $class.' dimmed_text'; 640 if (!$this->canviewhidden) { 641 $data['lettergrade']['content'] = '-'; 642 } else { 643 $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER); 644 } 645 } else { 646 $data['lettergrade']['class'] = $class; 647 $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER); 648 } 649 $data['lettergrade']['headers'] = "$header_cat $header_row lettergrade"; 650 $gradeitemdata['lettergradeformatted'] = $data['lettergrade']['content']; 651 } 652 653 // Rank 654 if ($this->showrank) { 655 $gradeitemdata['rank'] = 0; 656 if ($grade_grade->grade_item->needsupdate) { 657 $data['rank']['class'] = $class.' gradingerror'; 658 $data['rank']['content'] = get_string('error'); 659 } elseif ($grade_grade->is_hidden()) { 660 $data['rank']['class'] = $class.' dimmed_text'; 661 $data['rank']['content'] = '-'; 662 } else if (is_null($gradeval)) { 663 // no grade, no rank 664 $data['rank']['class'] = $class; 665 $data['rank']['content'] = '-'; 666 667 } else { 668 /// find the number of users with a higher grade 669 $sql = "SELECT COUNT(DISTINCT(userid)) 670 FROM {grade_grades} 671 WHERE finalgrade > ? 672 AND itemid = ? 673 AND hidden = 0"; 674 $rank = $DB->count_records_sql($sql, array($grade_grade->finalgrade, $grade_grade->grade_item->id)) + 1; 675 676 $data['rank']['class'] = $class; 677 $numusers = $this->get_numusers(false); 678 $data['rank']['content'] = "$rank/$numusers"; // Total course users. 679 680 $gradeitemdata['rank'] = $rank; 681 $gradeitemdata['numusers'] = $numusers; 682 } 683 $data['rank']['headers'] = "$header_cat $header_row rank"; 684 } 685 686 // Average 687 if ($this->showaverage) { 688 $gradeitemdata['averageformatted'] = ''; 689 690 $data['average']['class'] = $class; 691 if (!empty($this->gtree->items[$eid]->avg)) { 692 $data['average']['content'] = $this->gtree->items[$eid]->avg; 693 $gradeitemdata['averageformatted'] = $this->gtree->items[$eid]->avg; 694 } else { 695 $data['average']['content'] = '-'; 696 } 697 $data['average']['headers'] = "$header_cat $header_row average"; 698 } 699 700 // Feedback 701 if ($this->showfeedback) { 702 $gradeitemdata['feedback'] = ''; 703 $gradeitemdata['feedbackformat'] = $grade_grade->feedbackformat; 704 705 if ($grade_grade->feedback) { 706 $grade_grade->feedback = file_rewrite_pluginfile_urls( 707 $grade_grade->feedback, 708 'pluginfile.php', 709 $grade_grade->get_context()->id, 710 GRADE_FILE_COMPONENT, 711 GRADE_FEEDBACK_FILEAREA, 712 $grade_grade->id 713 ); 714 } 715 716 if ($grade_grade->overridden > 0 AND ($type == 'categoryitem' OR $type == 'courseitem')) { 717 $data['feedback']['class'] = $classfeedback.' feedbacktext'; 718 $data['feedback']['content'] = get_string('overridden', 'grades').': ' . 719 format_text($grade_grade->feedback, $grade_grade->feedbackformat, 720 ['context' => $grade_grade->get_context()]); 721 $gradeitemdata['feedback'] = $grade_grade->feedback; 722 } else if (empty($grade_grade->feedback) or (!$this->canviewhidden and $grade_grade->is_hidden())) { 723 $data['feedback']['class'] = $classfeedback.' feedbacktext'; 724 $data['feedback']['content'] = ' '; 725 } else { 726 $data['feedback']['class'] = $classfeedback.' feedbacktext'; 727 $data['feedback']['content'] = format_text($grade_grade->feedback, $grade_grade->feedbackformat, 728 ['context' => $grade_grade->get_context()]); 729 $gradeitemdata['feedback'] = $grade_grade->feedback; 730 } 731 $data['feedback']['headers'] = "$header_cat $header_row feedback"; 732 } 733 // Contribution to the course total column. 734 if ($this->showcontributiontocoursetotal) { 735 $data['contributiontocoursetotal']['class'] = $class; 736 $data['contributiontocoursetotal']['content'] = '-'; 737 $data['contributiontocoursetotal']['headers'] = "$header_cat $header_row contributiontocoursetotal"; 738 739 } 740 $this->gradeitemsdata[] = $gradeitemdata; 741 } 742 // We collect the aggregation hints whether they are hidden or not. 743 if ($this->showcontributiontocoursetotal) { 744 $hint['grademax'] = $grade_grade->grade_item->grademax; 745 $hint['grademin'] = $grade_grade->grade_item->grademin; 746 $hint['grade'] = $gradeval; 747 $parent = $grade_object->load_parent_category(); 748 if ($grade_object->is_category_item()) { 749 $parent = $parent->load_parent_category(); 750 } 751 $hint['parent'] = $parent->load_grade_item()->id; 752 $this->aggregationhints[$grade_grade->itemid] = $hint; 753 } 754 } 755 756 /// Category 757 if ($type == 'category') { 758 $data['leader']['class'] = $class.' '.$alter."d$depth b1t b2b b1l"; 759 $data['leader']['rowspan'] = $element['rowspan']; 760 761 if ($this->switch) { // alter style based on whether aggregation is first or last 762 $data['itemname']['class'] = $class.' '.$alter."d$depth b1b b1t"; 763 } else { 764 $data['itemname']['class'] = $class.' '.$alter."d$depth b2t"; 765 } 766 $data['itemname']['colspan'] = ($this->maxdepth - $depth + count($this->tablecolumns) - 1); 767 $data['itemname']['content'] = $fullname; 768 $data['itemname']['celltype'] = 'th'; 769 $data['itemname']['id'] = "cat_{$grade_object->id}_{$this->user->id}"; 770 } 771 772 /// Add this row to the overall system 773 foreach ($data as $key => $celldata) { 774 $data[$key]['class'] .= ' column-' . $key; 775 } 776 $this->tabledata[] = $data; 777 778 /// Recursively iterate through all child elements 779 if (isset($element['children'])) { 780 foreach ($element['children'] as $key=>$child) { 781 $this->fill_table_recursive($element['children'][$key]); 782 } 783 } 784 785 // Check we are showing this column, and we are looking at the root of the table. 786 // This should be the very last thing this fill_table_recursive function does. 787 if ($this->showcontributiontocoursetotal && ($type == 'category' && $depth == 1)) { 788 // We should have collected all the hints by now - walk the tree again and build the contributions column. 789 790 $this->fill_contributions_column($element); 791 } 792 } 793 794 /** 795 * This function is called after the table has been built and the aggregationhints 796 * have been collected. We need this info to walk up the list of parents of each 797 * grade_item. 798 * 799 * @param $element - An array containing the table data for the current row. 800 */ 801 public function fill_contributions_column($element) { 802 803 // Recursively iterate through all child elements. 804 if (isset($element['children'])) { 805 foreach ($element['children'] as $key=>$child) { 806 $this->fill_contributions_column($element['children'][$key]); 807 } 808 } else if ($element['type'] == 'item') { 809 // This is a grade item (We don't do this for categories or we would double count). 810 $grade_object = $element['object']; 811 $itemid = $grade_object->id; 812 813 // Ignore anything with no hint - e.g. a hidden row. 814 if (isset($this->aggregationhints[$itemid])) { 815 816 // Normalise the gradeval. 817 $gradecat = $grade_object->load_parent_category(); 818 if ($gradecat->aggregation == GRADE_AGGREGATE_SUM) { 819 // Natural aggregation/Sum of grades does not consider the mingrade, cannot traditionnally normalise it. 820 $graderange = $this->aggregationhints[$itemid]['grademax']; 821 822 if ($graderange != 0) { 823 $gradeval = $this->aggregationhints[$itemid]['grade'] / $graderange; 824 } else { 825 $gradeval = 0; 826 } 827 } else { 828 $gradeval = grade_grade::standardise_score($this->aggregationhints[$itemid]['grade'], 829 $this->aggregationhints[$itemid]['grademin'], $this->aggregationhints[$itemid]['grademax'], 0, 1); 830 } 831 832 // Multiply the normalised value by the weight 833 // of all the categories higher in the tree. 834 $parent = null; 835 do { 836 if (!is_null($this->aggregationhints[$itemid]['weight'])) { 837 $gradeval *= $this->aggregationhints[$itemid]['weight']; 838 } else if (empty($parent)) { 839 // If we are in the first loop, and the weight is null, then we cannot calculate the contribution. 840 $gradeval = null; 841 break; 842 } 843 844 // The second part of this if is to prevent infinite loops 845 // in case of crazy data. 846 if (isset($this->aggregationhints[$itemid]['parent']) && 847 $this->aggregationhints[$itemid]['parent'] != $itemid) { 848 $parent = $this->aggregationhints[$itemid]['parent']; 849 $itemid = $parent; 850 } else { 851 // We are at the top of the tree. 852 $parent = false; 853 } 854 } while ($parent); 855 856 // Finally multiply by the course grademax. 857 if (!is_null($gradeval)) { 858 // Convert to percent. 859 $gradeval *= 100; 860 } 861 862 // Now we need to loop through the "built" table data and update the 863 // contributions column for the current row. 864 $header_row = "row_{$grade_object->id}_{$this->user->id}"; 865 foreach ($this->tabledata as $key => $row) { 866 if (isset($row['itemname']) && ($row['itemname']['id'] == $header_row)) { 867 // Found it - update the column. 868 $content = '-'; 869 if (!is_null($gradeval)) { 870 $decimals = $grade_object->get_decimals(); 871 $content = format_float($gradeval, $decimals, true) . ' %'; 872 } 873 $this->tabledata[$key]['contributiontocoursetotal']['content'] = $content; 874 break; 875 } 876 } 877 } 878 } 879 } 880 881 /** 882 * Prints or returns the HTML from the flexitable. 883 * @param bool $return Whether or not to return the data instead of printing it directly. 884 * @return string 885 */ 886 public function print_table($return=false) { 887 $maxspan = $this->maxdepth; 888 889 /// Build table structure 890 $html = " 891 <table cellspacing='0' 892 cellpadding='0' 893 summary='" . s($this->get_lang_string('tablesummary', 'gradereport_user')) . "' 894 class='boxaligncenter generaltable user-grade'> 895 <thead> 896 <tr> 897 <th id='".$this->tablecolumns[0]."' class=\"header column-{$this->tablecolumns[0]}\" colspan='$maxspan'>".$this->tableheaders[0]."</th>\n"; 898 899 for ($i = 1; $i < count($this->tableheaders); $i++) { 900 $html .= "<th id='".$this->tablecolumns[$i]."' class=\"header column-{$this->tablecolumns[$i]}\">".$this->tableheaders[$i]."</th>\n"; 901 } 902 903 $html .= " 904 </tr> 905 </thead> 906 <tbody>\n"; 907 908 /// Print out the table data 909 for ($i = 0; $i < count($this->tabledata); $i++) { 910 $html .= "<tr>\n"; 911 if (isset($this->tabledata[$i]['leader'])) { 912 $rowspan = $this->tabledata[$i]['leader']['rowspan']; 913 $class = $this->tabledata[$i]['leader']['class']; 914 $html .= "<td class='$class' rowspan='$rowspan'></td>\n"; 915 } 916 for ($j = 0; $j < count($this->tablecolumns); $j++) { 917 $name = $this->tablecolumns[$j]; 918 $class = (isset($this->tabledata[$i][$name]['class'])) ? $this->tabledata[$i][$name]['class'] : ''; 919 $colspan = (isset($this->tabledata[$i][$name]['colspan'])) ? "colspan='".$this->tabledata[$i][$name]['colspan']."'" : ''; 920 $content = (isset($this->tabledata[$i][$name]['content'])) ? $this->tabledata[$i][$name]['content'] : null; 921 $celltype = (isset($this->tabledata[$i][$name]['celltype'])) ? $this->tabledata[$i][$name]['celltype'] : 'td'; 922 $id = (isset($this->tabledata[$i][$name]['id'])) ? "id='{$this->tabledata[$i][$name]['id']}'" : ''; 923 $headers = (isset($this->tabledata[$i][$name]['headers'])) ? "headers='{$this->tabledata[$i][$name]['headers']}'" : ''; 924 if (isset($content)) { 925 $html .= "<$celltype $id $headers class='$class' $colspan>$content</$celltype>\n"; 926 } 927 } 928 $html .= "</tr>\n"; 929 } 930 931 $html .= "</tbody></table>"; 932 933 if ($return) { 934 return $html; 935 } else { 936 echo $html; 937 } 938 } 939 940 /** 941 * Processes the data sent by the form (grades and feedbacks). 942 * @var array $data 943 * @return bool Success or Failure (array of errors). 944 */ 945 function process_data($data) { 946 } 947 function process_action($target, $action) { 948 } 949 950 /** 951 * Builds the grade item averages. 952 */ 953 function calculate_averages() { 954 global $USER, $DB, $CFG; 955 956 if ($this->showaverage) { 957 // This settings are actually grader report settings (not user report) 958 // however we're using them as having two separate but identical settings the 959 // user would have to keep in sync would be annoying. 960 $averagesdisplaytype = $this->get_pref('averagesdisplaytype'); 961 $averagesdecimalpoints = $this->get_pref('averagesdecimalpoints'); 962 $meanselection = $this->get_pref('meanselection'); 963 $shownumberofgrades = $this->get_pref('shownumberofgrades'); 964 965 $avghtml = ''; 966 $groupsql = $this->groupsql; 967 $groupwheresql = $this->groupwheresql; 968 $totalcount = $this->get_numusers(false); 969 970 // We want to query both the current context and parent contexts. 971 list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($this->context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'relatedctx'); 972 973 // Limit to users with a gradeable role ie students. 974 list($gradebookrolessql, $gradebookrolesparams) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0'); 975 976 // Limit to users with an active enrolment. 977 $coursecontext = $this->context->get_course_context(true); 978 $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol); 979 $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol); 980 $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $coursecontext); 981 list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->context, '', 0, $showonlyactiveenrol); 982 983 $params = array_merge($this->groupwheresql_params, $gradebookrolesparams, $enrolledparams, $relatedctxparams); 984 $params['courseid'] = $this->courseid; 985 986 // find sums of all grade items in course 987 $sql = "SELECT gg.itemid, SUM(gg.finalgrade) AS sum 988 FROM {grade_items} gi 989 JOIN {grade_grades} gg ON gg.itemid = gi.id 990 JOIN {user} u ON u.id = gg.userid 991 JOIN ($enrolledsql) je ON je.id = gg.userid 992 JOIN ( 993 SELECT DISTINCT ra.userid 994 FROM {role_assignments} ra 995 WHERE ra.roleid $gradebookrolessql 996 AND ra.contextid $relatedctxsql 997 ) rainner ON rainner.userid = u.id 998 $groupsql 999 WHERE gi.courseid = :courseid 1000 AND u.deleted = 0 1001 AND gg.finalgrade IS NOT NULL 1002 AND gg.hidden = 0 1003 $groupwheresql 1004 GROUP BY gg.itemid"; 1005 1006 $sum_array = array(); 1007 $sums = $DB->get_recordset_sql($sql, $params); 1008 foreach ($sums as $itemid => $csum) { 1009 $sum_array[$itemid] = $csum->sum; 1010 } 1011 $sums->close(); 1012 1013 $columncount=0; 1014 1015 // Empty grades must be evaluated as grademin, NOT always 0 1016 // This query returns a count of ungraded grades (NULL finalgrade OR no matching record in grade_grades table) 1017 // No join condition when joining grade_items and user to get a grade item row for every user 1018 // Then left join with grade_grades and look for rows with null final grade (which includes grade items with no grade_grade) 1019 $sql = "SELECT gi.id, COUNT(u.id) AS count 1020 FROM {grade_items} gi 1021 JOIN {user} u ON u.deleted = 0 1022 JOIN ($enrolledsql) je ON je.id = u.id 1023 JOIN ( 1024 SELECT DISTINCT ra.userid 1025 FROM {role_assignments} ra 1026 WHERE ra.roleid $gradebookrolessql 1027 AND ra.contextid $relatedctxsql 1028 ) rainner ON rainner.userid = u.id 1029 LEFT JOIN {grade_grades} gg 1030 ON (gg.itemid = gi.id AND gg.userid = u.id AND gg.finalgrade IS NOT NULL AND gg.hidden = 0) 1031 $groupsql 1032 WHERE gi.courseid = :courseid 1033 AND gg.finalgrade IS NULL 1034 $groupwheresql 1035 GROUP BY gi.id"; 1036 1037 $ungraded_counts = $DB->get_records_sql($sql, $params); 1038 1039 foreach ($this->gtree->items as $itemid=>$unused) { 1040 if (!empty($this->gtree->items[$itemid]->avg)) { 1041 continue; 1042 } 1043 $item = $this->gtree->items[$itemid]; 1044 1045 if ($item->needsupdate) { 1046 $avghtml .= '<td class="cell c' . $columncount++.'"><span class="gradingerror">'.get_string('error').'</span></td>'; 1047 continue; 1048 } 1049 1050 if (empty($sum_array[$item->id])) { 1051 $sum_array[$item->id] = 0; 1052 } 1053 1054 if (empty($ungraded_counts[$itemid])) { 1055 $ungraded_count = 0; 1056 } else { 1057 $ungraded_count = $ungraded_counts[$itemid]->count; 1058 } 1059 1060 //do they want the averages to include all grade items 1061 if ($meanselection == GRADE_REPORT_MEAN_GRADED) { 1062 $mean_count = $totalcount - $ungraded_count; 1063 } else { // Bump up the sum by the number of ungraded items * grademin 1064 $sum_array[$item->id] += ($ungraded_count * $item->grademin); 1065 $mean_count = $totalcount; 1066 } 1067 1068 // Determine which display type to use for this average 1069 if (isset($USER->editing) && $USER->editing) { 1070 $displaytype = GRADE_DISPLAY_TYPE_REAL; 1071 1072 } else if ($averagesdisplaytype == GRADE_REPORT_PREFERENCE_INHERIT) { // no ==0 here, please resave the report and user preferences 1073 $displaytype = $item->get_displaytype(); 1074 1075 } else { 1076 $displaytype = $averagesdisplaytype; 1077 } 1078 1079 // Override grade_item setting if a display preference (not inherit) was set for the averages 1080 if ($averagesdecimalpoints == GRADE_REPORT_PREFERENCE_INHERIT) { 1081 $decimalpoints = $item->get_decimals(); 1082 } else { 1083 $decimalpoints = $averagesdecimalpoints; 1084 } 1085 1086 if (empty($sum_array[$item->id]) || $mean_count == 0) { 1087 $this->gtree->items[$itemid]->avg = '-'; 1088 } else { 1089 $sum = $sum_array[$item->id]; 1090 $avgradeval = $sum/$mean_count; 1091 $gradehtml = grade_format_gradevalue($avgradeval, $item, true, $displaytype, $decimalpoints); 1092 1093 $numberofgrades = ''; 1094 if ($shownumberofgrades) { 1095 $numberofgrades = " ($mean_count)"; 1096 } 1097 1098 $this->gtree->items[$itemid]->avg = $gradehtml.$numberofgrades; 1099 } 1100 } 1101 } 1102 } 1103 1104 /** 1105 * Trigger the grade_report_viewed event 1106 * 1107 * @since Moodle 2.9 1108 */ 1109 public function viewed() { 1110 $event = \gradereport_user\event\grade_report_viewed::create( 1111 array( 1112 'context' => $this->context, 1113 'courseid' => $this->courseid, 1114 'relateduserid' => $this->user->id, 1115 ) 1116 ); 1117 $event->trigger(); 1118 } 1119 } 1120 1121 function grade_report_user_settings_definition(&$mform) { 1122 global $CFG; 1123 1124 $options = array(-1 => get_string('default', 'grades'), 1125 0 => get_string('hide'), 1126 1 => get_string('show')); 1127 1128 if (empty($CFG->grade_report_user_showrank)) { 1129 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1130 } else { 1131 $options[-1] = get_string('defaultprev', 'grades', $options[1]); 1132 } 1133 1134 $mform->addElement('select', 'report_user_showrank', get_string('showrank', 'grades'), $options); 1135 $mform->addHelpButton('report_user_showrank', 'showrank', 'grades'); 1136 1137 if (empty($CFG->grade_report_user_showpercentage)) { 1138 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1139 } else { 1140 $options[-1] = get_string('defaultprev', 'grades', $options[1]); 1141 } 1142 1143 $mform->addElement('select', 'report_user_showpercentage', get_string('showpercentage', 'grades'), $options); 1144 $mform->addHelpButton('report_user_showpercentage', 'showpercentage', 'grades'); 1145 1146 if (empty($CFG->grade_report_user_showgrade)) { 1147 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1148 } else { 1149 $options[-1] = get_string('defaultprev', 'grades', $options[1]); 1150 } 1151 1152 $mform->addElement('select', 'report_user_showgrade', get_string('showgrade', 'grades'), $options); 1153 1154 if (empty($CFG->grade_report_user_showfeedback)) { 1155 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1156 } else { 1157 $options[-1] = get_string('defaultprev', 'grades', $options[1]); 1158 } 1159 1160 $mform->addElement('select', 'report_user_showfeedback', get_string('showfeedback', 'grades'), $options); 1161 1162 if (empty($CFG->grade_report_user_showweight)) { 1163 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1164 } else { 1165 $options[-1] = get_string('defaultprev', 'grades', $options[1]); 1166 } 1167 1168 $mform->addElement('select', 'report_user_showweight', get_string('showweight', 'grades'), $options); 1169 1170 if (empty($CFG->grade_report_user_showaverage)) { 1171 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1172 } else { 1173 $options[-1] = get_string('defaultprev', 'grades', $options[1]); 1174 } 1175 1176 $mform->addElement('select', 'report_user_showaverage', get_string('showaverage', 'grades'), $options); 1177 $mform->addHelpButton('report_user_showaverage', 'showaverage', 'grades'); 1178 1179 if (empty($CFG->grade_report_user_showlettergrade)) { 1180 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1181 } else { 1182 $options[-1] = get_string('defaultprev', 'grades', $options[1]); 1183 } 1184 1185 $mform->addElement('select', 'report_user_showlettergrade', get_string('showlettergrade', 'grades'), $options); 1186 if (empty($CFG->grade_report_user_showcontributiontocoursetotal)) { 1187 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1188 } else { 1189 $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_user_showcontributiontocoursetotal]); 1190 } 1191 1192 $mform->addElement('select', 'report_user_showcontributiontocoursetotal', get_string('showcontributiontocoursetotal', 'grades'), $options); 1193 $mform->addHelpButton('report_user_showcontributiontocoursetotal', 'showcontributiontocoursetotal', 'grades'); 1194 1195 if (empty($CFG->grade_report_user_showrange)) { 1196 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1197 } else { 1198 $options[-1] = get_string('defaultprev', 'grades', $options[1]); 1199 } 1200 1201 $mform->addElement('select', 'report_user_showrange', get_string('showrange', 'grades'), $options); 1202 1203 $options = array(0=>0, 1=>1, 2=>2, 3=>3, 4=>4, 5=>5); 1204 if (! empty($CFG->grade_report_user_rangedecimals)) { 1205 $options[-1] = $options[$CFG->grade_report_user_rangedecimals]; 1206 } 1207 $mform->addElement('select', 'report_user_rangedecimals', get_string('rangedecimals', 'grades'), $options); 1208 1209 $options = array(-1 => get_string('default', 'grades'), 1210 0 => get_string('shownohidden', 'grades'), 1211 1 => get_string('showhiddenuntilonly', 'grades'), 1212 2 => get_string('showallhidden', 'grades')); 1213 1214 if (empty($CFG->grade_report_user_showhiddenitems)) { 1215 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1216 } else { 1217 $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_user_showhiddenitems]); 1218 } 1219 1220 $mform->addElement('select', 'report_user_showhiddenitems', get_string('showhiddenitems', 'grades'), $options); 1221 $mform->addHelpButton('report_user_showhiddenitems', 'showhiddenitems', 'grades'); 1222 1223 //showtotalsifcontainhidden 1224 $options = array(-1 => get_string('default', 'grades'), 1225 GRADE_REPORT_HIDE_TOTAL_IF_CONTAINS_HIDDEN => get_string('hide'), 1226 GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowexhiddenitems', 'grades'), 1227 GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowinchiddenitems', 'grades') ); 1228 1229 if (empty($CFG->grade_report_user_showtotalsifcontainhidden)) { 1230 $options[-1] = get_string('defaultprev', 'grades', $options[0]); 1231 } else { 1232 $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_user_showtotalsifcontainhidden]); 1233 } 1234 1235 $mform->addElement('select', 'report_user_showtotalsifcontainhidden', get_string('hidetotalifhiddenitems', 'grades'), $options); 1236 $mform->addHelpButton('report_user_showtotalsifcontainhidden', 'hidetotalifhiddenitems', 'grades'); 1237 1238 } 1239 1240 /** 1241 * Profile report callback. 1242 * 1243 * @param object $course The course. 1244 * @param object $user The user. 1245 * @param boolean $viewasuser True when we are viewing this as the targetted user sees it. 1246 */ 1247 function grade_report_user_profilereport($course, $user, $viewasuser = false) { 1248 global $OUTPUT; 1249 if (!empty($course->showgrades)) { 1250 1251 $context = context_course::instance($course->id); 1252 1253 /// return tracking object 1254 $gpr = new grade_plugin_return(array('type'=>'report', 'plugin'=>'user', 'courseid'=>$course->id, 'userid'=>$user->id)); 1255 // Create a report instance 1256 $report = new grade_report_user($course->id, $gpr, $context, $user->id, $viewasuser); 1257 1258 // print the page 1259 echo '<div class="grade-report-user">'; // css fix to share styles with real report page 1260 if ($report->fill_table()) { 1261 echo $report->print_table(true); 1262 } 1263 echo '</div>'; 1264 } 1265 } 1266 1267 /** 1268 * Add nodes to myprofile page. 1269 * 1270 * @param \core_user\output\myprofile\tree $tree Tree object 1271 * @param stdClass $user user object 1272 * @param bool $iscurrentuser 1273 * @param stdClass $course Course object 1274 */ 1275 function gradereport_user_myprofile_navigation(core_user\output\myprofile\tree $tree, $user, $iscurrentuser, $course) { 1276 global $CFG, $USER; 1277 if (empty($course)) { 1278 // We want to display these reports under the site context. 1279 $course = get_fast_modinfo(SITEID)->get_course(); 1280 } 1281 $usercontext = context_user::instance($user->id); 1282 $anyreport = has_capability('moodle/user:viewuseractivitiesreport', $usercontext); 1283 1284 // Start capability checks. 1285 if ($anyreport || $iscurrentuser) { 1286 // Add grade hardcoded grade report if necessary. 1287 $gradeaccess = false; 1288 $coursecontext = context_course::instance($course->id); 1289 if (has_capability('moodle/grade:viewall', $coursecontext)) { 1290 // Can view all course grades. 1291 $gradeaccess = true; 1292 } else if ($course->showgrades) { 1293 if ($iscurrentuser && has_capability('moodle/grade:view', $coursecontext)) { 1294 // Can view own grades. 1295 $gradeaccess = true; 1296 } else if (has_capability('moodle/grade:viewall', $usercontext)) { 1297 // Can view grades of this user - parent most probably. 1298 $gradeaccess = true; 1299 } else if ($anyreport) { 1300 // Can view grades of this user - parent most probably. 1301 $gradeaccess = true; 1302 } 1303 } 1304 if ($gradeaccess) { 1305 $url = new moodle_url('/course/user.php', array('mode' => 'grade', 'id' => $course->id, 'user' => $user->id)); 1306 $node = new core_user\output\myprofile\node('reports', 'grade', get_string('grades'), null, $url); 1307 $tree->add_node($node); 1308 } 1309 } 1310 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body