Merge branch 'MDL-68343-master' of git://github.com/rezaies/moodle
[moodle.git] / grade / report / singleview / classes / local / screen / user.php
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/>.
17 /**
18  * The user screen.
19  *
20  * @package   gradereport_singleview
21  * @copyright 2014 Moodle Pty Ltd (http://moodle.com)
22  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23  */
25 namespace gradereport_singleview\local\screen;
27 use grade_seq;
28 use gradereport_singleview;
29 use moodle_url;
30 use pix_icon;
31 use html_writer;
32 use gradereport_singleview\local\ui\range;
33 use gradereport_singleview\local\ui\bulk_insert;
34 use grade_item;
35 use grade_grade;
36 use stdClass;
38 defined('MOODLE_INTERNAL') || die;
40 /**
41  * The user screen.
42  *
43  * @package   gradereport_singleview
44  * @copyright 2014 Moodle Pty Ltd (http://moodle.com)
45  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46  */
47 class user extends tablelike implements selectable_items {
49     /** @var array $categories A cache for grade_item categories */
50     private $categories = array();
52     /** @var int $requirespaging Do we have more items than the paging limit? */
53     private $requirespaging = true;
55     /**
56      * Get the label for the select box that chooses items for this page.
57      * @return string
58      */
59     public function select_label() {
60         return get_string('selectgrade', 'gradereport_singleview');
61     }
63     /**
64      * Get the description for the screen.
65      *
66      * @return string
67      */
68     public function description() {
69         return get_string('gradeitems', 'grades');
70     }
72     /**
73      * Convert the list of items to a list of options.
74      *
75      * @return array
76      */
77     public function options() {
78         $result = array();
79         foreach ($this->items as $itemid => $item) {
80             $result[$itemid] = $item->get_name();
81         }
82         return $result;
83     }
85     /**
86      * Get the type of items on this screen.
87      *
88      * @return string
89      */
90     public function item_type() {
91         return 'grade';
92     }
94     /**
95      * Init the screen
96      *
97      * @param bool $selfitemisempty Have we selected an item yet?
98      */
99     public function init($selfitemisempty = false) {
100         global $DB;
102         if (!$selfitemisempty) {
103             $validusers = $this->load_users();
104             if (!isset($validusers[$this->itemid])) {
105                 // If the passed user id is not valid, show the first user from the list instead.
106                 $this->item = reset($validusers);
107                 $this->itemid = $this->item->id;
108             } else {
109                 $this->item = $validusers[$this->itemid];
110             }
111         }
113         $params = array('courseid' => $this->courseid);
115         $seq = new grade_seq($this->courseid, true);
117         $this->items = array();
118         foreach ($seq->items as $itemid => $item) {
119             if (grade::filter($item)) {
120                 $this->items[$itemid] = $item;
121             }
122         }
124         $this->requirespaging = count($this->items) > $this->perpage;
126         $this->setup_structure();
128         $this->definition = array(
129             'finalgrade', 'feedback', 'override', 'exclude'
130         );
131         $this->set_headers($this->original_headers());
132     }
134     /**
135      * Get the list of headers for the table.
136      *
137      * @return array List of headers
138      */
139     public function original_headers() {
140         return array(
141             '', // For filter icon.
142             get_string('assessmentname', 'gradereport_singleview'),
143             get_string('gradecategory', 'grades'),
144             get_string('range', 'grades'),
145             get_string('grade', 'grades'),
146             get_string('feedback', 'grades'),
147             $this->make_toggle_links('override'),
148             $this->make_toggle_links('exclude')
149         );
150     }
152     /**
153      * Format each row of the table.
154      *
155      * @param grade_item $item
156      * @return string
157      */
158     public function format_line($item) {
159         global $OUTPUT;
161         $grade = $this->fetch_grade_or_default($item, $this->item->id);
162         $lockicon = '';
164         $lockeditem = $lockeditemgrade = 0;
165         if (!empty($grade->locked)) {
166             $lockeditem = 1;
167         }
168         if (!empty($grade->grade_item->locked)) {
169             $lockeditemgrade = 1;
170         }
171         // Check both grade and grade item.
172         if ($lockeditem || $lockeditemgrade) {
173              $lockicon = $OUTPUT->pix_icon('t/locked', 'grade is locked');
174         }
176         $iconstring = get_string('filtergrades', 'gradereport_singleview', $item->get_name());
178         // Create a fake gradetreeitem so we can call get_element_header().
179         // The type logic below is from grade_category->_get_children_recursion().
180         $gradetreeitem = array();
181         if (in_array($item->itemtype, array('course', 'category'))) {
182             $gradetreeitem['type'] = $item->itemtype.'item';
183         } else {
184             $gradetreeitem['type'] = 'item';
185         }
186         $gradetreeitem['object'] = $item;
187         $gradetreeitem['userid'] = $this->item->id;
189         $itemlabel = $this->structure->get_element_header($gradetreeitem, true, false, false, false, true);
190         $grade->label = $item->get_name();
192         $line = array(
193             $OUTPUT->action_icon($this->format_link('grade', $item->id), new pix_icon('t/editstring', ''), null,
194                     ['title' => $iconstring, 'aria-label' => $iconstring]),
195             $this->format_icon($item) . $lockicon . $itemlabel,
196             $this->category($item),
197             new range($item)
198         );
199         $lineclasses = array(
200             "action",
201             "gradeitem",
202             "category",
203             "range"
204         );
206         $outputline = array();
207         $i = 0;
208         foreach ($line as $key => $value) {
209             $cell = new \html_table_cell($value);
210             if ($isheader = $i == 1) {
211                 $cell->header = $isheader;
212                 $cell->scope = "row";
213             }
214             if (array_key_exists($key, $lineclasses)) {
215                 $cell->attributes['class'] = $lineclasses[$key];
216             }
217             $outputline[] = $cell;
218             $i++;
219         }
221         return $this->format_definition($outputline, $grade);
222     }
224     /**
225      * Helper to get the icon for an item.
226      *
227      * @param grade_item $item
228      * @return string
229      */
230     private function format_icon($item) {
231         $element = array('type' => 'item', 'object' => $item);
232         return $this->structure->get_element_icon($element);
233     }
235     /**
236      * Helper to get the category for an item.
237      *
238      * @param grade_item $item
239      * @return grade_category
240      */
241     private function category($item) {
242         global $DB;
244         if (empty($item->categoryid)) {
246             if ($item->itemtype == 'course') {
247                 return $this->course->fullname;
248             }
250             $params = array('id' => $item->iteminstance);
251             $elem = $DB->get_record('grade_categories', $params);
253             return $elem->fullname;
254         }
256         if (!isset($this->categories[$item->categoryid])) {
257             $category = $item->get_parent_category();
259             $this->categories[$category->id] = $category;
260         }
262         return $this->categories[$item->categoryid]->get_name();
263     }
265     /**
266      * Get the heading for the page.
267      *
268      * @return string
269      */
270     public function heading() {
271         return get_string('gradeuser', 'gradereport_singleview', fullname($this->item));
272     }
274     /**
275      * Get the summary for this table.
276      *
277      * @return string
278      */
279     public function summary() {
280         return get_string('summaryuser', 'gradereport_singleview');
281     }
283     /**
284      * Default pager
285      *
286      * @return string
287      */
288     public function pager() {
289         global $OUTPUT;
291         if (!$this->supports_paging()) {
292             return '';
293         }
295         return $OUTPUT->paging_bar(
296             count($this->items), $this->page, $this->perpage,
297             new moodle_url('/grade/report/singleview/index.php', array(
298                 'perpage' => $this->perpage,
299                 'id' => $this->courseid,
300                 'group' => $this->groupid,
301                 'itemid' => $this->itemid,
302                 'item' => 'user'
303             ))
304         );
305     }
307     /**
308      * Does this page require paging?
309      *
310      * @return bool
311      */
312     public function supports_paging() {
313         return $this->requirespaging;
314     }
317     /**
318      * Process the data from the form.
319      *
320      * @param array $data
321      * @return array of warnings
322      */
323     public function process($data) {
324         $bulk = new bulk_insert($this->item);
325         // Bulk insert messages the data to be passed in
326         // ie: for all grades of empty grades apply the specified value.
327         if ($bulk->is_applied($data)) {
328             $filter = $bulk->get_type($data);
329             $insertvalue = $bulk->get_insert_value($data);
331             $userid = $this->item->id;
332             foreach ($this->items as $gradeitemid => $gradeitem) {
333                 $null = $gradeitem->gradetype == GRADE_TYPE_SCALE ? -1 : '';
334                 $field = "finalgrade_{$gradeitem->id}_{$this->itemid}";
335                 if (isset($data->$field)) {
336                     continue;
337                 }
339                 $oldfinalgradefield = "oldfinalgrade_{$gradeitem->id}_{$this->itemid}";
340                 // Bulk grade changes for all grades need to be processed and shouldn't be skipped if they had a previous grade.
341                 if ($gradeitem->is_course_item() || ($filter != 'all' && !empty($data->$oldfinalgradefield))) {
342                     if ($gradeitem->is_course_item()) {
343                         // The course total should not be overridden.
344                         unset($data->$field);
345                         unset($data->oldfinalgradefield);
346                         $oldoverride = "oldoverride_{$gradeitem->id}_{$this->itemid}";
347                         unset($data->$oldoverride);
348                         $oldfeedback = "oldfeedback_{$gradeitem->id}_{$this->itemid}";
349                         unset($data->$oldfeedback);
350                     }
351                     continue;
352                 }
353                 $grade = grade_grade::fetch(array(
354                     'itemid' => $gradeitemid,
355                     'userid' => $userid
356                 ));
358                 $data->$field = empty($grade) ? $null : $grade->finalgrade;
359                 $data->{"old$field"} = $data->$field;
360             }
362             foreach ($data as $varname => $value) {
363                 if (preg_match('/^oldoverride_(\d+)_(\d+)/', $varname, $matches)) {
364                     // If we've selected overriding all grades.
365                     if ($filter == 'all') {
366                         $override = "override_{$matches[1]}_{$matches[2]}";
367                         $data->$override = '1';
368                     }
369                 }
370                 if (!preg_match('/^finalgrade_(\d+)_(\d+)/', $varname, $matches)) {
371                     continue;
372                 }
374                 $gradeitem = grade_item::fetch(array(
375                     'courseid' => $this->courseid,
376                     'id' => $matches[1]
377                 ));
379                 $isscale = ($gradeitem->gradetype == GRADE_TYPE_SCALE);
381                 $empties = (trim($value) === '' or ($isscale and $value == -1));
383                 if ($filter == 'all' or $empties) {
384                     $data->$varname = ($isscale and empty($insertvalue)) ?
385                         -1 : $insertvalue;
386                 }
387             }
388         }
389         return parent::process($data);
390     }