gradebook MDL-20617 Fixed SQL formatting
[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         $fullname = $this->gtree->get_element_header($element, true, true, true);
308         $data = array();
309         $hidden = '';
310         $excluded = '';
311         $class = '';
313         // If this is a hidden grade category, hide it completely from the user
314         if ($type == 'category' && $grade_object->is_hidden() && !$this->canviewhidden && (
315                 $this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN ||
316                 ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_object->is_hiddenuntil()))) {
317             return false;
318         }
320         if ($type == 'category') {
321             $this->evenodd[$depth] = (($this->evenodd[$depth] + 1) % 2);
322         }
323         $alter = ($this->evenodd[$depth] == 0) ? 'even' : 'odd';
325         /// Process those items that have scores associated
326         if ($type == 'item' or $type == 'categoryitem' or $type == 'courseitem') {
327             if (! $grade_grade = grade_grade::fetch(array('itemid'=>$grade_object->id,'userid'=>$this->user->id))) {
328                 $grade_grade = new grade_grade();
329                 $grade_grade->userid = $this->user->id;
330                 $grade_grade->itemid = $grade_object->id;
331             }
333             $grade_grade->load_grade_item();
335             /// Hidden Items
336             if ($grade_grade->grade_item->is_hidden()) {
337                 $hidden = ' hidden';
338             }
340             // If this is a hidden grade item, hide it completely from the user.
341             if ($grade_grade->is_hidden() && !$this->canviewhidden && (
342                     $this->showhiddenitems == GRADE_REPORT_USER_HIDE_HIDDEN ||
343                     ($this->showhiddenitems == GRADE_REPORT_USER_HIDE_UNTIL && !$grade_grade->is_hiddenuntil()))) {
344                 // return false;
345             } else {
346                 /// Excluded Item
347                 if ($grade_grade->is_excluded()) {
348                     $fullname .= ' ['.get_string('excluded', 'grades').']';
349                     $excluded = ' excluded';
350                 }
352                 /// Other class information
353                 $class = "$hidden $excluded";
354                 if ($this->switch) { // alter style based on whether aggregation is first or last
355                    $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " ".$alter."d$depth baggt b2b" : " item b1b";
356                 } else {
357                    $class .= ($type == 'categoryitem' or $type == 'courseitem') ? " ".$alter."d$depth baggb" : " item b1b";
358                 }
360                 /// Name
361                 $data['itemname']['content'] = $fullname;
362                 $data['itemname']['class'] = $class;
363                 $data['itemname']['colspan'] = ($this->maxdepth - $depth);
365                 /// Actual Grade
366                 $gradeval = $grade_grade->finalgrade;
368                 $class .= " itemcenter ";
369                 if ($this->showweight) {
370                     $data['weight']['class'] = $class;
371                     $data['weight']['content'] = '-';
372                     // has a weight assigned, might be extra credit
373                     if ($grade_object->aggregationcoef > 0 && $type <> 'courseitem') {
374                         $data['weight']['content'] = number_format($grade_object->aggregationcoef,2).'%';
375                     }
376                 }
378                 if ($this->showgrade) {
379                     if ($grade_grade->grade_item->needsupdate) {
380                         $data['grade']['class'] = $class.' gradingerror';
381                         $data['grade']['content'] = get_string('error');
382                     } else if (!empty($CFG->grade_hiddenasdate) and $grade_grade->get_datesubmitted() and !$this->canviewhidden and $grade_grade->is_hidden()
383                            and !$grade_grade->grade_item->is_category_item() and !$grade_grade->grade_item->is_course_item()) {
384                         // 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
385                         $class .= ' datesubmitted';
386                         $data['grade']['class'] = $class;
387                         $data['grade']['content'] = get_string('submittedon', 'grades', userdate($grade_grade->get_datesubmitted(), get_string('strftimedatetimeshort')));
389                     } elseif ($grade_grade->is_hidden()) {
390                             $data['grade']['class'] = $class.' hidden';
391                             $data['grade']['content'] = '-';
392                     } else {
393                         $data['grade']['class'] = $class;
394                         $gradeval = $this->blank_hidden_total($this->courseid, $grade_grade->grade_item, $gradeval);
395                         $data['grade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true);
396                     }
397                 }
399                 // Range
400                 if ($this->showrange) {
401                     $data['range']['class'] = $class;
402                     $data['range']['content'] = $grade_grade->grade_item->get_formatted_range(GRADE_DISPLAY_TYPE_REAL, $this->rangedecimals);
403                 }
405                 // Percentage
406                 if ($this->showpercentage) {
407                     if ($grade_grade->grade_item->needsupdate) {
408                         $data['percentage']['class'] = $class.' gradingerror';
409                         $data['percentage']['content'] = get_string('error');
410                     } else if ($grade_grade->is_hidden()) {
411                         $data['percentage']['class'] = $class.' hidden';
412                         $data['percentage']['content'] = '-';
413                     } else {
414                         $data['percentage']['class'] = $class;
415                         $data['percentage']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_PERCENTAGE);
416                     }
417                 }
419                 // Lettergrade
420                 if ($this->showlettergrade) {
421                     if ($grade_grade->grade_item->needsupdate) {
422                         $data['lettergrade']['class'] = $class.' gradingerror';
423                         $data['lettergrade']['content'] = get_string('error');
424                     } else if ($grade_grade->is_hidden()) {
425                         $data['lettergrade']['class'] = $class.' hidden';
426                         if (!$this->canviewhidden) {
427                             $data['lettergrade']['content'] = '-';
428                         } else {
429                             $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER);
430                         }
431                     } else {
432                         $data['lettergrade']['class'] = $class;
433                         $data['lettergrade']['content'] = grade_format_gradevalue($gradeval, $grade_grade->grade_item, true, GRADE_DISPLAY_TYPE_LETTER);
434                     }
435                 }
437                 // Rank
438                 if ($this->showrank) {
439                     if ($grade_grade->grade_item->needsupdate) {
440                         $data['rank']['class'] = $class.' gradingerror';
441                         $data['rank']['content'] = get_string('error');
442                         } elseif ($grade_grade->is_hidden()) {
443                             $data['rank']['class'] = $class.' hidden';
444                             $data['rank']['content'] = '-';
445                     } else if (is_null($gradeval)) {
446                         // no grade, no rank
447                         $data['rank']['class'] = $class;
448                         $data['rank']['content'] = '-';
450                     } else {
451                         /// find the number of users with a higher grade
452                         $sql = "SELECT COUNT(DISTINCT(userid))
453                                   FROM {grade_grades}
454                                  WHERE finalgrade > ?
455                                        AND itemid = ?
456                                        AND hidden = 0";
457                         $rank = $DB->count_records_sql($sql, array($grade_grade->finalgrade, $grade_grade->grade_item->id)) + 1;
459                         $data['rank']['class'] = $class;
460                         $data['rank']['content'] = "$rank/".$this->get_numusers(false); // total course users
461                     }
462                 }
464                 // Average
465                 if ($this->showaverage) {
466                     $data['average']['class'] = $class;
467                     if (!empty($this->gtree->items[$eid]->avg)) {
468                         $data['average']['content'] = $this->gtree->items[$eid]->avg;
469                     } else {
470                         $data['average']['content'] = '-';
471                     }
472                 }
474                 // Feedback
475                 if ($this->showfeedback) {
476                     if ($grade_grade->overridden > 0 AND ($type == 'categoryitem' OR $type == 'courseitem')) {
477                     $data['feedback']['class'] = $class.' feedbacktext';
478                         $data['feedback']['content'] = get_string('overridden', 'grades').': ' . format_text($grade_grade->feedback, $grade_grade->feedbackformat);
479                     } else if (empty($grade_grade->feedback) or (!$this->canviewhidden and $grade_grade->is_hidden())) {
480                         $data['feedback']['class'] = $class.' feedbacktext';
481                         $data['feedback']['content'] = '&nbsp;';
482                     } else {
483                         $data['feedback']['class'] = $class.' feedbacktext';
484                         $data['feedback']['content'] = format_text($grade_grade->feedback, $grade_grade->feedbackformat);
485                     }
486                 }
487             }
488         }
490         /// Category
491         if ($type == 'category') {
492             $data['leader']['class'] = $class.' '.$alter."d$depth b1t b2b b1l";
493             $data['leader']['rowspan'] = $element['rowspan'];
495             if ($this->switch) { // alter style based on whether aggregation is first or last
496                $data['itemname']['class'] = $class.' '.$alter."d$depth b1b b1t";
497             } else {
498                $data['itemname']['class'] = $class.' '.$alter."d$depth b2t";
499             }
500             $data['itemname']['colspan'] = ($this->maxdepth - $depth + count($this->tablecolumns) - 1);
501             $data['itemname']['content'] = $fullname;
502         }
504         /// Add this row to the overall system
505         $this->tabledata[] = $data;
507         /// Recursively iterate through all child elements
508         if (isset($element['children'])) {
509             foreach ($element['children'] as $key=>$child) {
510                 $this->fill_table_recursive($element['children'][$key]);
511             }
512         }
513     }
515     /**
516      * Prints or returns the HTML from the flexitable.
517      * @param bool $return Whether or not to return the data instead of printing it directly.
518      * @return string
519      */
520     public function print_table($return=false) {
521          $maxspan = $this->maxdepth;
523         /// Build table structure
524         $html = "
525             <table cellspacing='0' cellpadding='0' class='boxaligncenter generaltable user-grade'>
526             <thead>
527                 <tr>
528                     <th class=\"header\" colspan='$maxspan'>".$this->tableheaders[0]."</th>\n";
530         for ($i = 1; $i < count($this->tableheaders); $i++) {
531             $html .= "<th class=\"header\">".$this->tableheaders[$i]."</th>\n";
532         }
534         $html .= "
535                 </tr>
536             </thead>
537             <tbody>\n";
539         /// Print out the table data
540         for ($i = 0; $i < count($this->tabledata); $i++) {
541             $html .= "<tr>\n";
542             if (isset($this->tabledata[$i]['leader'])) {
543                 $rowspan = $this->tabledata[$i]['leader']['rowspan'];
544                 $class = $this->tabledata[$i]['leader']['class'];
545                 $html .= "<td class='$class' rowspan='$rowspan'></td>\n";
546             }
547             for ($j = 0; $j < count($this->tablecolumns); $j++) {
548                 $name = $this->tablecolumns[$j];
549                 $class = (isset($this->tabledata[$i][$name]['class'])) ? $this->tabledata[$i][$name]['class'] : '';
550                 $colspan = (isset($this->tabledata[$i][$name]['colspan'])) ? "colspan='".$this->tabledata[$i][$name]['colspan']."'" : '';
551                 $content = (isset($this->tabledata[$i][$name]['content'])) ? $this->tabledata[$i][$name]['content'] : null;
552                 if (isset($content)) {
553                     $html .= "<td class='$class' $colspan>$content</td>\n";
554                 }
555             }
556             $html .= "</tr>\n";
557         }
559         $html .= "</tbody></table>";
561         if ($return) {
562             return $html;
563         } else {
564             echo $html;
565         }
566     }
568     /**
569      * Processes the data sent by the form (grades and feedbacks).
570      * @var array $data
571      * @return bool Success or Failure (array of errors).
572      */
573     function process_data($data) {
574     }
575     function process_action($target, $action) {
576     }
578     /**
579      * Builds the grade item averages.
580      *
581      */
582     function calculate_averages() {
583         global $USER, $DB;
585         if ($this->showaverage) {
586             // this settings are actually grader report settings (not user report)
587             // however we're using them as having two separate but identical settings the
588             // user would have to keep in sync would be annoying
589             $averagesdisplaytype   = $this->get_pref('averagesdisplaytype');
590             $averagesdecimalpoints = $this->get_pref('averagesdecimalpoints');
591             $meanselection         = $this->get_pref('meanselection');
592             $shownumberofgrades    = $this->get_pref('shownumberofgrades');
594             $avghtml = '';
595             $avgcssclass = 'avg';
597             $straverage = get_string('overallaverage', 'grades');
599             $groupsql = $this->groupsql;
600             $groupwheresql = $this->groupwheresql;
601             //$groupwheresqlparams = ;
603             if ($shownumberofgrades) {
604                 $straverage .= ' (' . get_string('submissions', 'grades') . ') ';
605             }
607             $totalcount = $this->get_numusers(false);
609             //limit to users with a gradeable role ie students
610             list($gradebookrolessql, $gradebookrolesparams) = $DB->get_in_or_equal(explode(',', $this->gradebookroles), SQL_PARAMS_NAMED, 'grbr0');
612             //limit to users with an active enrolment
613             list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->context);
615             $params = array_merge($this->groupwheresql_params, $gradebookrolesparams, $enrolledparams);
616             $params['courseid'] = $this->courseid;
618             // find sums of all grade items in course
619             $sql = "SELECT gg.itemid, SUM(gg.finalgrade) AS sum
620                       FROM {grade_items} gi
621                       JOIN {grade_grades} gg
622                            ON gg.itemid = gi.id
623                       JOIN ($enrolledsql) je
624                            ON je.id = gg.userid
625                       JOIN {role_assignments} ra
626                            ON ra.userid = gg.userid
627                       $groupsql
628                      WHERE gi.courseid = :courseid
629                            AND ra.roleid $gradebookrolessql
630                            AND ra.contextid ".get_related_contexts_string($this->context)."
631                            AND gg.finalgrade IS NOT NULL
632                            AND gg.hidden = 0
633                            $groupwheresql
634                   GROUP BY gg.itemid";
636             $sum_array = array();
637             if ($sums = $DB->get_recordset_sql($sql, $params)) {
638                 foreach ($sums as $itemid => $csum) {
639                     $sum_array[$itemid] = $csum->sum;
640                 }
641                 $sums->close();
642             }
644             $columncount=0;
646             // Empty grades must be evaluated as grademin, NOT always 0
647             // This query returns a count of ungraded grades (NULL finalgrade OR no matching record in grade_grades table)
648             // No join condition when joining grade_items and user to get a grade item row for every user
649             // Then left join with grade_grades and look for rows with null final grade (which includes grade items with no grade_grade)
650             $sql = "SELECT gi.id, COUNT(u.id) AS count
651                       FROM {grade_items} gi
652                       JOIN {user} u
653                       JOIN ($enrolledsql) je
654                            ON je.id = u.id
655                       JOIN {role_assignments} ra
656                            ON ra.userid = u.id
657                       LEFT JOIN {grade_grades} gg
658                            ON (gg.itemid = gi.id AND gg.userid = u.id AND gg.finalgrade IS NOT NULL AND gg.hidden = 0)
659                       $groupsql
660                     WHERE gi.courseid = :courseid
661                           AND ra.roleid $gradebookrolessql
662                           AND ra.contextid ".get_related_contexts_string($this->context)."
663                           AND gg.finalgrade IS NULL
664                           $groupwheresql
665                     GROUP BY gi.id";
667             $ungraded_counts = $DB->get_records_sql($sql, $params);
669             foreach ($this->gtree->items as $itemid=>$unused) {
670                 if (!empty($this->gtree->items[$itemid]->avg)) {
671                     continue;
672                 }
673                 $item = $this->gtree->items[$itemid];
675                 if ($item->needsupdate) {
676                     $avghtml .= '<td class="cell c' . $columncount++.'"><span class="gradingerror">'.get_string('error').'</span></td>';
677                     continue;
678                 }
680                 if (empty($sum_array[$item->id])) {
681                     $sum_array[$item->id] = 0;
682                 }
684                 if (empty($ungraded_counts[$itemid])) {
685                     $ungraded_count = 0;
686                 } else {
687                     $ungraded_count = $ungraded_counts[$itemid]->count;
688                 }
690                 //do they want the averages to include all grade items
691                 if ($meanselection == GRADE_REPORT_MEAN_GRADED) {
692                     $mean_count = $totalcount - $ungraded_count;
693                 } else { // Bump up the sum by the number of ungraded items * grademin
694                     $sum_array[$item->id] += ($ungraded_count * $item->grademin);
695                     $mean_count = $totalcount;
696                 }
698                 $decimalpoints = $item->get_decimals();
700                 // Determine which display type to use for this average
701                 if (!empty($USER->gradeediting) && $USER->gradeediting[$this->courseid]) {
702                     $displaytype = GRADE_DISPLAY_TYPE_REAL;
704                 } else if ($averagesdisplaytype == GRADE_REPORT_PREFERENCE_INHERIT) { // no ==0 here, please resave the report and user preferences
705                     $displaytype = $item->get_displaytype();
707                 } else {
708                     $displaytype = $averagesdisplaytype;
709                 }
711                 // Override grade_item setting if a display preference (not inherit) was set for the averages
712                 if ($averagesdecimalpoints == GRADE_REPORT_PREFERENCE_INHERIT) {
713                     $decimalpoints = $item->get_decimals();
715                 } else {
716                     $decimalpoints = $averagesdecimalpoints;
717                 }
719                 if (empty($sum_array[$item->id]) || $mean_count == 0) {
720                     $this->gtree->items[$itemid]->avg = '-';
721                 } else {
722                     $sum = $sum_array[$item->id];
723                     $avgradeval = $sum/$mean_count;
724                     $gradehtml = grade_format_gradevalue($avgradeval, $item, true, $displaytype, $decimalpoints);
726                     $numberofgrades = '';
727                     if ($shownumberofgrades) {
728                         $numberofgrades = " ($mean_count)";
729                     }
731                     $this->gtree->items[$itemid]->avg = $gradehtml.$numberofgrades;
732                 }
733             }
734         }
735     }
738 function grade_report_user_settings_definition(&$mform) {
739     global $CFG;
741     $options = array(-1 => get_string('default', 'grades'),
742                       0 => get_string('hide'),
743                       1 => get_string('show'));
745     if (empty($CFG->grade_report_user_showrank)) {
746         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
747     } else {
748         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
749     }
751     $mform->addElement('select', 'report_user_showrank', get_string('showrank', 'grades'), $options);
752     $mform->addHelpButton('report_user_showrank', 'showrank', 'grades');
754     if (empty($CFG->grade_report_user_showpercentage)) {
755         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
756     } else {
757         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
758     }
760     $mform->addElement('select', 'report_user_showpercentage', get_string('showpercentage', 'grades'), $options);
761     $mform->addHelpButton('report_user_showpercentage', 'showpercentage', 'grades');
763     if (empty($CFG->grade_report_user_showgrade)) {
764         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
765     } else {
766         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
767     }
769     $mform->addElement('select', 'report_user_showgrade', get_string('showgrade', 'grades'), $options);
771     if (empty($CFG->grade_report_user_showfeedback)) {
772         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
773     } else {
774         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
775     }
777     $mform->addElement('select', 'report_user_showfeedback', get_string('showfeedback', 'grades'), $options);
779     if (empty($CFG->grade_report_user_showweight)) {
780         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
781     } else {
782         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
783     }
785     $mform->addElement('select', 'report_user_showweight', get_string('showweight', 'grades'), $options);
787     if (empty($CFG->grade_report_user_showaverage)) {
788         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
789     } else {
790         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
791     }
793     $mform->addElement('select', 'report_user_showaverage', get_string('showaverage', 'grades'), $options);
794     $mform->addHelpButton('report_user_showaverage', 'showaverage', 'grades');
796     if (empty($CFG->grade_report_user_showlettergrade)) {
797         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
798     } else {
799         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
800     }
802     $mform->addElement('select', 'report_user_showlettergrade', get_string('showlettergrade', 'grades'), $options);
804     if (empty($CFG->grade_report_user_showrange)) {
805         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
806     } else {
807         $options[-1] = get_string('defaultprev', 'grades', $options[1]);
808     }
810     $mform->addElement('select', 'report_user_showrange', get_string('showrange', 'grades'), $options);
812     $options = array(0=>0, 1=>1, 2=>2, 3=>3, 4=>4, 5=>5);
813     if (! empty($CFG->grade_report_user_rangedecimals)) {
814         $options[-1] = $options[$CFG->grade_report_user_rangedecimals];
815     }
816     $mform->addElement('select', 'report_user_rangedecimals', get_string('rangedecimals', 'grades'), $options);
818     $options = array(-1 => get_string('default', 'grades'),
819                       0 => get_string('shownohidden', 'grades'),
820                       1 => get_string('showhiddenuntilonly', 'grades'),
821                       2 => get_string('showallhidden', 'grades'));
823     if (empty($CFG->grade_report_user_showhiddenitems)) {
824         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
825     } else {
826         $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_user_showhiddenitems]);
827     }
829     $mform->addElement('select', 'report_user_showhiddenitems', get_string('showhiddenitems', 'grades'), $options);
830     $mform->addHelpButton('report_user_showhiddenitems', 'showhiddenitems', 'grades');
832     //showtotalsifcontainhidden
833     $options = array(-1 => get_string('default', 'grades'),
834                       GRADE_REPORT_HIDE_TOTAL_IF_CONTAINS_HIDDEN => get_string('hide'),
835                       GRADE_REPORT_SHOW_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowexhiddenitems', 'grades'),
836                       GRADE_REPORT_SHOW_REAL_TOTAL_IF_CONTAINS_HIDDEN => get_string('hidetotalshowinchiddenitems', 'grades') );
838     if (empty($CFG->grade_report_user_showtotalsifcontainhidden)) {
839         $options[-1] = get_string('defaultprev', 'grades', $options[0]);
840     } else {
841         $options[-1] = get_string('defaultprev', 'grades', $options[$CFG->grade_report_user_showtotalsifcontainhidden]);
842     }
844     $mform->addElement('select', 'report_user_showtotalsifcontainhidden', get_string('hidetotalifhiddenitems', 'grades'), $options);
845     $mform->addHelpButton('report_user_showtotalsifcontainhidden', 'hidetotalifhiddenitems', 'grades');
848 function grade_report_user_profilereport($course, $user) {
849     global $OUTPUT;
850     if (!empty($course->showgrades)) {
852         $context = get_context_instance(CONTEXT_COURSE, $course->id);
854         //first make sure we have proper final grades - this must be done before constructing of the grade tree
855         grade_regrade_final_grades($course->id);
857         /// return tracking object
858         $gpr = new grade_plugin_return(array('type'=>'report', 'plugin'=>'user', 'courseid'=>$course->id, 'userid'=>$user->id));
859         // Create a report instance
860         $report = new grade_report_user($course->id, $gpr, $context, $user->id);
862         // print the page
863         echo '<div class="grade-report-user">'; // css fix to share styles with real report page
864         echo $OUTPUT->heading(get_string('pluginname', 'gradereport_user'). ' - '.fullname($report->user));
866         if ($report->fill_table()) {
867             echo $report->print_table(true);
868         }
869         echo '</div>';
870     }