[ Index ] |
PHP Cross Reference of Unnamed Project |
[Summary view] [Print] [Text view]
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 * File containing the grade_report class 19 * 20 * @package core_grades 21 * @copyright 2007 Moodle Pty Ltd (http://moodle.com) 22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 23 */ 24 25 require_once($CFG->libdir.'/gradelib.php'); 26 27 /** 28 * An abstract class containing variables and methods used by all or most reports. 29 * @copyright 2007 Moodle Pty Ltd (http://moodle.com) 30 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 31 */ 32 abstract class grade_report { 33 /** 34 * The courseid. 35 * @var int $courseid 36 */ 37 public $courseid; 38 39 /** 40 * The course. 41 * @var object $course 42 */ 43 public $course; 44 45 /** Grade plugin return tracking object. 46 * @var object $gpr 47 */ 48 public $gpr; 49 50 /** 51 * The context. 52 * @var int $context 53 */ 54 public $context; 55 56 /** 57 * The grade_tree object. 58 * @var grade_tree $gtree 59 */ 60 public $gtree; 61 62 /** 63 * User preferences related to this report. 64 * @var array $prefs 65 */ 66 public $prefs = array(); 67 68 /** 69 * The roles for this report. 70 * @var string $gradebookroles 71 */ 72 public $gradebookroles; 73 74 /** 75 * base url for sorting by first/last name. 76 * @var string $baseurl 77 */ 78 public $baseurl; 79 80 /** 81 * base url for paging. 82 * @var string $pbarurl 83 */ 84 public $pbarurl; 85 86 /** 87 * Current page (for paging). 88 * @var int $page 89 */ 90 public $page; 91 92 /** 93 * Array of cached language strings (using get_string() all the time takes a long time!). 94 * @var array $lang_strings 95 */ 96 public $lang_strings = array(); 97 98 // GROUP VARIABLES (including SQL) 99 100 /** 101 * The current group being displayed. 102 * @var int $currentgroup 103 */ 104 public $currentgroup; 105 106 /** 107 * The current groupname being displayed. 108 * @var string $currentgroupname 109 */ 110 public $currentgroupname; 111 112 /** 113 * Current course group mode 114 * @var int $groupmode 115 */ 116 public $groupmode; 117 118 /** 119 * A HTML select element used to select the current group. 120 * @var string $group_selector 121 */ 122 public $group_selector; 123 124 /** 125 * An SQL fragment used to add linking information to the group tables. 126 * @var string $groupsql 127 */ 128 protected $groupsql; 129 130 /** 131 * An SQL constraint to append to the queries used by this object to build the report. 132 * @var string $groupwheresql 133 */ 134 protected $groupwheresql; 135 136 /** 137 * The ordered params for $groupwheresql 138 * @var array $groupwheresql_params 139 */ 140 protected $groupwheresql_params = array(); 141 142 // USER VARIABLES (including SQL). 143 144 /** 145 * An SQL constraint to append to the queries used by this object to build the report. 146 * @var string $userwheresql 147 */ 148 protected $userwheresql; 149 150 /** 151 * The ordered params for $userwheresql 152 * @var array $userwheresql_params 153 */ 154 protected $userwheresql_params = array(); 155 156 /** 157 * Constructor. Sets local copies of user preferences and initialises grade_tree. 158 * @param int $courseid 159 * @param object $gpr grade plugin return tracking object 160 * @param string $context 161 * @param int $page The current page being viewed (when report is paged) 162 */ 163 public function __construct($courseid, $gpr, $context, $page=null) { 164 global $CFG, $COURSE, $DB; 165 166 if (empty($CFG->gradebookroles)) { 167 print_error('norolesdefined', 'grades'); 168 } 169 170 $this->courseid = $courseid; 171 if ($this->courseid == $COURSE->id) { 172 $this->course = $COURSE; 173 } else { 174 $this->course = $DB->get_record('course', array('id' => $this->courseid)); 175 } 176 177 $this->gpr = $gpr; 178 $this->context = $context; 179 $this->page = $page; 180 181 // roles to be displayed in the gradebook 182 $this->gradebookroles = $CFG->gradebookroles; 183 184 // Set up link to preferences page 185 $this->preferences_page = $CFG->wwwroot.'/grade/report/grader/preferences.php?id='.$courseid; 186 187 // init gtree in child class 188 } 189 190 /** 191 * Given the name of a user preference (without grade_report_ prefix), locally saves then returns 192 * the value of that preference. If the preference has already been fetched before, 193 * the saved value is returned. If the preference is not set at the User level, the $CFG equivalent 194 * is given (site default). 195 * Can be called statically, but then doesn't benefit from caching 196 * @param string $pref The name of the preference (do not include the grade_report_ prefix) 197 * @param int $objectid An optional itemid or categoryid to check for a more fine-grained preference 198 * @return mixed The value of the preference 199 */ 200 public function get_pref($pref, $objectid=null) { 201 global $CFG; 202 $fullprefname = 'grade_report_' . $pref; 203 $shortprefname = 'grade_' . $pref; 204 205 $retval = null; 206 207 if (!isset($this) OR get_class($this) != 'grade_report') { 208 if (!empty($objectid)) { 209 $retval = get_user_preferences($fullprefname . $objectid, self::get_pref($pref)); 210 } else if (isset($CFG->$fullprefname)) { 211 $retval = get_user_preferences($fullprefname, $CFG->$fullprefname); 212 } else if (isset($CFG->$shortprefname)) { 213 $retval = get_user_preferences($fullprefname, $CFG->$shortprefname); 214 } else { 215 $retval = null; 216 } 217 } else { 218 if (empty($this->prefs[$pref.$objectid])) { 219 220 if (!empty($objectid)) { 221 $retval = get_user_preferences($fullprefname . $objectid); 222 if (empty($retval)) { 223 // No item pref found, we are returning the global preference 224 $retval = $this->get_pref($pref); 225 $objectid = null; 226 } 227 } else { 228 $retval = get_user_preferences($fullprefname, $CFG->$fullprefname); 229 } 230 $this->prefs[$pref.$objectid] = $retval; 231 } else { 232 $retval = $this->prefs[$pref.$objectid]; 233 } 234 } 235 236 return $retval; 237 } 238 239 /** 240 * Uses set_user_preferences() to update the value of a user preference. If 'default' is given as the value, 241 * the preference will be removed in favour of a higher-level preference. 242 * @param string $pref The name of the preference. 243 * @param mixed $pref_value The value of the preference. 244 * @param int $itemid An optional itemid to which the preference will be assigned 245 * @return bool Success or failure. 246 */ 247 public function set_pref($pref, $pref_value='default', $itemid=null) { 248 $fullprefname = 'grade_report_' . $pref; 249 if ($pref_value == 'default') { 250 return unset_user_preference($fullprefname.$itemid); 251 } else { 252 return set_user_preference($fullprefname.$itemid, $pref_value); 253 } 254 } 255 256 /** 257 * Handles form data sent by this report for this report. Abstract method to implement in all children. 258 * @abstract 259 * @param array $data 260 * @return mixed True or array of errors 261 */ 262 abstract public function process_data($data); 263 264 /** 265 * Processes a single action against a category, grade_item or grade. 266 * @param string $target Sortorder 267 * @param string $action Which action to take (edit, delete etc...) 268 * @return 269 */ 270 abstract public function process_action($target, $action); 271 272 /** 273 * First checks the cached language strings, then returns match if found, or uses get_string() 274 * to get it from the DB, caches it then returns it. 275 * @param string $strcode 276 * @param string $section Optional language section 277 * @return string 278 */ 279 public function get_lang_string($strcode, $section=null) { 280 if (empty($this->lang_strings[$strcode])) { 281 $this->lang_strings[$strcode] = get_string($strcode, $section); 282 } 283 return $this->lang_strings[$strcode]; 284 } 285 286 /** 287 * Fetches and returns a count of all the users that will be shown on this page. 288 * @param boolean $groups include groups limit 289 * @param boolean $users include users limit - default false, used for searching purposes 290 * @return int Count of users 291 */ 292 public function get_numusers($groups = true, $users = false) { 293 global $CFG, $DB; 294 $userwheresql = ""; 295 $groupsql = ""; 296 $groupwheresql = ""; 297 298 // Limit to users with a gradeable role. 299 list($gradebookrolessql, $gradebookrolesparams) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0'); 300 301 // Limit to users with an active enrollment. 302 list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->context); 303 304 // We want to query both the current context and parent contexts. 305 list($relatedctxsql, $relatedctxparams) = $DB->get_in_or_equal($this->context->get_parent_context_ids(true), SQL_PARAMS_NAMED, 'relatedctx'); 306 307 $params = array_merge($gradebookrolesparams, $enrolledparams, $relatedctxparams); 308 309 if ($users) { 310 $userwheresql = $this->userwheresql; 311 $params = array_merge($params, $this->userwheresql_params); 312 } 313 314 if ($groups) { 315 $groupsql = $this->groupsql; 316 $groupwheresql = $this->groupwheresql; 317 $params = array_merge($params, $this->groupwheresql_params); 318 } 319 320 $sql = "SELECT DISTINCT u.id 321 FROM {user} u 322 JOIN ($enrolledsql) je 323 ON je.id = u.id 324 JOIN {role_assignments} ra 325 ON u.id = ra.userid 326 $groupsql 327 WHERE ra.roleid $gradebookrolessql 328 AND u.deleted = 0 329 $userwheresql 330 $groupwheresql 331 AND ra.contextid $relatedctxsql"; 332 $selectedusers = $DB->get_records_sql($sql, $params); 333 334 $count = 0; 335 // Check if user's enrolment is active and should be displayed. 336 if (!empty($selectedusers)) { 337 $coursecontext = $this->context->get_course_context(true); 338 339 $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol); 340 $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol); 341 $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $coursecontext); 342 343 if ($showonlyactiveenrol) { 344 $useractiveenrolments = get_enrolled_users($coursecontext, '', 0, 'u.id', null, 0, 0, true); 345 } 346 347 foreach ($selectedusers as $id => $value) { 348 if (!$showonlyactiveenrol || ($showonlyactiveenrol && array_key_exists($id, $useractiveenrolments))) { 349 $count++; 350 } 351 } 352 } 353 return $count; 354 } 355 356 /** 357 * Shows support for being used as a 'Grades' report. 358 */ 359 public static function supports_mygrades() { 360 return false; 361 } 362 363 /** 364 * Sets up this object's group variables, mainly to restrict the selection of users to display. 365 */ 366 protected function setup_groups() { 367 // find out current groups mode 368 if ($this->groupmode = groups_get_course_groupmode($this->course)) { 369 $this->currentgroup = groups_get_course_group($this->course, true); 370 $this->group_selector = groups_print_course_menu($this->course, $this->pbarurl, true); 371 372 if ($this->groupmode == SEPARATEGROUPS and !$this->currentgroup and !has_capability('moodle/site:accessallgroups', $this->context)) { 373 $this->currentgroup = -2; // means can not access any groups at all 374 } 375 376 if ($this->currentgroup) { 377 $group = groups_get_group($this->currentgroup); 378 $this->currentgroupname = $group->name; 379 $this->groupsql = " JOIN {groups_members} gm ON gm.userid = u.id "; 380 $this->groupwheresql = " AND gm.groupid = :gr_grpid "; 381 $this->groupwheresql_params = array('gr_grpid'=>$this->currentgroup); 382 } 383 } 384 } 385 386 /** 387 * Sets up this report's user criteria to restrict the selection of users to display. 388 */ 389 public function setup_users() { 390 global $SESSION, $DB; 391 392 $this->userwheresql = ""; 393 $this->userwheresql_params = array(); 394 if (isset($SESSION->gradereport['filterfirstname']) && !empty($SESSION->gradereport['filterfirstname'])) { 395 $this->userwheresql .= ' AND '.$DB->sql_like('u.firstname', ':firstname', false, false); 396 $this->userwheresql_params['firstname'] = $SESSION->gradereport['filterfirstname'].'%'; 397 } 398 if (isset($SESSION->gradereport['filtersurname']) && !empty($SESSION->gradereport['filtersurname'])) { 399 $this->userwheresql .= ' AND '.$DB->sql_like('u.lastname', ':lastname', false, false); 400 $this->userwheresql_params['lastname'] = $SESSION->gradereport['filtersurname'].'%'; 401 } 402 } 403 404 /** 405 * Returns an arrow icon inside an <a> tag, for the purpose of sorting a column. 406 * @param string $direction 407 * @param moodle_url $sortlink 408 */ 409 protected function get_sort_arrow($direction='move', $sortlink=null) { 410 global $OUTPUT; 411 $pix = array('up' => 't/sort_desc', 'down' => 't/sort_asc', 'move' => 't/sort'); 412 $matrix = array('up' => 'desc', 'down' => 'asc', 'move' => 'desc'); 413 $strsort = $this->get_lang_string('sort' . $matrix[$direction]); 414 415 $arrow = $OUTPUT->pix_icon($pix[$direction], $strsort, '', array('class' => 'sorticon')); 416 return html_writer::link($sortlink, $arrow, array('title'=>$strsort)); 417 } 418 419 /** 420 * Optionally blank out course/category totals if they contain any hidden items 421 * @param string $courseid the course id 422 * @param string $course_item an instance of grade_item 423 * @param string $finalgrade the grade for the course_item 424 * @return array[] containing values for 'grade', 'grademax', 'grademin', 'aggregationstatus' and 'aggregationweight' 425 */ 426 protected function blank_hidden_total_and_adjust_bounds($courseid, $course_item, $finalgrade) { 427 global $CFG, $DB; 428 static $hiding_affected = null;//array of items in this course affected by hiding 429 430 // If we're dealing with multiple users we need to know when we've moved on to a new user. 431 static $previous_userid = null; 432 433 // If we're dealing with multiple courses we need to know when we've moved on to a new course. 434 static $previous_courseid = null; 435 436 $coursegradegrade = grade_grade::fetch(array('userid'=>$this->user->id, 'itemid'=>$course_item->id)); 437 $grademin = $course_item->grademin; 438 $grademax = $course_item->grademax; 439 if ($coursegradegrade) { 440 $grademin = $coursegradegrade->get_grade_min(); 441 $grademax = $coursegradegrade->get_grade_max(); 442 } else { 443 $coursegradegrade = new grade_grade(array('userid'=>$this->user->id, 'itemid'=>$course_item->id), false); 444 } 445 $hint = $coursegradegrade->get_aggregation_hint(); 446 $aggregationstatus = $hint['status']; 447 $aggregationweight = $hint['weight']; 448 449 if (!is_array($this->showtotalsifcontainhidden)) { 450 debugging('showtotalsifcontainhidden should be an array', DEBUG_DEVELOPER); 451 $this->showtotalsifcontainhidden = array($courseid => $this->showtotalsifcontainhidden); 452 } 453 454 if ($this->showtotalsifcontainhidden[$courseid] == GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN) { 455 return array('grade' => $finalgrade, 456 'grademin' => $grademin, 457 'grademax' => $grademax, 458 'aggregationstatus' => $aggregationstatus, 459 'aggregationweight' => $aggregationweight); 460 } 461 462 // If we've moved on to another course or user, reload the grades. 463 if ($previous_userid != $this->user->id || $previous_courseid != $courseid) { 464 $hiding_affected = null; 465 $previous_userid = $this->user->id; 466 $previous_courseid = $courseid; 467 } 468 469 if (!$hiding_affected) { 470 $items = grade_item::fetch_all(array('courseid'=>$courseid)); 471 $grades = array(); 472 $sql = "SELECT g.* 473 FROM {grade_grades} g 474 JOIN {grade_items} gi ON gi.id = g.itemid 475 WHERE g.userid = {$this->user->id} AND gi.courseid = {$courseid}"; 476 if ($gradesrecords = $DB->get_records_sql($sql)) { 477 foreach ($gradesrecords as $grade) { 478 $grades[$grade->itemid] = new grade_grade($grade, false); 479 } 480 unset($gradesrecords); 481 } 482 foreach ($items as $itemid => $unused) { 483 if (!isset($grades[$itemid])) { 484 $grade_grade = new grade_grade(); 485 $grade_grade->userid = $this->user->id; 486 $grade_grade->itemid = $items[$itemid]->id; 487 $grades[$itemid] = $grade_grade; 488 } 489 $grades[$itemid]->grade_item =& $items[$itemid]; 490 } 491 $hiding_affected = grade_grade::get_hiding_affected($grades, $items); 492 } 493 494 //if the item definitely depends on a hidden item 495 if (array_key_exists($course_item->id, $hiding_affected['altered']) || 496 array_key_exists($course_item->id, $hiding_affected['alteredgrademin']) || 497 array_key_exists($course_item->id, $hiding_affected['alteredgrademax']) || 498 array_key_exists($course_item->id, $hiding_affected['alteredaggregationstatus']) || 499 array_key_exists($course_item->id, $hiding_affected['alteredaggregationweight'])) { 500 if (!$this->showtotalsifcontainhidden[$courseid] && array_key_exists($course_item->id, $hiding_affected['altered'])) { 501 // Hide the grade, but only when it has changed. 502 $finalgrade = null; 503 } else { 504 //use reprocessed marks that exclude hidden items 505 if (array_key_exists($course_item->id, $hiding_affected['altered'])) { 506 $finalgrade = $hiding_affected['altered'][$course_item->id]; 507 } 508 if (array_key_exists($course_item->id, $hiding_affected['alteredgrademin'])) { 509 $grademin = $hiding_affected['alteredgrademin'][$course_item->id]; 510 } 511 if (array_key_exists($course_item->id, $hiding_affected['alteredgrademax'])) { 512 $grademax = $hiding_affected['alteredgrademax'][$course_item->id]; 513 } 514 if (array_key_exists($course_item->id, $hiding_affected['alteredaggregationstatus'])) { 515 $aggregationstatus = $hiding_affected['alteredaggregationstatus'][$course_item->id]; 516 } 517 if (array_key_exists($course_item->id, $hiding_affected['alteredaggregationweight'])) { 518 $aggregationweight = $hiding_affected['alteredaggregationweight'][$course_item->id]; 519 } 520 521 if (!$this->showtotalsifcontainhidden[$courseid]) { 522 // If the course total is hidden we must hide the weight otherwise 523 // it can be used to compute the course total. 524 $aggregationstatus = 'unknown'; 525 $aggregationweight = null; 526 } 527 } 528 } else if (!empty($hiding_affected['unknown'][$course_item->id])) { 529 //not sure whether or not this item depends on a hidden item 530 if (!$this->showtotalsifcontainhidden[$courseid]) { 531 //hide the grade 532 $finalgrade = null; 533 } else { 534 //use reprocessed marks that exclude hidden items 535 $finalgrade = $hiding_affected['unknown'][$course_item->id]; 536 537 if (array_key_exists($course_item->id, $hiding_affected['alteredgrademin'])) { 538 $grademin = $hiding_affected['alteredgrademin'][$course_item->id]; 539 } 540 if (array_key_exists($course_item->id, $hiding_affected['alteredgrademax'])) { 541 $grademax = $hiding_affected['alteredgrademax'][$course_item->id]; 542 } 543 if (array_key_exists($course_item->id, $hiding_affected['alteredaggregationstatus'])) { 544 $aggregationstatus = $hiding_affected['alteredaggregationstatus'][$course_item->id]; 545 } 546 if (array_key_exists($course_item->id, $hiding_affected['alteredaggregationweight'])) { 547 $aggregationweight = $hiding_affected['alteredaggregationweight'][$course_item->id]; 548 } 549 } 550 } 551 552 return array('grade' => $finalgrade, 'grademin' => $grademin, 'grademax' => $grademax, 'aggregationstatus'=>$aggregationstatus, 'aggregationweight'=>$aggregationweight); 553 } 554 555 /** 556 * Optionally blank out course/category totals if they contain any hidden items 557 * @deprecated since Moodle 2.8 - Call blank_hidden_total_and_adjust_bounds instead. 558 * @param string $courseid the course id 559 * @param string $course_item an instance of grade_item 560 * @param string $finalgrade the grade for the course_item 561 * @return string The new final grade 562 */ 563 protected function blank_hidden_total($courseid, $course_item, $finalgrade) { 564 // Note it is flawed to call this function directly because 565 // the aggregated grade does not make sense without the updated min and max information. 566 567 debugging('grade_report::blank_hidden_total() is deprecated. 568 Call grade_report::blank_hidden_total_and_adjust_bounds instead.', DEBUG_DEVELOPER); 569 $result = $this->blank_hidden_total_and_adjust_bounds($courseid, $course_item, $finalgrade); 570 return $result['grade']; 571 } 572 } 573
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Thu Aug 11 10:00:09 2016 | Cross-referenced by PHPXref 0.7.1 |