gradebook MDL-22841 fixed a bug where the user report when viewing multiple students...
[moodle.git] / grade / report / lib.php
CommitLineData
e060e33d 1<?php
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
8ad36f4c 17
38b9e8a8 18/**
eea6690a 19 * File containing the grade_report class.
20 * @package gradebook
38b9e8a8 21 */
eea6690a 22
23require_once($CFG->libdir.'/gradelib.php');
24
25/**
26 * An abstract class containing variables and methods used by all or most reports.
27 * @abstract
28 * @package gradebook
29 */
d24832f9 30abstract class grade_report {
eea6690a 31 /**
32 * The courseid.
33 * @var int $courseid
34 */
d24832f9 35 public $courseid;
eea6690a 36
b2bc96d1 37 /**
38 * The course.
39 * @var object $course
40 */
d24832f9 41 public $course;
b2bc96d1 42
d30c4481 43 /** Grade plugin return tracking object.
4889285b 44 * @var object $gpr
45 */
46 public $gpr;
d30c4481 47
eea6690a 48 /**
49 * The context.
50 * @var int $context
51 */
d24832f9 52 public $context;
eea6690a 53
54 /**
55 * The grade_tree object.
56 * @var object $gtree
57 */
d24832f9 58 public $gtree;
eea6690a 59
60 /**
61 * User preferences related to this report.
e50ce569 62 * @var array $prefs
eea6690a 63 */
d24832f9 64 public $prefs = array();
eea6690a 65
66 /**
67 * The roles for this report.
68 * @var string $gradebookroles
69 */
d24832f9 70 public $gradebookroles;
eea6690a 71
72 /**
73 * base url for sorting by first/last name.
74 * @var string $baseurl
75 */
d24832f9 76 public $baseurl;
eea6690a 77
78 /**
79 * base url for paging.
80 * @var string $pbarurl
81 */
d24832f9 82 public $pbarurl;
eea6690a 83
84 /**
85 * Current page (for paging).
86 * @var int $page
87 */
d24832f9 88 public $page;
eea6690a 89
388234f4 90 /**
91 * Array of cached language strings (using get_string() all the time takes a long time!).
92 * @var array $lang_strings
93 */
d24832f9 94 public $lang_strings = array();
388234f4 95
90d3960c 96//// GROUP VARIABLES (including SQL)
97
98 /**
99 * The current group being displayed.
100 * @var int $currentgroup
101 */
d24832f9 102 public $currentgroup;
90d3960c 103
35079f53 104 /**
105 * Current course group mode
106 * @var int $groupmode
107 */
108 var $groupmode;
109
90d3960c 110 /**
111 * A HTML select element used to select the current group.
112 * @var string $group_selector
113 */
d24832f9 114 public $group_selector;
90d3960c 115
116 /**
117 * An SQL fragment used to add linking information to the group tables.
118 * @var string $groupsql
119 */
d24832f9 120 protected $groupsql;
90d3960c 121
122 /**
123 * An SQL constraint to append to the queries used by this object to build the report.
124 * @var string $groupwheresql
125 */
d24832f9 126 protected $groupwheresql;
127
128 /**
129 * The ordered params for $groupwheresql
130 * @var array $groupwheresql_params
131 */
132 protected $groupwheresql_params = array();
90d3960c 133
134
eea6690a 135 /**
136 * Constructor. Sets local copies of user preferences and initialises grade_tree.
137 * @param int $courseid
d30c4481 138 * @param object $gpr grade plugin return tracking object
eea6690a 139 * @param string $context
140 * @param int $page The current page being viewed (when report is paged)
141 */
d24832f9 142 public function __construct($courseid, $gpr, $context, $page=null) {
5c75a0a3 143 global $CFG, $COURSE, $DB;
eea6690a 144
dde8e548 145 if (empty($CFG->gradebookroles)) {
771dc7b2 146 print_error('norolesdefined', 'grades');
0893aa30 147 }
284abb09 148
0893aa30 149
4faf5f99 150 $this->courseid = $courseid;
b2bc96d1 151 if ($this->courseid == $COURSE->id) {
152 $this->course = $COURSE;
153 } else {
5c75a0a3 154 $this->course = $DB->get_record('course', array('id' => $this->courseid));
b2bc96d1 155 }
41f22daa 156
4faf5f99 157 $this->gpr = $gpr;
158 $this->context = $context;
159 $this->page = $page;
eea6690a 160
161 // roles to be displayed in the gradebook
162 $this->gradebookroles = $CFG->gradebookroles;
163
dc482cfa 164 // Set up link to preferences page
165 $this->preferences_page = $CFG->wwwroot.'/grade/report/grader/preferences.php?id='.$courseid;
166
4faf5f99 167 // init gtree in child class
38b9e8a8 168 }
169
eea6690a 170 /**
171 * Given the name of a user preference (without grade_report_ prefix), locally saves then returns
172 * the value of that preference. If the preference has already been fetched before,
173 * the saved value is returned. If the preference is not set at the User level, the $CFG equivalent
174 * is given (site default).
501e0e34 175 * @static (Can be called statically, but then doesn't benefit from caching)
eea6690a 176 * @param string $pref The name of the preference (do not include the grade_report_ prefix)
8c5a416e 177 * @param int $objectid An optional itemid or categoryid to check for a more fine-grained preference
eea6690a 178 * @return mixed The value of the preference
179 */
d24832f9 180 public function get_pref($pref, $objectid=null) {
eea6690a 181 global $CFG;
501e0e34 182 $fullprefname = 'grade_report_' . $pref;
54294d3b 183 $shortprefname = 'grade_' . $pref;
38b9e8a8 184
e50ce569 185 $retval = null;
186
438a5aa9 187 if (!isset($this) OR get_class($this) != 'grade_report') {
8c5a416e 188 if (!empty($objectid)) {
189 $retval = get_user_preferences($fullprefname . $objectid, grade_report::get_pref($pref));
54294d3b 190 } elseif (isset($CFG->$fullprefname)) {
e50ce569 191 $retval = get_user_preferences($fullprefname, $CFG->$fullprefname);
54294d3b 192 } elseif (isset($CFG->$shortprefname)) {
d24832f9 193 $retval = get_user_preferences($fullprefname, $CFG->$shortprefname);
54294d3b 194 } else {
195 $retval = null;
bb384a8e 196 }
501e0e34 197 } else {
8c5a416e 198 if (empty($this->prefs[$pref.$objectid])) {
e50ce569 199
8c5a416e 200 if (!empty($objectid)) {
201 $retval = get_user_preferences($fullprefname . $objectid);
e50ce569 202 if (empty($retval)) {
203 // No item pref found, we are returning the global preference
204 $retval = $this->get_pref($pref);
8c5a416e 205 $objectid = null;
e50ce569 206 }
501e0e34 207 } else {
e50ce569 208 $retval = get_user_preferences($fullprefname, $CFG->$fullprefname);
501e0e34 209 }
8c5a416e 210 $this->prefs[$pref.$objectid] = $retval;
e50ce569 211 } else {
8c5a416e 212 $retval = $this->prefs[$pref.$objectid];
501e0e34 213 }
eea6690a 214 }
e50ce569 215
216 return $retval;
eea6690a 217 }
bb384a8e 218
eea6690a 219 /**
501e0e34 220 * Uses set_user_preferences() to update the value of a user preference. If 'default' is given as the value,
221 * the preference will be removed in favour of a higher-level preference.
222 * @static
eea6690a 223 * @param string $pref_name The name of the preference.
224 * @param mixed $pref_value The value of the preference.
bb384a8e 225 * @param int $itemid An optional itemid to which the preference will be assigned
eea6690a 226 * @return bool Success or failure.
eea6690a 227 */
d24832f9 228 public function set_pref($pref, $pref_value='default', $itemid=null) {
bb384a8e 229 $fullprefname = 'grade_report_' . $pref;
501e0e34 230 if ($pref_value == 'default') {
231 return unset_user_preference($fullprefname.$itemid);
232 } else {
233 return set_user_preference($fullprefname.$itemid, $pref_value);
eea6690a 234 }
38b9e8a8 235 }
38b9e8a8 236
eea6690a 237 /**
238 * Handles form data sent by this report for this report. Abstract method to implement in all children.
239 * @abstract
240 * @param array $data
241 * @return mixed True or array of errors
242 */
d24832f9 243 abstract function process_data($data);
38b9e8a8 244
eea6690a 245 /**
246 * Processes a single action against a category, grade_item or grade.
247 * @param string $target Sortorder
248 * @param string $action Which action to take (edit, delete etc...)
249 * @return
eea6690a 250 */
d24832f9 251 abstract function process_action($target, $action);
eea6690a 252
388234f4 253 /**
254 * First checks the cached language strings, then returns match if found, or uses get_string()
255 * to get it from the DB, caches it then returns it.
256 * @param string $strcode
257 * @param string $section Optional language section
258 * @return string
259 */
d24832f9 260 public function get_lang_string($strcode, $section=null) {
388234f4 261 if (empty($this->lang_strings[$strcode])) {
262 $this->lang_strings[$strcode] = get_string($strcode, $section);
263 }
264 return $this->lang_strings[$strcode];
265 }
266
90d3960c 267 /**
268 * Fetches and returns a count of all the users that will be shown on this page.
28bcbc38 269 * @param boolean $groups include groups limit
90d3960c 270 * @return int Count of users
271 */
d24832f9 272 public function get_numusers($groups=true) {
273 global $CFG, $DB;
90d3960c 274
28bcbc38 275 $groupsql = "";
276 $groupwheresql = "";
b50371da 277 list($usql, $params) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0');
d24832f9 278
28bcbc38 279 if ($groups) {
280 $groupsql = $this->groupsql;
bbadce53 281 $groupwheresql = $this->groupwheresql;
d24832f9 282 $params = array_merge($params, $this->groupwheresql_params);
28bcbc38 283 }
284
90d3960c 285 $countsql = "SELECT COUNT(DISTINCT u.id)
b50371da 286 FROM {user} u
287 JOIN {role_assignments} ra ON u.id = ra.userid
288 $groupsql
289 WHERE ra.roleid $usql AND u.deleted = 0
290 $groupwheresql
291 AND ra.contextid ".get_related_contexts_string($this->context);
d24832f9 292 return $DB->count_records_sql($countsql, $params);
90d3960c 293 }
294
295 /**
296 * Sets up this object's group variables, mainly to restrict the selection of users to display.
297 */
0fd8bc00 298 protected function setup_groups() {
90d3960c 299 /// find out current groups mode
35079f53 300 if ($this->groupmode = groups_get_course_groupmode($this->course)) {
7a9ba4b4 301 $this->currentgroup = groups_get_course_group($this->course, true);
35079f53 302 $this->group_selector = groups_print_course_menu($this->course, $this->pbarurl, true);
7a9ba4b4 303
304 if ($this->groupmode == SEPARATEGROUPS and !$this->currentgroup and !has_capability('moodle/site:accessallgroups', $this->context)) {
305 $this->currentgroup = -2; // means can not accesss any groups at all
306 }
35079f53 307
308 if ($this->currentgroup) {
309 $this->groupsql = " JOIN {groups_members} gm ON gm.userid = u.id ";
310 $this->groupwheresql = " AND gm.groupid = :gr_grpid ";
311 $this->groupwheresql_params = array('gr_grpid'=>$this->currentgroup);
312 }
90d3960c 313 }
314 }
2e3987a9 315
316 /**
317 * Returns an arrow icon inside an <a> tag, for the purpose of sorting a column.
318 * @param string $direction
319770d7 319 * @param moodle_url $sort_link
2e3987a9 320 * @param string HTML
321 */
319770d7 322 protected function get_sort_arrow($direction='move', $sortlink=null) {
323 global $OUTPUT;
dc482cfa 324 $matrix = array('up' => 'desc', 'down' => 'asc', 'move' => 'desc');
2e3987a9 325 $strsort = $this->get_lang_string('sort' . $matrix[$direction]);
dc482cfa 326
2e3987a9 327 $arrow = print_arrow($direction, $strsort, true);
75015e5f 328 return html_writer::link($sortlink, $arrow, array('title'=>$strsort));
2e3987a9 329 }
61541a5a
AD
330
331 /**
332 * Optionally blank out course/category totals if they contain any hidden items
333 * @param string $courseid the course id
334 * @param string $course_item an instance of grade_item
335 * @param string $finalgrade the grade for the course_item
336 * @return string The new final grade
337 */
338 protected function blank_hidden_total($courseid, $course_item, $finalgrade) {
339 global $CFG, $DB;
340 static $hiding_affected = null;//array of items in this course affected by hiding
341
8eabc1d8
AD
342 //if we're dealing with multiple users we need to know when we've moved on to a new user
343 static $previous_userid = null;
344
61541a5a
AD
345 if( $this->showtotalsifcontainhidden==GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN ) {
346 return $finalgrade;
347 }
348
8eabc1d8
AD
349 //if we've moved on to another user don't return the previous user's affected grades
350 if ($previous_userid!=$this->user->id) {
351 $hiding_affected = null;
352 $previous_userid = $this->user->id;
353 }
354
61541a5a
AD
355 if( !$hiding_affected ) {
356 $items = grade_item::fetch_all(array('courseid'=>$courseid));
357 $grades = array();
358 $sql = "SELECT g.*
ffe50258
EL
359 FROM {grade_grades} g
360 JOIN {grade_items} gi ON gi.id = g.itemid
61541a5a
AD
361 WHERE g.userid = {$this->user->id} AND gi.courseid = {$courseid}";
362 if ($gradesrecords = $DB->get_records_sql($sql)) {
363 foreach ($gradesrecords as $grade) {
364 $grades[$grade->itemid] = new grade_grade($grade, false);
365 }
366 unset($gradesrecords);
367 }
368 foreach ($items as $itemid=>$unused) {
369 if (!isset($grades[$itemid])) {
370 $grade_grade = new grade_grade();
371 $grade_grade->userid = $this->user->id;
372 $grade_grade->itemid = $items[$itemid]->id;
373 $grades[$itemid] = $grade_grade;
374 }
375 $grades[$itemid]->grade_item =& $items[$itemid];
376 }
377 $hiding_affected = grade_grade::get_hiding_affected($grades, $items);
378 }
379
380 //if the item definitely depends on a hidden item
381 if (array_key_exists($course_item->id, $hiding_affected['altered'])) {
382 if( !$this->showtotalsifcontainhidden ) {
383 //hide the grade
384 $finalgrade = null;
385 }
386 else {
387 //use reprocessed marks that exclude hidden items
388 $finalgrade = $hiding_affected['altered'][$course_item->id];
389 }
390 } else if (!empty($hiding_affected['unknown'][$course_item->id])) {
391 //not sure whether or not this item depends on a hidden item
392 if( !$this->showtotalsifcontainhidden ) {
393 //hide the grade
394 $finalgrade = null;
395 }
396 else {
397 //use reprocessed marks that exclude hidden items
398 $finalgrade = $hiding_affected['unknown'][$course_item->id];
399 }
400 }
401
402 return $finalgrade;
403 }
38b9e8a8 404}
6c3ef410 405