MDL-60915 core_dml: fix miscellaneous incorrect recordset usage
[moodle.git] / grade / report / singleview / classes / local / screen / screen.php
blobdb3ecb601e36fdb37fc8728ebcc774995b4f1a12
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.
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 * Abstract class used as a base for the 3 screens.
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
25 namespace gradereport_singleview\local\screen;
27 use context_course;
28 use moodle_url;
29 use html_writer;
30 use grade_structure;
31 use grade_grade;
32 use grade_item;
33 use stdClass;
35 defined('MOODLE_INTERNAL') || die;
37 /**
38 * Abstract class used as a base for the 3 screens.
40 * @package gradereport_singleview
41 * @copyright 2014 Moodle Pty Ltd (http://moodle.com)
42 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
44 abstract class screen {
46 /** @var int $courseid The id of the course */
47 protected $courseid;
49 /** @var int $itemid Either a user id or a grade_item id */
50 protected $itemid;
52 /** @var int $groupid The currently set groupid (if set) */
53 protected $groupid;
55 /** @var course_context $context The course context */
56 protected $context;
58 /** @var int $page The page number */
59 protected $page;
61 /** @var int $perpage Results per page */
62 protected $perpage;
64 /** @var array $items List of items on the page, they could be users or grade_items */
65 protected $items;
67 /** @var array $validperpage List of allowed values for 'perpage' setting */
68 protected static $validperpage = [20, 50, 100, 200, 400, 1000, 5000];
70 /**
71 * Constructor
73 * @param int $courseid The course id
74 * @param int $itemid The item id
75 * @param int $groupid The group id
77 public function __construct($courseid, $itemid, $groupid = null) {
78 global $DB;
80 $this->courseid = $courseid;
81 $this->itemid = $itemid;
82 $this->groupid = $groupid;
84 $this->context = context_course::instance($this->courseid);
85 $this->course = $DB->get_record('course', array('id' => $courseid));
87 $this->page = optional_param('page', 0, PARAM_INT);
89 $cache = \cache::make_from_params(\cache_store::MODE_SESSION, 'gradereport_singleview', 'perpage');
90 $perpage = optional_param('perpage', null, PARAM_INT);
91 if (!in_array($perpage, self::$validperpage)) {
92 // Get from cache.
93 $perpage = $cache->get(get_class($this));
94 } else {
95 // Save to cache.
96 $cache->set(get_class($this), $perpage);
98 if ($perpage) {
99 $this->perpage = $perpage;
100 } else {
101 $this->perpage = 100;
104 $this->init(empty($itemid));
108 * Cache the grade_structure class
110 public function setup_structure() {
111 $this->structure = new grade_structure();
112 $this->structure->modinfo = get_fast_modinfo($this->course);
116 * Create a nice link from a thing (user or grade_item).
118 * @param string $screen
119 * @param int $itemid
120 * @param bool $display Should we wrap this in an anchor ?
121 * @return string The link
123 public function format_link($screen, $itemid, $display = null) {
124 $url = new moodle_url('/grade/report/singleview/index.php', array(
125 'id' => $this->courseid,
126 'item' => $screen,
127 'itemid' => $itemid,
128 'group' => $this->groupid,
131 if ($display) {
132 return html_writer::link($url, $display);
133 } else {
134 return $url;
139 * Get the grade_grade
141 * @param grade_item $item The grade_item
142 * @param int $userid The user id
143 * @return grade_grade
145 public function fetch_grade_or_default($item, $userid) {
146 $grade = grade_grade::fetch(array(
147 'itemid' => $item->id, 'userid' => $userid
150 if (!$grade) {
151 $default = new stdClass;
153 $default->userid = $userid;
154 $default->itemid = $item->id;
155 $default->feedback = '';
157 $grade = new grade_grade($default, false);
160 $grade->grade_item = $item;
162 return $grade;
166 * Make the HTML element that toggles all the checkboxes on or off.
168 * @param string $key A unique key for this control - inserted in the classes.
169 * @return string
171 public function make_toggle($key) {
172 $attrs = array('href' => '#');
174 // Do proper lang strings for title attributes exist for the given key?
175 $strmanager = \get_string_manager();
176 $titleall = get_string('all');
177 $titlenone = get_string('none');
178 if ($strmanager->string_exists(strtolower($key) . 'all', 'gradereport_singleview')) {
179 $titleall = get_string(strtolower($key) . 'all', 'gradereport_singleview');
181 if ($strmanager->string_exists(strtolower($key) . 'none', 'gradereport_singleview')) {
182 $titlenone = get_string(strtolower($key) . 'none', 'gradereport_singleview');
185 $all = html_writer::tag('a', get_string('all'), $attrs + array(
186 'class' => 'include all ' . $key,
187 'title' => $titleall
190 $none = html_writer::tag('a', get_string('none'), $attrs + array(
191 'class' => 'include none ' . $key,
192 'title' => $titlenone
195 return html_writer::tag('span', "$all / $none", array(
196 'class' => 'inclusion_links'
201 * Make a toggle link with some text before it.
203 * @param string $key A unique key for this control - inserted in the classes.
204 * @return string
206 public function make_toggle_links($key) {
207 return get_string($key, 'gradereport_singleview') . ' ' .
208 $this->make_toggle($key);
212 * Get the default heading for the screen.
214 * @return string
216 public function heading() {
217 return get_string('entrypage', 'gradereport_singleview');
221 * Override this to init the screen.
223 * @param boolean $selfitemisempty True if no item has been selected yet.
225 public abstract function init($selfitemisempty = false);
228 * Get the type of items in the list.
230 * @return string
232 public abstract function item_type();
235 * Get the entire screen as a string.
237 * @return string
239 public abstract function html();
242 * Does this screen support paging?
244 * @return bool
246 public function supports_paging() {
247 return true;
251 * Default pager
253 * @return string
255 public function pager() {
256 return '';
260 * Initialise the js for this screen.
262 public function js() {
263 global $PAGE;
265 $module = array(
266 'name' => 'gradereport_singleview',
267 'fullpath' => '/grade/report/singleview/js/singleview.js',
268 'requires' => array('base', 'dom', 'event', 'event-simulate', 'io-base')
271 $PAGE->requires->js_init_call('M.gradereport_singleview.init', array(), false, $module);
275 * Process the data from a form submission.
277 * @param array $data
278 * @return array of warnings
280 public function process($data) {
281 $warnings = array();
283 $fields = $this->definition();
285 // Avoiding execution timeouts when updating
286 // a large amount of grades.
287 $progress = 0;
288 $progressbar = new \core\progress\display_if_slow();
289 $progressbar->start_html();
290 $progressbar->start_progress(get_string('savegrades', 'gradereport_singleview'), count((array) $data) - 1);
291 $changecount = array();
293 foreach ($data as $varname => $throw) {
294 $progressbar->progress($progress);
295 $progress++;
296 if (preg_match("/(\w+)_(\d+)_(\d+)/", $varname, $matches)) {
297 $itemid = $matches[2];
298 $userid = $matches[3];
299 } else {
300 continue;
303 $gradeitem = grade_item::fetch(array(
304 'id' => $itemid, 'courseid' => $this->courseid
307 if (preg_match('/^old[oe]{1}/', $varname)) {
308 $elementname = preg_replace('/^old/', '', $varname);
309 if (!isset($data->$elementname)) {
310 // Decrease the progress because we've increased the
311 // size of the array we are iterating through.
312 $progress--;
313 $data->$elementname = false;
317 if (!in_array($matches[1], $fields)) {
318 continue;
321 if (!$gradeitem) {
322 continue;
325 $grade = $this->fetch_grade_or_default($gradeitem, $userid);
327 $classname = '\\gradereport_singleview\\local\\ui\\' . $matches[1];
328 $element = new $classname($grade);
330 $name = $element->get_name();
331 $oldname = "old$name";
333 $posted = $data->$name;
335 $format = $element->determine_format();
337 if ($format->is_textbox() and trim($data->$name) === '') {
338 $data->$name = null;
341 // Same value; skip.
342 if (isset($data->$oldname) && $data->$oldname == $posted) {
343 continue;
346 // If the user submits Exclude grade elements without the proper.
347 // permissions then we should refuse to update.
348 if ($matches[1] === 'exclude' && !has_capability('moodle/grade:manage', $this->context)){
349 $warnings[] = get_string('nopermissions', 'error', get_string('grade:manage', 'role'));
350 continue;
353 $msg = $element->set($posted);
355 // Optional type.
356 if (!empty($msg)) {
357 $warnings[] = $msg;
359 if (preg_match('/_(\d+)_(\d+)/', $varname, $matchelement)) {
360 $changecount[$matchelement[0]] = 1;
364 // Some post-processing.
365 $eventdata = new stdClass;
366 $eventdata->warnings = $warnings;
367 $eventdata->post_data = $data;
368 $eventdata->instance = $this;
369 $eventdata->changecount = $changecount;
371 $progressbar->end_html();
373 return $eventdata;
377 * By default there are no options.
378 * @return array
380 public function options() {
381 return array();
385 * Should we show the group selector?
386 * @return bool
388 public function display_group_selector() {
389 return true;
393 * Should we show the next prev selector?
394 * @return bool
396 public function supports_next_prev() {
397 return true;
401 * Load a valid list of users for this gradebook as the screen "items".
402 * @return array $users A list of enroled users.
404 protected function load_users() {
405 global $CFG;
407 // Create a graded_users_iterator because it will properly check the groups etc.
408 $defaultgradeshowactiveenrol = !empty($CFG->grade_report_showonlyactiveenrol);
409 $showonlyactiveenrol = get_user_preferences('grade_report_showonlyactiveenrol', $defaultgradeshowactiveenrol);
410 $showonlyactiveenrol = $showonlyactiveenrol || !has_capability('moodle/course:viewsuspendedusers', $this->context);
412 require_once($CFG->dirroot.'/grade/lib.php');
413 $gui = new \graded_users_iterator($this->course, null, $this->groupid);
414 $gui->require_active_enrolment($showonlyactiveenrol);
415 $gui->init();
417 // Flatten the users.
418 $users = array();
419 while ($user = $gui->next_user()) {
420 $users[$user->user->id] = $user->user;
422 $gui->close();
423 return $users;
427 * Allow selection of number of items to display per page.
428 * @return string
430 public function perpage_select() {
431 global $PAGE, $OUTPUT;
433 $options = array_combine(self::$validperpage, self::$validperpage);
435 $url = new moodle_url($PAGE->url);
436 $url->remove_params(['page', 'perpage']);
438 $out = '';
439 $select = new \single_select($url, 'perpage', $options, $this->perpage, null, 'perpagechanger');
440 $select->label = get_string('itemsperpage', 'gradereport_singleview');
441 $out .= $OUTPUT->render($select);
443 return $out;