MDL-48273 singleview: add load_user method and other group validations
[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 description for the screen.
57      *
58      * @return string
59      */
60     public function description() {
61         return get_string('gradeitems', 'grades');
62     }
64     /**
65      * Convert the list of items to a list of options.
66      *
67      * @return array
68      */
69     public function options() {
70         $result = array();
71         foreach ($this->items as $itemid => $item) {
72             $result[$itemid] = $item->get_name();
73         }
74         return $result;
75     }
77     /**
78      * Get the type of items on this screen.
79      *
80      * @return string
81      */
82     public function item_type() {
83         return 'grade';
84     }
86     /**
87      * Should we show the group selector on this screen?
88      *
89      * @return bool
90      */
91     public function display_group_selector() {
92         return false;
93     }
95     /**
96      * Init the screen
97      *
98      * @param bool $selfitemisempty Have we selected an item yet?
99      */
100     public function init($selfitemisempty = false) {
101         global $DB;
103         if (!$selfitemisempty) {
104             $validusers = $this->load_users();
105             if (!isset($validusers[$this->itemid])) {
106                 print_error('invaliduserid');
107             }
108             $this->item = $validusers[$this->itemid];
109         }
111         $params = array('courseid' => $this->courseid);
113         $seq = new grade_seq($this->courseid, true);
114         foreach ($seq->items as $key => $item) {
115             if (isset($item->itemmodule)) {
116                 list($courseid, $cmid) = get_course_and_cm_from_instance($item->iteminstance, $item->itemmodule);
117                 $seq->items[$key]->cmid = $cmid->id;
118             }
119         }
121         $this->items = array();
122         foreach ($seq->items as $itemid => $item) {
123             if (grade::filter($item)) {
124                 $this->items[$itemid] = $item;
125             }
126         }
128         $this->requirespaging = count($this->items) > $this->perpage;
130         $this->setup_structure();
132         $this->definition = array(
133             'finalgrade', 'feedback', 'override', 'exclude'
134         );
135         $this->set_headers($this->original_headers());
136     }
138     /**
139      * Get the list of headers for the table.
140      *
141      * @return array List of headers
142      */
143     public function original_headers() {
144         return array(
145             '', // For filter icon.
146             get_string('assessmentname', 'gradereport_singleview'),
147             get_string('gradecategory', 'grades'),
148             get_string('range', 'grades'),
149             get_string('grade', 'grades'),
150             get_string('feedback', 'grades'),
151             $this->make_toggle_links('override'),
152             $this->make_toggle_links('exclude')
153         );
154     }
156     /**
157      * Format each row of the table.
158      *
159      * @param grade_item $item
160      * @return string
161      */
162     public function format_line($item) {
163         global $OUTPUT;
165         $grade = $this->fetch_grade_or_default($item, $this->item->id);
166         $lockicon = '';
168         $lockeditem = $lockeditemgrade = 0;
169         if (!empty($grade->locked)) {
170             $lockeditem = 1;
171         }
172         if (!empty($grade->grade_item->locked)) {
173             $lockeditemgrade = 1;
174         }
175         // Check both grade and grade item.
176         if ($lockeditem || $lockeditemgrade) {
177              $lockicon = $OUTPUT->pix_icon('t/locked', 'grade is locked');
178         }
180         $realmodid = '';
181         if (isset($item->cmid)) {
182             $realmodid = $item->cmid;
183         }
185         $iconstring = get_string('filtergrades', 'gradereport_singleview', $item->get_name());
187         // Create a fake gradetreeitem so we can call get_element_header().
188         // The type logic below is from grade_category->_get_children_recursion().
189         $gradetreeitem = array();
190         if (in_array($item->itemtype, array('course', 'category'))) {
191             $gradetreeitem['type'] = $item->itemtype.'item';
192         } else {
193             $gradetreeitem['type'] = 'item';
194         }
195         $gradetreeitem['object'] = $item;
196         $gradetreeitem['userid'] = $this->item->id;
198         $itemlabel = $this->structure->get_element_header($gradetreeitem, true, false, false, false, true);
199         $grade->label = $item->get_name();
201         $itemlabel = $item->get_name();
202         if (!empty($realmodid)) {
203             $url = new moodle_url('/mod/' . $item->itemmodule . '/view.php', array('id' => $realmodid));
204             $itemlabel = html_writer::link($url, $item->get_name());
205         }
207         $line = array(
208             $OUTPUT->action_icon($this->format_link('grade', $item->id), new pix_icon('t/editstring', $iconstring)),
209             $this->format_icon($item) . $lockicon . $itemlabel,
210             $this->category($item),
211             new range($item)
212         );
213         $lineclasses = array(
214             "action",
215             "gradeitem",
216             "category",
217             "range"
218         );
220         $outputline = array();
221         $i = 0;
222         foreach ($line as $key => $value) {
223             $cell = new \html_table_cell($value);
224             if ($isheader = $i == 1) {
225                 $cell->header = $isheader;
226                 $cell->scope = "row";
227             }
228             if (array_key_exists($key, $lineclasses)) {
229                 $cell->attributes['class'] = $lineclasses[$key];
230             }
231             $outputline[] = $cell;
232             $i++;
233         }
235         return $this->format_definition($outputline, $grade);
236     }
238     /**
239      * Helper to get the icon for an item.
240      *
241      * @param grade_item $item
242      * @return string
243      */
244     private function format_icon($item) {
245         $element = array('type' => 'item', 'object' => $item);
246         return $this->structure->get_element_icon($element);
247     }
249     /**
250      * Helper to get the category for an item.
251      *
252      * @param grade_item $item
253      * @return grade_category
254      */
255     private function category($item) {
256         global $DB;
258         if (empty($item->categoryid)) {
260             if ($item->itemtype == 'course') {
261                 return $this->course->fullname;
262             }
264             $params = array('id' => $item->iteminstance);
265             $elem = $DB->get_record('grade_categories', $params);
267             return $elem->fullname;
268         }
270         if (!isset($this->categories[$item->categoryid])) {
271             $category = $item->get_parent_category();
273             $this->categories[$category->id] = $category;
274         }
276         return $this->categories[$item->categoryid]->get_name();
277     }
279     /**
280      * Get the heading for the page.
281      *
282      * @return string
283      */
284     public function heading() {
285         return fullname($this->item);
286     }
288     /**
289      * Get the summary for this table.
290      *
291      * @return string
292      */
293     public function summary() {
294         return get_string('summaryuser', 'gradereport_singleview');
295     }
297     /**
298      * Default pager
299      *
300      * @return string
301      */
302     public function pager() {
303         global $OUTPUT;
305         if (!$this->supports_paging()) {
306             return '';
307         }
309         return $OUTPUT->paging_bar(
310             count($this->items), $this->page, $this->perpage,
311             new moodle_url('/grade/report/singleview/index.php', array(
312                 'perpage' => $this->perpage,
313                 'id' => $this->courseid,
314                 'group' => $this->groupid,
315                 'itemid' => $this->itemid,
316                 'item' => 'user'
317             ))
318         );
319     }
321     /**
322      * Does this page require paging?
323      *
324      * @return bool
325      */
326     public function supports_paging() {
327         return $this->requirespaging;
328     }
331     /**
332      * Process the data from the form.
333      *
334      * @param array $data
335      * @return array of warnings
336      */
337     public function process($data) {
338         $bulk = new bulk_insert($this->item);
339         // Bulk insert messages the data to be passed in
340         // ie: for all grades of empty grades apply the specified value.
341         if ($bulk->is_applied($data)) {
342             $filter = $bulk->get_type($data);
343             $insertvalue = $bulk->get_insert_value($data);
345             $userid = $this->item->id;
346             foreach ($this->items as $gradeitemid => $gradeitem) {
347                 $null = $gradeitem->gradetype == GRADE_TYPE_SCALE ? -1 : '';
348                 $field = "finalgrade_{$gradeitem->id}_{$this->itemid}";
349                 if (isset($data->$field)) {
350                     continue;
351                 }
353                 $grade = grade_grade::fetch(array(
354                     'itemid' => $this->itemid,
355                     'userid' => $userid
356                 ));
358                 $data->$field = empty($grade) ? $null : $grade->finalgrade;
359                 $data->{"old$field"} = $data->$field;
361                 preg_match('/_(\d+)_(\d+)/', $field, $oldoverride);
362                 $oldoverride = 'oldoverride' . $oldoverride[0];
363                 if (empty($data->$oldoverride)) {
364                     $data->$field = (!isset($grade->rawgrade)) ? $null : $grade->rawgrade;
365                 }
367             }
369             foreach ($data as $varname => $value) {
370                 if (preg_match('/override_(\d+)_(\d+)/', $varname, $matches)) {
371                     $data->$matches[0] = '1';
372                 }
373                 if (!preg_match('/^finalgrade_(\d+)_(\d+)/', $varname, $matches)) {
374                     continue;
375                 }
377                 $gradeitem = grade_item::fetch(array(
378                     'courseid' => $this->courseid,
379                     'id' => $matches[1]
380                 ));
382                 $isscale = ($gradeitem->gradetype == GRADE_TYPE_SCALE);
384                 $empties = (trim($value) === '' or ($isscale and $value == -1));
386                 if ($filter == 'all' or $empties) {
387                     $data->$varname = ($isscale and empty($insertvalue)) ?
388                         -1 : $insertvalue;
389                 }
390             }
391         }
392         return parent::process($data);
393     }