Differences Between: [Versions 310 and 403] [Versions 311 and 403] [Versions 39 and 403] [Versions 400 and 403] [Versions 401 and 403] [Versions 402 and 403]
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/>. 16 17 /** 18 * Abstract class used as a base for the 3 screens. 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 */ 24 25 namespace gradereport_singleview\local\screen; 26 27 use context_course; 28 use grade_report; 29 use moodle_url; 30 use html_writer; 31 use grade_structure; 32 use grade_grade; 33 use grade_item; 34 use stdClass; 35 36 defined('MOODLE_INTERNAL') || die; 37 require_once($CFG->dirroot . '/grade/report/lib.php'); 38 39 /** 40 * Abstract class used as a base for the 3 screens. 41 * 42 * @package gradereport_singleview 43 * @copyright 2014 Moodle Pty Ltd (http://moodle.com) 44 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 45 */ 46 abstract class screen { 47 48 /** 49 * The id of the course 50 * @var int $courseid 51 */ 52 protected $courseid; 53 54 /** 55 * Either a user id or a grade_item id 56 * @var int|null $itemid 57 */ 58 protected $itemid; 59 60 /** 61 * The currently set groupid (if set) 62 * @var int $groupid 63 */ 64 protected $groupid; 65 66 /** 67 * The course context 68 * @var context_course $context 69 */ 70 protected $context; 71 72 /** 73 * The page number 74 * @var int $page 75 */ 76 protected $page; 77 78 /** 79 * Results per page 80 * @var int $perpage 81 */ 82 protected $perpage; 83 84 /** 85 * List of items on the page, they could be users or grade_items 86 * @var array $items 87 */ 88 protected $items; 89 90 /** @var int Maximum number of students that can be shown on one page */ 91 protected static $maxperpage = 5000; 92 93 /** 94 * List of allowed values for 'perpage' setting 95 * @var array $validperpage 96 */ 97 protected static $validperpage = [20, 100]; 98 99 /** 100 * To store course data 101 * @var stdClass 102 */ 103 protected $course; 104 105 /** 106 * General structure representing grade items in course 107 * @var grade_structure 108 */ 109 protected $structure; 110 111 /** 112 * Constructor 113 * 114 * @param int $courseid The course id 115 * @param int|null $itemid The item id 116 * @param int|null $groupid The group id 117 */ 118 public function __construct(int $courseid, ?int $itemid, ?int $groupid = null) { 119 global $DB; 120 121 $this->courseid = $courseid; 122 $this->itemid = $itemid; 123 $this->groupid = $groupid; 124 125 $this->context = context_course::instance($this->courseid); 126 $this->course = $DB->get_record('course', ['id' => $courseid]); 127 128 $this->page = optional_param('page', 0, PARAM_INT); 129 130 $cache = \cache::make_from_params(\cache_store::MODE_SESSION, 'gradereport_singleview', 'perpage'); 131 $perpage = optional_param('perpage', null, PARAM_INT); 132 if (!in_array($perpage, self::$validperpage) && ($perpage !== 0)) { 133 // Get from cache. 134 $perpage = $cache->get(get_class($this)); 135 } else { 136 // Save to cache. 137 $cache->set(get_class($this), $perpage); 138 } 139 if (isset($perpage) && $perpage) { 140 $this->perpage = $perpage; 141 } else { 142 // Get from cache. 143 $perpage = $cache->get(get_class($this)); 144 $this->perpage = ($perpage === 0) ? $perpage : min(self::$validperpage); 145 } 146 147 $this->init(empty($itemid)); 148 } 149 150 /** 151 * Cache the grade_structure class 152 */ 153 public function setup_structure() { 154 $this->structure = new grade_structure(); 155 $this->structure->modinfo = get_fast_modinfo($this->course); 156 } 157 158 /** 159 * Create a nice link from a thing (user or grade_item). 160 * 161 * @param string $screen 162 * @param int $itemid 163 * @param bool|null $display Should we wrap this in an anchor ? 164 * @return string The link 165 */ 166 public function format_link(string $screen, int $itemid, bool $display = null): string { 167 $url = new moodle_url('/grade/report/singleview/index.php', [ 168 'id' => $this->courseid, 169 'item' => $screen, 170 'itemid' => $itemid, 171 'group' => $this->groupid, 172 ]); 173 174 if ($display) { 175 return html_writer::link($url, $display); 176 } else { 177 return $url; 178 } 179 } 180 181 /** 182 * Get the grade_grade 183 * 184 * @param grade_item $item The grade_item 185 * @param int $userid The user id 186 * @return grade_grade 187 */ 188 public function fetch_grade_or_default(grade_item $item, int $userid): grade_grade { 189 $grade = grade_grade::fetch([ 190 'itemid' => $item->id, 'userid' => $userid 191 ]); 192 193 if (!$grade) { 194 $default = new stdClass; 195 196 $default->userid = $userid; 197 $default->itemid = $item->id; 198 $default->feedback = ''; 199 200 $grade = new grade_grade($default, false); 201 } 202 203 $grade->grade_item = $item; 204 205 return $grade; 206 } 207 208 /** 209 * Get the default heading for the screen. 210 * 211 * @return string 212 */ 213 public function heading(): string { 214 return get_string('entrypage', 'gradereport_singleview'); 215 } 216 217 /** 218 * Override this to init the screen. 219 * 220 * @param boolean $selfitemisempty True if no item has been selected yet. 221 */ 222 abstract public function init(bool $selfitemisempty = false); 223 224 /** 225 * Get the type of items in the list. 226 * 227 * @return null|string 228 */ 229 abstract public function item_type(): ?string; 230 231 /** 232 * Get the entire screen as a string. 233 * 234 * @return string 235 */ 236 abstract public function html(): string; 237 238 /** 239 * Does this screen support paging? 240 * 241 * @return bool 242 */ 243 public function supports_paging(): bool { 244 return true; 245 } 246 247 /** 248 * Default pager 249 * 250 * @return string 251 */ 252 public function pager(): string { 253 return ''; 254 } 255 256 /** 257 * Initialise the js for this screen. 258 */ 259 public function js() { 260 global $PAGE; 261 262 $module = [ 263 'name' => 'gradereport_singleview', 264 'fullpath' => '/grade/report/singleview/js/singleview.js', 265 'requires' => ['base', 'dom', 'event', 'event-simulate', 'io-base'] 266 ]; 267 268 $PAGE->requires->strings_for_js(['overridenoneconfirm', 'removeoverride', 'removeoverridesave'], 269 'gradereport_singleview'); 270 $PAGE->requires->js_init_call('M.gradereport_singleview.init', [], false, $module); 271 } 272 273 /** 274 * Process the data from a form submission. 275 * 276 * @param array|object $data 277 * @return stdClass of warnings 278 */ 279 public function process($data): stdClass { 280 $warnings = []; 281 282 $fields = $this->definition(); 283 284 // Avoiding execution timeouts when updating 285 // a large amount of grades. 286 $progress = 0; 287 $progressbar = new \core\progress\display_if_slow(); 288 $progressbar->start_html(); 289 $progressbar->start_progress(get_string('savegrades', 'gradereport_singleview'), count((array) $data) - 1); 290 $changecount = []; 291 // This array is used to determine if the override should be excluded from being counted as a change. 292 $ignorevalues = []; 293 294 foreach ($data as $varname => $throw) { 295 $progressbar->progress($progress); 296 $progress++; 297 if (preg_match("/(\w+)_(\d+)_(\d+)/", $varname, $matches)) { 298 $itemid = $matches[2]; 299 $userid = $matches[3]; 300 } else { 301 continue; 302 } 303 304 $gradeitem = grade_item::fetch([ 305 'id' => $itemid, 'courseid' => $this->courseid 306 ]); 307 308 if (preg_match('/^old[oe]{1}/', $varname)) { 309 $elementname = preg_replace('/^old/', '', $varname); 310 if (!isset($data->$elementname)) { 311 // Decrease the progress because we've increased the 312 // size of the array we are iterating through. 313 $progress--; 314 $data->$elementname = false; 315 } 316 } 317 318 if (!in_array($matches[1], $fields)) { 319 continue; 320 } 321 322 if (!$gradeitem) { 323 continue; 324 } 325 326 $grade = $this->fetch_grade_or_default($gradeitem, $userid); 327 328 $classname = '\\gradereport_singleview\\local\\ui\\' . $matches[1]; 329 $element = new $classname($grade); 330 331 $name = $element->get_name(); 332 $oldname = "old$name"; 333 334 $posted = $data->$name; 335 336 $format = $element->determine_format(); 337 338 if ($format->is_textbox() and trim($data->$name) === '') { 339 $data->$name = null; 340 } 341 342 // Same value; skip. 343 if (isset($data->$oldname) && $data->$oldname == $posted) { 344 continue; 345 } 346 347 // If the user submits Exclude grade elements without the proper. 348 // permissions then we should refuse to update. 349 if ($matches[1] === 'exclude' && !has_capability('moodle/grade:manage', $this->context)){ 350 $warnings[] = get_string('nopermissions', 'error', get_string('grade:manage', 'role')); 351 continue; 352 } 353 354 $msg = $element->set($posted); 355 // Value to check against our list of matchelements to ignore. 356 $check = explode('_', $varname, 2); 357 358 // Optional type. 359 if (!empty($msg)) { 360 $warnings[] = $msg; 361 if ($element instanceof \gradereport_singleview\local\ui\finalgrade) { 362 // Add this value to this list so that the override object that is coming next will also be skipped. 363 $ignorevalues[$check[1]] = $check[1]; 364 // This item wasn't changed so don't add to the changecount. 365 continue; 366 } 367 } 368 // Check to see if this value has already been skipped. 369 if (array_key_exists($check[1], $ignorevalues)) { 370 continue; 371 } 372 if (preg_match('/_(\d+)_(\d+)/', $varname, $matchelement)) { 373 $changecount[$matchelement[0]] = 1; 374 } 375 } 376 377 // Some post-processing. 378 $eventdata = new stdClass; 379 $eventdata->warnings = $warnings; 380 $eventdata->post_data = $data; 381 $eventdata->instance = $this; 382 $eventdata->changecount = $changecount; 383 384 $progressbar->end_html(); 385 386 return $eventdata; 387 } 388 389 /** 390 * By default, there are no options. 391 * @return array 392 */ 393 public function options(): array { 394 return []; 395 } 396 397 /** 398 * Should we show the group selector? 399 * @return bool 400 */ 401 public function display_group_selector(): bool { 402 return true; 403 } 404 405 /** 406 * Should we show the next prev selector? 407 * @return bool 408 */ 409 public function supports_next_prev(): bool { 410 return true; 411 } 412 413 /** 414 * Load a valid list of users for this gradebook as the screen "items". 415 * 416 * @deprecated since Moodle 4.3 417 * @return array A list of enroled users. 418 */ 419 protected function load_users(): array { 420 debugging('The function ' . __FUNCTION__ . '() is deprecated. Please use grade_report::get_gradable_users() instead.', 421 DEBUG_DEVELOPER); 422 423 return grade_report::get_gradable_users($this->courseid, $this->groupid); 424 } 425 426 /** 427 * Allow selection of number of items to display per page. 428 * @return string 429 */ 430 public function perpage_select(): string { 431 global $PAGE, $OUTPUT; 432 433 $url = new moodle_url($PAGE->url); 434 $numusers = count($this->items); 435 // Print per-page dropdown. 436 $pagingoptions = self::$validperpage; 437 if ($this->perpage) { 438 $pagingoptions[] = $this->perpage; // To make sure the current preference is within the options. 439 } 440 $pagingoptions = array_unique($pagingoptions); 441 sort($pagingoptions); 442 $pagingoptions = array_combine($pagingoptions, $pagingoptions); 443 if ($numusers > self::$maxperpage) { 444 $pagingoptions['0'] = self::$maxperpage; 445 } else { 446 $pagingoptions['0'] = get_string('all'); 447 } 448 449 $perpagedata = [ 450 'baseurl' => $url->out(false), 451 'options' => [] 452 ]; 453 foreach ($pagingoptions as $key => $name) { 454 $perpagedata['options'][] = [ 455 'name' => $name, 456 'value' => $key, 457 'selected' => $key == $this->perpage, 458 ]; 459 } 460 461 // The number of students per page is always limited even if it is claimed to be unlimited. 462 $this->perpage = $this->perpage ?: self::$maxperpage; 463 $perpagedata['pagingbar'] = $this->pager(); 464 return $OUTPUT->render_from_template('gradereport_singleview/perpage', $perpagedata);; 465 } 466 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body