MDL-27703 gradebook: altered an sql query in the user report. join with no on clause...
[moodle.git] / grade / report / user / lib.php
1 <?php
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/>.
18 /**
19  * File in which the user_report class is defined.
20  * @package gradebook
21  */
23 require_once($CFG->dirroot . '/grade/report/lib.php');
24 require_once($CFG->libdir.'/tablelib.php');
26 //showhiddenitems values
27 define("GRADE_REPORT_USER_HIDE_HIDDEN", 0);
28 define("GRADE_REPORT_USER_HIDE_UNTIL", 1);
29 define("GRADE_REPORT_USER_SHOW_HIDDEN", 2);
31 /**
32  * Class providing an API for the user report building and displaying.
33  * @uses grade_report
34  * @package gradebook
35  */
36 class grade_report_user extends grade_report {
38     /**
39      * The user.
40      * @var object $user
41      */
42     public $user;
44     /**
45      * A flexitable to hold the data.
46      * @var object $table
47      */
48     public $table;
50     /**
51      * An array of table headers
52      * @var array
53      */
54     public $tableheaders = array();
56     /**
57      * An array of table columns
58      * @var array
59      */
60     public $tablecolumns = array();
62     /**
63      * An array containing rows of data for the table.
64      * @var type
65      */
66     public $tabledata = array();
68     /**
69      * The grade tree structure
70      * @var grade_tree
71      */
72     public $gtree;
74     /**
75      * Flat structure similar to grade tree
76      */
77     public $gseq;
79     /**
80      * show student ranks
81      */
82     public $showrank;
84     /**
85      * show grade percentages
86      */
87     public $showpercentage;
89     /**
90      * Show range
91      */
92     public $showrange = true;
94     /**
95      * Show grades in the report, default true
96      * @var bool
97      */
98     public $showgrade = true;
100     /**
101      * Decimal points to use for values in the report, default 2
102      * @var int
103      */
104     public $decimals = 2;
106     /**
107      * The number of decimal places to round range to, default 0
108      * @var int
109      */
110     public $rangedecimals = 0;
112     /**
113      * Show grade feedback in the report, default true
114      * @var bool
115      */
116     public $showfeedback = true;
118     /**
119      * Show grade weighting in the report, default false
120      * @var bool
121      */
122     public $showweight = false;
124     /**
125      * Show letter grades in the report, default false
126      * @var bool
127      */
128     public $showlettergrade = false;
130     /**
131      * Show average grades in the report, default false.
132      * @var false
133      */
134     public $showaverage = false;
136     public $maxdepth;
137     public $evenodd;
139     public $canviewhidden;
141     public $switch;
143     /**
144      * Show hidden items even when user does not have required cap
145      */
146     public $showhiddenitems;
147     public $showtotalsifcontainhidden;
149     public $baseurl;
150     public $pbarurl;
152     /**
153      * Constructor. Sets local copies of user preferences and initialises grade_tree.
154      * @param int $courseid
155      * @param object $gpr grade plugin return tracking object
156      * @param string $context
157      * @param int $userid The id of the user
158      */
159     public function __construct($courseid, $gpr, $context, $userid) {
160         global $DB, $CFG;
161         parent::__construct($courseid, $gpr, $context);
163         $this->showrank        = grade_get_setting($this->courseid, 'report_user_showrank', $CFG->grade_report_user_showrank);
164         $this->showpercentage  = grade_get_setting($this->courseid, 'report_user_showpercentage', $CFG->grade_report_user_showpercentage);
165         $this->showhiddenitems = grade_get_setting($this->courseid, 'report_user_showhiddenitems', $CFG->grade_report_user_showhiddenitems);
166         $this->showtotalsifcontainhidden = grade_get_setting($this->courseid, 'report_user_showtotalsifcontainhidden', $CFG->grade_report_user_showtotalsifcontainhidden);
168         $this->showgrade       = grade_get_setting($this->courseid, 'report_user_showgrade',       !empty($CFG->grade_report_user_showgrade));
169         $this->showrange       = grade_get_setting($this->courseid, 'report_user_showrange',       !empty($CFG->grade_report_user_showrange));
170         $this->showfeedback    = grade_get_setting($this->courseid, 'report_user_showfeedback',    !empty($CFG->grade_report_user_showfeedback));
171         $this->showweight      = grade_get_setting($this->courseid, 'report_user_showweight',      !empty($CFG->grade_report_user_showweight));
172         $this->showlettergrade = grade_get_setting($this->courseid, 'report_user_showlettergrade', !empty($CFG->grade_report_user_showlettergrade));
173         $this->showaverage     = grade_get_setting($this->courseid, 'report_user_showaverage',     !empty($CFG->grade_report_user_showaverage));
175         // The default grade decimals is 2
176         $defaultdecimals = 2;
177         if (property_exists($CFG, 'grade_decimalpoints')) {
178             $defaultdecimals = $CFG->grade_decimalpoints;
179         }
180         $this->decimals = grade_get_setting($this->courseid, 'decimalpoints', $defaultdecimals);
182         // The default range decimals is 0
183         $defaultrangedecimals = 0;
184         if (property_exists($CFG, 'grade_report_user_rangedecimals')) {
185             $defaultrangedecimals = $CFG->grade_report_user_rangedecimals;
186         }
187         $this->rangedecimals = grade_get_setting($this->courseid, 'report_user_rangedecimals', $defaultrangedecimals);
189         $this->switch = grade_get_setting($this->courseid, 'aggregationposition', $CFG->grade_aggregationposition);
191         // Grab the grade_tree for this course
192         $this->gtree = new grade_tree($this->courseid, false, $this->switch, null, !$CFG->enableoutcomes);
194         // Determine the number of rows and indentation
195         $this->maxdepth = 1;
196         $this->inject_rowspans($this->gtree->top_element);
197         $this->maxdepth++; // Need to account for the lead column that spans all children
198         for ($i = 1; $i <= $this->maxdepth; $i++) {
199             $this->evenodd[$i] = 0;
200         }
202         $this->tabledata = array();
204         $this->canviewhidden = has_capability('moodle/grade:viewhidden', get_context_instance(CONTEXT_COURSE, $this->courseid));
206         // get the user (for full name)
207         $this->user = $DB->get_record('user', array('id' => $userid));
209         // base url for sorting by first/last name
210         $this->baseurl = $CFG->wwwroot.'/grade/report?id='.$courseid.'&amp;userid='.$userid;
211         $this->pbarurl = $this->baseurl;
213         // no groups on this report - rank is from all course users
214         $this->setup_table();
216         //optionally calculate grade item averages
217         $this->calculate_averages();
218     }
220     function inject_rowspans(&$element) {
221         if ($element['depth'] > $this->maxdepth) {
222             $this->maxdepth = $element['depth'];
223         }
224         if (empty($element['children'])) {
225             return 1;
226         }
227         $count = 1;
228         foreach ($element['children'] as $key=>$child) {
229             $count += $this->inject_rowspans($element['children'][$key]);
230         }
231         $element['rowspan'] = $count;
232         return $count;
233     }
236     /**
237      * Prepares the headers and attributes of the flexitable.
238      */
239     public function setup_table() {
240         /*
241          * Table has 1-8 columns
242          *| All columns except for itemname/description are optional
243          */
245         // setting up table headers
247         $this->tablecolumns = array('itemname');
248         $this->tableheaders = array($this->get_lang_string('gradeitem', 'grades'));
250         if ($this->showweight) {
251             $this->tablecolumns[] = 'weight';
252             $this->tableheaders[] = $this->get_lang_string('weightuc', 'grades');
253         }
255         if ($this->showgrade) {
256             $this->tablecolumns[] = 'grade';
257             $this->tableheaders[] = $this->get_lang_string('grade', 'grades');
258         }
260         if ($this->showrange) {
261             $this->tablecolumns[] = 'range';
262             $this->tableheaders[] = $this->get_lang_string('range', 'grades');
263         }
265         if ($this->showpercentage) {
266             $this->tablecolumns[] = 'percentage';
267             $this->tableheaders[] = $this->get_lang_string('percentage', 'grades');
268         }
270         if ($this->showlettergrade) {
271             $this->tablecolumns[] = 'lettergrade';
272             $this->tableheaders[] = $this->get_lang_string('lettergrade', 'grades');
273         }
275         if ($this->showrank) {
276             $this->tablecolumns[] = 'rank';
277             $this->tableheaders[] = $this->get_lang_string('rank', 'grades');
278         }
280         if ($this->showaverage) {
281             $this->tablecolumns[] = 'average';
282             $this->tableheaders[] = $this->get_lang_string('average', 'grades');
283         }
285         if ($this->showfeedback) {
286             $this->tablecolumns[] = 'feedback';
287             $this->tableheaders[] = $this->get_lang_string('feedback', 'grades');
288         }
289     }
291     function fill_table() {
292         //print "<pre>";
293         //print_r($this->gtree->top_element);
294         $this->fill_table_recursive($this->gtree->top_element);
295         //print_r($this->tabledata);
296         //print "</pre>";
297         return true;
298     }
300     private function fill_table_recursive(&$element) {
301         global $DB, $CFG;
303         $type = $element['type'];
304         $depth = $element['depth'];
305         $grade_object = $element['object'];
306         $eid = $grade_object->id;
307         $element['userid'] = $this->user->id;
308         $fullname = $this->gtree->get_element_header($element, true, true, true);
309         $data = array();
310         $hidden = '';
311         $excluded = '';
312         $class = '';
314         // If this is a hidden grade category, hide it completely from the user
315         if ($type == 'category' && $grade_object->is_hidden() && !$this->canviewhidden && (
316                 $this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN ||
317                 ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_object->is_hiddenuntil()))) {
318             return false;
319         }
321         if ($type == 'category') {
322             $this->evenodd[$depth] = (($this->evenodd[$depth] + 1) % 2);
323         }
324         $alter = ($this->evenodd[$depth] == 0) ? 'even' : 'odd';
326         /// Process those items that have scores associated
327         if ($type == 'item' or $type == 'categoryitem' or $type == 'courseitem') {
328             if (! $grade_grade = grade_grade::fetch(array('itemid'=>$grade_object->id,'userid'=>$this->user->id))) {
329                 $grade_grade = new grade_grade();
330                 $grade_grade->userid = $this->user->id;
331                 $grade_grade->itemid = $grade_object->id;
332             }
334             $grade_grade->load_grade_item();
336             /// Hidden Items
337             if ($grade_grade->grade_item->is_hidden()) {
338                 $hidden = ' hidden';
339             }
341             // If this is a hidden grade item, hide it completely from the user.
342             if ($grade_grade->is_hidden() && !$this->canviewhidden && (
343                     $this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN ||
344                     ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_grade->is_hiddenuntil()))) {
345                 // return false;
346             } else {
347                 /// Excluded Item
348                 if ($grade_grade->is_excluded()) {
349                     $fullname .= ' ['.get_string('excluded', 'grades').']';
350                     $excluded = ' excluded';
351                 }
353                 /// Other class information
354                 $class = "$hidden $excluded";
355                 if ($this->switch) { // alter style based on whether aggregation is first or last
356                    $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " ".$alter."d$depth baggt b2b" : " item b1b";
357                 } else {
358                    $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " ".$alter."d$depth baggb" : " item b1b";
359                 }
361                 /// Name
362                 $data['itemname']['content'] = $fullname;
363                 $data['itemname']['class'] = $class;
364                 $data['itemname']['colspan'] = ($this->maxdepth - $depth);
366                 /// Actual Grade
367                 $gradeval = $grade_grade->finalgrade;
369                 $class .= " itemcenter ";
370                 if ($this->showweight) {
371                     $data['weight']['class'] = $class;
372                     $data['weight']['content'] = '-';
373                     // has a weight assigned, might be extra credit
374                     if ($grade_object->aggregationcoef > 0 && $type <> 'courseitem') {
375                         $data['weight']['content'] = number_format($grade_object->aggregationcoef,2).'%';
376                     }
377                 }
379                 if ($this->showgrade) {
380                     if ($grade_grade->grade_item->needsupdate) {
381                         $data['grade']['class'] = $class.' gradingerror';
382                         $data['grade']['content'] = get_string('error');
383                     } else if (!empty($CFG->grade_hiddenasdate) and $grade_grade->get_datesubmitted() and !$this->canviewhidden and $grade_grade->is_hidden()
384                            and !$grade_grade->grade_item->is_category_item() and !$grade_grade->grade_item->is_course_item()) {
385                         // 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
386                         $class .= ' datesubmitted';
387                         $data['grade']['class'] = $class;
388                         $data['grade']['content'] = get_string('submittedon', 'grades', userdate($grade_grade->get_datesubmitted(), get_string('strftimedatetimeshort')));
390                     } elseif ($grade_grade->is_hidden()) {
391                             $data['grade']['class'] = $class.' hidden';
392                             $data['grade']['content'] = '-';
393                     } else {
394                         $data['grade']['class'] = $class;
395                         $gradeval = $this->blank_hidden_total($this->courseid, $grade_grade->grade_item, $gradeval);
396                         $data['grade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true);
397                     }
398                 }
400                 // Range
401                 if ($this->showrange) {
402                     $data['range']['class'] = $class;
403                     $data['range']['content'] = $grade_grade->grade_item->get_formatted_range(GRADE_DISPLAY_TYPE_REAL, $this->rangedecimals);
404                 }
406                 // Percentage
407                 if ($this->showpercentage) {
408                     if ($grade_grade->grade_item->needsupdate) {
409                         $data['percentage']['class'] = $class.' gradingerror';
410                         $data['percentage']['content'] = get_string('error');
411                     } else if ($grade_grade->is_hidden()) {
412                         $data['percentage']['class'] = $class.' hidden';
413                         $data['percentage']['content'] = '-';
414                     } else {
415                         $data['percentage']['class'] = $class;
416                         $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE);
417                     }
418                 }
420                 // Lettergrade
421                 if ($this->showlettergrade) {
422                     if ($grade_grade->grade_item->needsupdate) {
423                         $data['lettergrade']['class'] = $class.' gradingerror';
424                         $data['lettergrade']['content'] = get_string('error');
425                     } else if ($grade_grade->is_hidden()) {
426                         $data['lettergrade']['class'] = $class.' hidden';
427                         if (!$this->canviewhidden) {
428                             $data['lettergrade']['content'] = '-';
429                         } else {
430                             $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER);
431                         }
432                     } else {
433                         $data['lettergrade']['class'] = $class;
434                         $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER);
435                     }
436                 }
438                 // Rank
439                 if ($this->showrank) {
440                     if ($grade_grade->grade_item->needsupdate) {
441                         $data['rank']['class'] = $class.' gradingerror';
442                         $data['rank']['content'] = get_string('error');
443                         } elseif ($grade_grade->is_hidden()) {
444                             $data['rank']['class'] = $class.' hidden';
445                             $data['rank']['content'] = '-';
446                     } else if (is_null($gradeval)) {
447                         // no grade, no rank
448                         $data['rank']['class'] = $class;
449                         $data['rank']['content'] = '-';
451                     } else {
452                         /// find the number of users with a higher grade
453                         $sql = "SELECT COUNT(DISTINCT(userid))
454                                   FROM {grade_grades}
455                                  WHERE finalgrade > ?
456                                        AND itemid = ?
457                                        AND hidden = 0";
458                         $rank = $DB->count_records_sql($sql, array($grade_grade->finalgrade, $grade_grade->grade_item->id)) + 1;
460                         $data['rank']['class'] = $class;
461                         $data['rank']['content'] = "$rank/".$this->get_numusers(false); // total course users
462                     }
463                 }
465                 // Average
466                 if ($this->showaverage) {
467                     $data['average']['class'] = $class;
468                     if (!empty($this->gtree->items[$eid]->avg)) {
469                         $data['average']['content'] = $this->gtree->items[$eid]->avg;
470                     } else {
471                         $data['average']['content'] = '-';
472                     }
473                 }
475                 // Feedback
476                 if ($this->showfeedback) {
477                     if ($grade_grade->overridden > 0 AND ($type == 'categoryitem' OR $type == 'courseitem')) {
478                     $data['feedback']['class'] = $class.' feedbacktext';
479                         $data['feedback']['content'] = get_string('overridden', 'grades').': ' . format_text($grade_grade->feedback, $grade_grade->feedbackformat);
480                     } else if (empty($grade_grade->feedback) or (!$this->canviewhidden and $grade_grade->is_hidden())) {
481                         $data['feedback']['class'] = $class.' feedbacktext';
482                         $data['feedback']['content'] = '&nbsp;';
483                     } else {
484                         $data['feedback']['class'] = $class.' feedbacktext';
485                         $data['feedback']['content'] = format_text($grade_grade->feedback, $grade_grade->feedbackformat);
486                     }
487                 }
488             }
489         }
491         /// Category
492         if ($type == 'category') {
493             $data['leader']['class'] = $class.' '.$alter."d$depth b1t b2b b1l";
494             $data['leader']['rowspan'] = $element['rowspan'];
496             if ($this->switch) { // alter style based on whether aggregation is first or last
497                $data['itemname']['class'] = $class.' '.$alter."d$depth b1b b1t";
498             } else {
499                $data['itemname']['class'] = $class.' '.$alter."d$depth b2t";
500             }
501             $data['itemname']['colspan'] = ($this->maxdepth - $depth + count($this->tablecolumns) - 1);
502             $data['itemname']['content'] = $fullname;
503         }
505         /// Add this row to the overall system
506         $this->tabledata[] = $data;
508         /// Recursively iterate through all child elements
509         if (isset($element['children'])) {
510             foreach ($element['children'] as $key=>$child) {
511                 $this->fill_table_recursive($element['children'][$key]);
512             }
513         }
514     }
516     /**
517      * Prints or returns the HTML from the flexitable.
518      * @param bool $return Whether or not to return the data instead of printing it directly.
519      * @return string
520      */
521     public function print_table($return=false) {
522          $maxspan = $this->maxdepth;
524         /// Build table structure
525         $html = "
526             <table cellspacing='0' cellpadding='0' class='boxaligncenter generaltable user-grade'>
527             <thead>
528                 <tr>
529                     <th class=\"header\" colspan='$maxspan'>".$this->tableheaders[0]."</th>\n";
531         for ($i = 1; $i < count($this->tableheaders); $i++) {
532             $html .= "<th class=\"header\">".$this->tableheaders[$i]."</th>\n";
533         }
535         $html .= "
536                 </tr>
537             </thead>
538             <tbody>\n";
540         /// Print out the table data
541         for ($i = 0; $i < count($this->tabledata); $i++) {
542             $html .= "<tr>\n";
543             if (isset($this->tabledata[$i]['leader'])) {
544                 $rowspan = $this->tabledata[$i]['leader']['rowspan'];
545                 $class = $this->tabledata[$i]['leader']['class'];
546                 $html .= "<td class='$class' rowspan='$rowspan'></td>\n";
547             }
548             for ($j = 0; $j < count($this->tablecolumns); $j++) {
549                 $name = $this->tablecolumns[$j];
550                 $class = (isset($this->tabledata[$i][$name]['class'])) ? $this->tabledata[$i][$name]['class'] : '';
551                 $colspan = (isset($this->tabledata[$i][$name]['colspan'])) ? "colspan='".$this->tabledata[$i][$name]['colspan']."'" : '';
552                 $content = (isset($this->tabledata[$i][$name]['content'])) ? $this->tabledata[$i][$name]['content'] : null;
553                 if (isset($content)) {
554                     $html .= "<td class='$class' $colspan>$content</td>\n";
555                 }
556             }
557             $html .= "</tr>\n";
558         }
560         $html .= "</tbody></table>";
562         if ($return) {
563             return $html;
564         } else {
565             echo $html;
566         }
567     }
569     /**
570      * Processes the data sent by the form (grades and feedbacks).
571      * @var array $data
572      * @return bool Success or Failure (array of errors).
573      */
574     function process_data($data) {
575     }
576     function process_action($target, $action) {
577     }
579     /**
580      * Builds the grade item averages.
581      *
582      */
583     function calculate_averages() {
584         global $USER, $DB;
586         if ($this->showaverage) {
587             // this settings are actually grader report settings (not user report)
588             // however we're using them as having two separate but identical settings the
589             // user would have to keep in sync would be annoying
590             $averagesdisplaytype   = $this->get_pref('averagesdisplaytype');
591             $averagesdecimalpoints = $this->get_pref('averagesdecimalpoints');
592             $meanselection         = $this->get_pref('meanselection');
593             $shownumberofgrades    = $this->get_pref('shownumberofgrades');
595             $avghtml = '';
596             $avgcssclass = 'avg';
598             $straverage = get_string('overallaverage', 'grades');
600             $groupsql = $this->groupsql;
601             $groupwheresql = $this->groupwheresql;
602             //$groupwheresqlparams = ;
604             if ($shownumberofgrades) {
605                 $straverage .= ' (' . get_string('submissions', 'grades') . ') ';
606             }
608             $totalcount = $this->get_numusers(false);
610             //limit to users with a gradeable role ie students
611             list($gradebookrolessql, $gradebookrolesparams) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0');
613             //limit to users with an active enrolment
614             list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->context);
616             $params = array_merge($this->groupwheresql_params, $gradebookrolesparams, $enrolledparams);
617             $params['courseid'] = $this->courseid;
619             // find sums of all grade items in course
620             $sql = "SELECT gg.itemid, SUM(gg.finalgrade) AS sum
621                       FROM {grade_items} gi
622                       JOIN {grade_grades} gg ON gg.itemid = gi.id
623                       JOIN {user} u ON u.id = gg.userid
624                       JOIN ($enrolledsql) je ON je.id = gg.userid
625                       JOIN (
626                                    SELECT DISTINCT ra.userid
627                                      FROM {role_assignments} ra
628                                     WHERE ra.roleid $gradebookrolessql
629                                       AND ra.contextid " . get_related_contexts_string($this->context) . "
630                            ) rainner ON rainner.userid = u.id
631                       $groupsql
632                      WHERE gi.courseid = :courseid
633                        AND u.deleted = 0
634                        AND gg.finalgrade IS NOT NULL
635                        AND gg.hidden = 0
636                        $groupwheresql
637                   GROUP BY gg.itemid";
639             $sum_array = array();
640             $sums = $DB->get_recordset_sql($sql, $params);
641             foreach ($sums as $itemid => $csum) {
642                 $sum_array[$itemid] = $csum->sum;
643             }
644             $sums->close();
646             $columncount=0;
648             // Empty grades must be evaluated as grademin, NOT always 0
649             // This query returns a count of ungraded grades (NULL finalgrade OR no matching record in grade_grades table)
650             // No join condition when joining grade_items and user to get a grade item row for every user
651             // Then left join with grade_grades and look for rows with null final grade (which includes grade items with no grade_grade)
652             $sql = "SELECT gi.id, COUNT(u.id) AS count
653                       FROM {grade_items} gi
654                       JOIN {user} u ON u.deleted = 0
655                       JOIN ($enrolledsql) je ON je.id = u.id
656                       JOIN (
657                                SELECT DISTINCT ra.userid
658                                  FROM {role_assignments} ra
659                                 WHERE ra.roleid $gradebookrolessql
660                                   AND ra.contextid " . get_related_contexts_string($this->context) . "
661                            ) rainner ON rainner.userid = u.id
662                       LEFT JOIN {grade_grades} gg
663                              ON (gg.itemid = gi.id AND gg.userid = u.id AND gg.finalgrade IS NOT NULL AND gg.hidden = 0)
664                       $groupsql
665                      WHERE gi.courseid = :courseid
666                            AND gg.finalgrade IS NULL
667                            $groupwheresql
668                   GROUP BY gi.id";
670             $ungraded_counts = $DB->get_records_sql($sql, $params);
672             foreach ($this->gtree->items as $itemid=>$unused) {
673                 if (!empty($this->gtree->items[$itemid]->avg)) {
674                     continue;
675                 }
676                 $item = $this->gtree->items[$itemid];
678                 if ($item->needsupdate) {
679                     $avghtml .= '<td class="cell c' . $columncount++.'"><span class="gradingerror">'.get_string('error').'</span></td>';
680                     continue;
681                 }
683                 if (empty($sum_array[$item->id])) {
684                     $sum_array[$item->id] = 0;
685                 }
687                 if (empty($ungraded_counts[$itemid])) {
688                     $ungraded_count = 0;
689                 } else {
690                     $ungraded_count = $ungraded_counts[$itemid]->count;
691                 }
693                 //do they want the averages to include all grade items
694                 if ($meanselection == GRADE_REPORT_MEAN_GRADED) {
695                     $mean_count = $totalcount - $ungraded_count;
696                 } else { // Bump up the sum by the number of ungraded items * grademin
697                     $sum_array[$item->id] += ($ungraded_count * $item->grademin);
698                     $mean_count = $totalcount;
699                 }
701                 $decimalpoints = $item->get_decimals();
703                 // Determine which display type to use for this average
704                 if (!empty($USER->gradeediting) && $USER->gradeediting[$this->courseid]) {
705                     $displaytype = GRADE_DISPLAY_TYPE_REAL;
707                 } else if ($averagesdisplaytype == GRADE_REPORT_PREFERENCE_INHERIT) { // no ==0 here, please resave the report and user preferences
708                     $displaytype = $item->get_displaytype();
710                 } else {
711                     $displaytype = $averagesdisplaytype;
712                 }
714                 // Override grade_item setting if a display preference (not inherit) was set for the averages
715                 if ($averagesdecimalpoints == GRADE_REPORT_PREFERENCE_INHERIT) {
716                     $decimalpoints = $item->get_decimals();
718                 } else {
719                     $decimalpoints = $averagesdecimalpoints;
720                 }
722                 if (empty($sum_array[$item->id]) || $mean_count == 0) {
723                     $this->gtree->items[$itemid]->avg = '-';
724                 } else {
725                     $sum = $sum_array[$item->id];
726                     $avgradeval = $sum/$mean_count;
727                     $gradehtml = grade_format_gradevalue($avgradeval, $item, true, $displaytype, $decimalpoints);
729                     $numberofgrades = '';
730                     if ($shownumberofgrades) {
731                         $numberofgrades = " ($mean_count)";
732                     }
734                     $this->gtree->items[$itemid]->avg = $gradehtml.$numberofgrades;
735                 }
736             }
737         }
738     }
741 function grade_report_user_settings_definition(&$mform) {
742     global $CFG;
744     $options = array(-1 => get_string('default', 'grades'),
745                       0 => get_string('hide'),
746                       1 => get_string('show'));
748     if (empty($CFG->grade_report_user_showrank)) {
749         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
750     } else {
751         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
752     }
754     $mform->addElement('select', 'report_user_showrank', get_string('showrank', 'grades'), $options);
755     $mform->addHelpButton('report_user_showrank', 'showrank', 'grades');
757     if (empty($CFG->grade_report_user_showpercentage)) {
758         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
759     } else {
760         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
761     }
763     $mform->addElement('select', 'report_user_showpercentage', get_string('showpercentage', 'grades'), $options);
764     $mform->addHelpButton('report_user_showpercentage', 'showpercentage', 'grades');
766     if (empty($CFG->grade_report_user_showgrade)) {
767         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
768     } else {
769         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
770     }
772     $mform->addElement('select', 'report_user_showgrade', get_string('showgrade', 'grades'), $options);
774     if (empty($CFG->grade_report_user_showfeedback)) {
775         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
776     } else {
777         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
778     }
780     $mform->addElement('select', 'report_user_showfeedback', get_string('showfeedback', 'grades'), $options);
782     if (empty($CFG->grade_report_user_showweight)) {
783         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
784     } else {
785         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
786     }
788     $mform->addElement('select', 'report_user_showweight', get_string('showweight', 'grades'), $options);
790     if (empty($CFG->grade_report_user_showaverage)) {
791         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
792     } else {
793         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
794     }
796     $mform->addElement('select', 'report_user_showaverage', get_string('showaverage', 'grades'), $options);
797     $mform->addHelpButton('report_user_showaverage', 'showaverage', 'grades');
799     if (empty($CFG->grade_report_user_showlettergrade)) {
800         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
801     } else {
802         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
803     }
805     $mform->addElement('select', 'report_user_showlettergrade', get_string('showlettergrade', 'grades'), $options);
807     if (empty($CFG->grade_report_user_showrange)) {
808         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
809     } else {
810         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
811     }
813     $mform->addElement('select', 'report_user_showrange', get_string('showrange', 'grades'), $options);
815     $options = array(0=>0, 1=>1, 2=>2, 3=>3, 4=>4, 5=>5);
816     if (! empty($CFG->grade_report_user_rangedecimals)) {
817         $options[-1] = $options[$CFG->grade_report_user_rangedecimals];
818     }
819     $mform->addElement('select', 'report_user_rangedecimals', get_string('rangedecimals', 'grades'), $options);
821     $options = array(-1 => get_string('default', 'grades'),
822                       0 => get_string('shownohidden', 'grades'),
823                       1 => get_string('showhiddenuntilonly', 'grades'),
824                       2 => get_string('showallhidden', 'grades'));
826     if (empty($CFG->grade_report_user_showhiddenitems)) {
827         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
828     } else {
829         $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_user_showhiddenitems]);
830     }
832     $mform->addElement('select', 'report_user_showhiddenitems', get_string('showhiddenitems', 'grades'), $options);
833     $mform->addHelpButton('report_user_showhiddenitems', 'showhiddenitems', 'grades');
835     //showtotalsifcontainhidden
836     $options = array(-1 => get_string('default', 'grades'),
837                       GRADE_REPORT_HIDE_TOTAL_IF_CONTAINS_HIDDEN => get_string('hide'),
838                       GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowexhiddenitems', 'grades'),
839                       GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowinchiddenitems', 'grades') );
841     if (empty($CFG->grade_report_user_showtotalsifcontainhidden)) {
842         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
843     } else {
844         $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_user_showtotalsifcontainhidden]);
845     }
847     $mform->addElement('select', 'report_user_showtotalsifcontainhidden', get_string('hidetotalifhiddenitems', 'grades'), $options);
848     $mform->addHelpButton('report_user_showtotalsifcontainhidden', 'hidetotalifhiddenitems', 'grades');
851 function grade_report_user_profilereport($course, $user) {
852     global $OUTPUT;
853     if (!empty($course->showgrades)) {
855         $context = get_context_instance(CONTEXT_COURSE, $course->id);
857         //first make sure we have proper final grades - this must be done before constructing of the grade tree
858         grade_regrade_final_grades($course->id);
860         /// return tracking object
861         $gpr = new grade_plugin_return(array('type'=>'report', 'plugin'=>'user', 'courseid'=>$course->id, 'userid'=>$user->id));
862         // Create a report instance
863         $report = new grade_report_user($course->id, $gpr, $context, $user->id);
865         // print the page
866         echo '<div class="grade-report-user">'; // css fix to share styles with real report page
867         echo $OUTPUT->heading(get_string('pluginname', 'gradereport_user'). ' - '.fullname($report->user));
869         if ($report->fill_table()) {
870             echo $report->print_table(true);
871         }
872         echo '</div>';
873     }