[ Index ] |
PHP Cross Reference of moodle-2.8 |
[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 object $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 * Sets up this object's group variables, mainly to restrict the selection of users to display. 358 */ 359 protected function setup_groups() { 360 // find out current groups mode 361 if ($this->groupmode = groups_get_course_groupmode($this->course)) { 362 $this->currentgroup = groups_get_course_group($this->course, true); 363 $this->group_selector = groups_print_course_menu($this->course, $this->pbarurl, true); 364 365 if ($this->groupmode == SEPARATEGROUPS and !$this->currentgroup and !has_capability('moodle/site:accessallgroups', $this->context)) { 366 $this->currentgroup = -2; // means can not access any groups at all 367 } 368 369 if ($this->currentgroup) { 370 $group = groups_get_group($this->currentgroup); 371 $this->currentgroupname = $group->name; 372 $this->groupsql = " JOIN {groups_members} gm ON gm.userid = u.id "; 373 $this->groupwheresql = " AND gm.groupid = :gr_grpid "; 374 $this->groupwheresql_params = array('gr_grpid'=>$this->currentgroup); 375 } 376 } 377 } 378 379 /** 380 * Sets up this report's user criteria to restrict the selection of users to display. 381 */ 382 public function setup_users() { 383 global $SESSION, $DB; 384 385 $this->userwheresql = ""; 386 $this->userwheresql_params = array(); 387 if (isset($SESSION->gradereport['filterfirstname']) && !empty($SESSION->gradereport['filterfirstname'])) { 388 $this->userwheresql .= ' AND '.$DB->sql_like('u.firstname', ':firstname', false, false); 389 $this->userwheresql_params['firstname'] = $SESSION->gradereport['filterfirstname'].'%'; 390 } 391 if (isset($SESSION->gradereport['filtersurname']) && !empty($SESSION->gradereport['filtersurname'])) { 392 $this->userwheresql .= ' AND '.$DB->sql_like('u.lastname', ':lastname', false, false); 393 $this->userwheresql_params['lastname'] = $SESSION->gradereport['filtersurname'].'%'; 394 } 395 } 396 397 /** 398 * Returns an arrow icon inside an <a> tag, for the purpose of sorting a column. 399 * @param string $direction 400 * @param moodle_url $sortlink 401 */ 402 protected function get_sort_arrow($direction='move', $sortlink=null) { 403 global $OUTPUT; 404 $pix = array('up' => 't/sort_desc', 'down' => 't/sort_asc', 'move' => 't/sort'); 405 $matrix = array('up' => 'desc', 'down' => 'asc', 'move' => 'desc'); 406 $strsort = $this->get_lang_string('sort' . $matrix[$direction]); 407 408 $arrow = $OUTPUT->pix_icon($pix[$direction], $strsort, '', array('class' => 'sorticon')); 409 return html_writer::link($sortlink, $arrow, array('title'=>$strsort)); 410 } 411 412 /** 413 * Optionally blank out course/category totals if they contain any hidden items 414 * @param string $courseid the course id 415 * @param string $course_item an instance of grade_item 416 * @param string $finalgrade the grade for the course_item 417 * @return array[] containing values for 'grade', 'grademax', 'grademin', 'aggregationstatus' and 'aggregationweight' 418 */ 419 protected function blank_hidden_total_and_adjust_bounds($courseid, $course_item, $finalgrade) { 420 global $CFG, $DB; 421 static $hiding_affected = null;//array of items in this course affected by hiding 422 423 // If we're dealing with multiple users we need to know when we've moved on to a new user. 424 static $previous_userid = null; 425 426 // If we're dealing with multiple courses we need to know when we've moved on to a new course. 427 static $previous_courseid = null; 428 429 $coursegradegrade = grade_grade::fetch(array('userid'=>$this->user->id, 'itemid'=>$course_item->id)); 430 $grademin = $course_item->grademin; 431 $grademax = $course_item->grademax; 432 if ($coursegradegrade) { 433 $grademin = $coursegradegrade->rawgrademin; 434 $grademax = $coursegradegrade->rawgrademax; 435 } else { 436 $coursegradegrade = new grade_grade(array('userid'=>$this->user->id, 'itemid'=>$course_item->id), false); 437 } 438 $hint = $coursegradegrade->get_aggregation_hint(); 439 $aggregationstatus = $hint['status']; 440 $aggregationweight = $hint['weight']; 441 442 if (!is_array($this->showtotalsifcontainhidden)) { 443 debugging('showtotalsifcontainhidden should be an array', DEBUG_DEVELOPER); 444 $this->showtotalsifcontainhidden = array($courseid => $this->showtotalsifcontainhidden); 445 } 446 447 if ($this->showtotalsifcontainhidden[$courseid] == GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN) { 448 return array('grade' => $finalgrade, 449 'grademin' => $grademin, 450 'grademax' => $grademax, 451 'aggregationstatus' => $aggregationstatus, 452 'aggregationweight' => $aggregationweight); 453 } 454 455 // If we've moved on to another course or user, reload the grades. 456 if ($previous_userid != $this->user->id || $previous_courseid != $courseid) { 457 $hiding_affected = null; 458 $previous_userid = $this->user->id; 459 $previous_courseid = $courseid; 460 } 461 462 if (!$hiding_affected) { 463 $items = grade_item::fetch_all(array('courseid'=>$courseid)); 464 $grades = array(); 465 $sql = "SELECT g.* 466 FROM {grade_grades} g 467 JOIN {grade_items} gi ON gi.id = g.itemid 468 WHERE g.userid = {$this->user->id} AND gi.courseid = {$courseid}"; 469 if ($gradesrecords = $DB->get_records_sql($sql)) { 470 foreach ($gradesrecords as $grade) { 471 $grades[$grade->itemid] = new grade_grade($grade, false); 472 } 473 unset($gradesrecords); 474 } 475 foreach ($items as $itemid => $unused) { 476 if (!isset($grades[$itemid])) { 477 $grade_grade = new grade_grade(); 478 $grade_grade->userid = $this->user->id; 479 $grade_grade->itemid = $items[$itemid]->id; 480 $grades[$itemid] = $grade_grade; 481 } 482 $grades[$itemid]->grade_item =& $items[$itemid]; 483 } 484 $hiding_affected = grade_grade::get_hiding_affected($grades, $items); 485 } 486 487 //if the item definitely depends on a hidden item 488 if (array_key_exists($course_item->id, $hiding_affected['altered']) || 489 array_key_exists($course_item->id, $hiding_affected['alteredgrademin']) || 490 array_key_exists($course_item->id, $hiding_affected['alteredgrademax']) || 491 array_key_exists($course_item->id, $hiding_affected['alteredaggregationstatus']) || 492 array_key_exists($course_item->id, $hiding_affected['alteredaggregationweight'])) { 493 if (!$this->showtotalsifcontainhidden[$courseid] && array_key_exists($course_item->id, $hiding_affected['altered'])) { 494 // Hide the grade, but only when it has changed. 495 $finalgrade = null; 496 } else { 497 //use reprocessed marks that exclude hidden items 498 if (array_key_exists($course_item->id, $hiding_affected['altered'])) { 499 $finalgrade = $hiding_affected['altered'][$course_item->id]; 500 } 501 if (array_key_exists($course_item->id, $hiding_affected['alteredgrademin'])) { 502 $grademin = $hiding_affected['alteredgrademin'][$course_item->id]; 503 } 504 if (array_key_exists($course_item->id, $hiding_affected['alteredgrademax'])) { 505 $grademax = $hiding_affected['alteredgrademax'][$course_item->id]; 506 } 507 if (array_key_exists($course_item->id, $hiding_affected['alteredaggregationstatus'])) { 508 $aggregationstatus = $hiding_affected['alteredaggregationstatus'][$course_item->id]; 509 } 510 if (array_key_exists($course_item->id, $hiding_affected['alteredaggregationweight'])) { 511 $aggregationweight = $hiding_affected['alteredaggregationweight'][$course_item->id]; 512 } 513 514 if (!$this->showtotalsifcontainhidden[$courseid]) { 515 // If the course total is hidden we must hide the weight otherwise 516 // it can be used to compute the course total. 517 $aggregationstatus = 'unknown'; 518 $aggregationweight = null; 519 } 520 } 521 } else if (!empty($hiding_affected['unknown'][$course_item->id])) { 522 //not sure whether or not this item depends on a hidden item 523 if (!$this->showtotalsifcontainhidden[$courseid]) { 524 //hide the grade 525 $finalgrade = null; 526 } else { 527 //use reprocessed marks that exclude hidden items 528 $finalgrade = $hiding_affected['unknown'][$course_item->id]; 529 530 if (array_key_exists($course_item->id, $hiding_affected['alteredgrademin'])) { 531 $grademin = $hiding_affected['alteredgrademin'][$course_item->id]; 532 } 533 if (array_key_exists($course_item->id, $hiding_affected['alteredgrademax'])) { 534 $grademax = $hiding_affected['alteredgrademax'][$course_item->id]; 535 } 536 if (array_key_exists($course_item->id, $hiding_affected['alteredaggregationstatus'])) { 537 $aggregationstatus = $hiding_affected['alteredaggregationstatus'][$course_item->id]; 538 } 539 if (array_key_exists($course_item->id, $hiding_affected['alteredaggregationweight'])) { 540 $aggregationweight = $hiding_affected['alteredaggregationweight'][$course_item->id]; 541 } 542 } 543 } 544 545 return array('grade' => $finalgrade, 'grademin' => $grademin, 'grademax' => $grademax, 'aggregationstatus'=>$aggregationstatus, 'aggregationweight'=>$aggregationweight); 546 } 547 548 /** 549 * Optionally blank out course/category totals if they contain any hidden items 550 * @deprecated since Moodle 2.8 - Call blank_hidden_total_and_adjust_bounds instead. 551 * @param string $courseid the course id 552 * @param string $course_item an instance of grade_item 553 * @param string $finalgrade the grade for the course_item 554 * @return string The new final grade 555 */ 556 protected function blank_hidden_total($courseid, $course_item, $finalgrade) { 557 // Note it is flawed to call this function directly because 558 // the aggregated grade does not make sense without the updated min and max information. 559 560 debugging('grade_report::blank_hidden_total() is deprecated. 561 Call grade_report::blank_hidden_total_and_adjust_bounds instead.', DEBUG_DEVELOPER); 562 $result = $this->blank_hidden_total_and_adjust_bounds($courseid, $course_item, $finalgrade); 563 return $result['grade']; 564 } 565 } 566
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |