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