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 * 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 */ 24 25 namespace gradereport_singleview\local\screen; 26 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; 37 38 defined('MOODLE_INTERNAL') || die; 39 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 { 48 49 /** @var array $categories A cache for grade_item categories */ 50 private $categories = []; 51 52 /** @var int $requirespaging Do we have more items than the paging limit? */ 53 private $requirespaging = true; 54 55 /** @var array get a valid user. */ 56 public $item = []; 57 58 /** 59 * Get the label for the select box that chooses items for this page. 60 * @return string 61 */ 62 public function select_label(): string { 63 return get_string('selectgrade', 'gradereport_singleview'); 64 } 65 66 /** 67 * Get the description for the screen. 68 * 69 * @return string 70 */ 71 public function description(): string { 72 return get_string('gradeitems', 'grades'); 73 } 74 75 /** 76 * Convert the list of items to a list of options. 77 * 78 * @return array 79 */ 80 public function options(): array { 81 $result = []; 82 foreach ($this->items as $itemid => $item) { 83 $result[$itemid] = $item->get_name(); 84 } 85 return $result; 86 } 87 88 /** 89 * Get the type of items on this screen. 90 * 91 * @return string 92 */ 93 public function item_type(): string { 94 return 'grade'; 95 } 96 97 /** 98 * Init the screen 99 * 100 * @param bool $selfitemisempty Have we selected an item yet? 101 */ 102 public function init($selfitemisempty = false) { 103 104 if (!$selfitemisempty) { 105 $validusers = \grade_report::get_gradable_users($this->courseid, $this->groupid); 106 if (!isset($validusers[$this->itemid])) { 107 // If the passed user id is not valid, show the first user from the list instead. 108 $this->item = reset($validusers); 109 $this->itemid = $this->item->id; 110 } else { 111 $this->item = $validusers[$this->itemid]; 112 } 113 } 114 115 $seq = new grade_seq($this->courseid, true); 116 117 $this->items = []; 118 foreach ($seq->items as $itemid => $item) { 119 if (grade::filter($item)) { 120 $this->items[$itemid] = $item; 121 } 122 } 123 124 // If we change perpage on pagination we might end up with a page that doesn't exist. 125 if ($this->perpage) { 126 $numpages = intval(count($this->items) / $this->perpage) + 1; 127 if ($numpages <= $this->page) { 128 $this->page = 0; 129 } 130 } else { 131 $this->page = 0; 132 } 133 134 $this->requirespaging = count($this->items) > $this->perpage; 135 136 $this->setup_structure(); 137 138 $this->definition = [ 139 'finalgrade', 'feedback', 'override', 'exclude' 140 ]; 141 $this->set_headers($this->original_headers()); 142 } 143 144 /** 145 * Get the list of headers for the table. 146 * 147 * @return array List of headers 148 */ 149 public function original_headers(): array { 150 return [ 151 get_string('assessmentname', 'gradereport_singleview'), 152 '', // For filter icon. 153 get_string('gradecategory', 'grades'), 154 get_string('grade', 'grades'), 155 get_string('range', 'grades'), 156 get_string('feedback', 'grades'), 157 get_string('override', 'gradereport_singleview'), 158 get_string('exclude', 'gradereport_singleview'), 159 ]; 160 } 161 162 /** 163 * Format each row of the table. 164 * 165 * @param grade_item $item 166 * @return array 167 */ 168 public function format_line($item): array { 169 global $OUTPUT; 170 171 $grade = $this->fetch_grade_or_default($item, $this->item->id); 172 $gradestatus = ''; 173 174 $context = [ 175 'hidden' => $grade->is_hidden(), 176 'locked' => $grade->is_locked(), 177 ]; 178 179 if (in_array(true, $context)) { 180 $context['classes'] = 'gradestatus'; 181 $gradestatus = $OUTPUT->render_from_template('core_grades/status_icons', $context); 182 } 183 184 // Create a fake gradetreeitem so we can call get_element_header(). 185 // The type logic below is from grade_category->_get_children_recursion(). 186 $gradetreeitem = []; 187 188 $type = in_array($item->itemtype, ['course', 'category']) ? "{$item->itemtype}item" : 'item'; 189 $gradetreeitem['type'] = $type; 190 $gradetreeitem['object'] = $item; 191 $gradetreeitem['userid'] = $this->item->id; 192 193 $itemname = $this->structure->get_element_header($gradetreeitem, true, false, false, false, true); 194 $grade->label = $item->get_name(); 195 196 $formatteddefinition = $this->format_definition($grade); 197 198 $itemicon = html_writer::div($this->format_icon($item), 'mr-1'); 199 $itemtype = \html_writer::span($this->structure->get_element_type_string($gradetreeitem), 200 'd-block text-uppercase small dimmed_text'); 201 // If a behat test site is running avoid outputting the information about the type of the grade item. 202 // This additional information currently causes issues in behat particularly with the existing xpath used to 203 // interact with table elements. 204 if (!defined('BEHAT_SITE_RUNNING')) { 205 $itemcontent = html_writer::div($itemtype . $itemname); 206 } else { 207 $itemcontent = html_writer::div($itemname); 208 } 209 210 $line = [ 211 html_writer::div($itemicon . $itemcontent, "{$type} d-flex align-items-center"), 212 $this->get_item_action_menu($item), 213 $this->category($item), 214 $formatteddefinition['finalgrade'] . $gradestatus, 215 new range($item), 216 $formatteddefinition['feedback'], 217 $formatteddefinition['override'], 218 $formatteddefinition['exclude'], 219 ]; 220 $lineclasses = [ 221 'gradeitem', 222 'action', 223 'category', 224 'grade', 225 'range', 226 ]; 227 228 $outputline = []; 229 $i = 0; 230 foreach ($line as $key => $value) { 231 $cell = new \html_table_cell($value); 232 if ($isheader = $i == 0) { 233 $cell->header = $isheader; 234 $cell->scope = "row"; 235 } 236 if (array_key_exists($key, $lineclasses)) { 237 $cell->attributes['class'] = $lineclasses[$key]; 238 } 239 $outputline[] = $cell; 240 $i++; 241 } 242 243 return $outputline; 244 } 245 246 /** 247 * Helper to get the icon for an item. 248 * 249 * @param grade_item $item 250 * @return string 251 */ 252 private function format_icon($item): string { 253 $element = ['type' => 'item', 'object' => $item]; 254 return $this->structure->get_element_icon($element); 255 } 256 257 /** 258 * Return the action menu HTML for the grade item. 259 * 260 * @param grade_item $item 261 * @return mixed 262 */ 263 private function get_item_action_menu(grade_item $item) { 264 global $OUTPUT; 265 266 $menuitems = []; 267 $url = new moodle_url($this->format_link('grade', $item->id)); 268 $title = get_string('showallgrades', 'core_grades'); 269 $menuitems[] = new \action_menu_link_secondary($url, null, $title); 270 $menu = new \action_menu($menuitems); 271 $icon = $OUTPUT->pix_icon('i/moremenu', get_string('actions')); 272 $extraclasses = 'btn btn-link btn-icon icon-size-3 d-flex align-items-center justify-content-center'; 273 $menu->set_menu_trigger($icon, $extraclasses); 274 $menu->set_menu_left(); 275 $menu->set_boundary('window'); 276 277 return $OUTPUT->render($menu); 278 } 279 280 /** 281 * Helper to get the category for an item. 282 * 283 * @param grade_item $item 284 * @return string 285 */ 286 private function category(grade_item $item): string { 287 global $DB; 288 289 if (empty($item->categoryid)) { 290 291 if ($item->itemtype == 'course') { 292 return $this->course->fullname; 293 } 294 295 $params = ['id' => $item->iteminstance]; 296 $elem = $DB->get_record('grade_categories', $params); 297 298 return $elem->fullname; 299 } 300 301 if (!isset($this->categories[$item->categoryid])) { 302 $category = $item->get_parent_category(); 303 304 $this->categories[$category->id] = $category; 305 } 306 307 return $this->categories[$item->categoryid]->get_name(); 308 } 309 310 /** 311 * Get the heading for the page. 312 * 313 * @return string 314 */ 315 public function heading(): string { 316 global $PAGE; 317 $headinglangstring = $PAGE->user_is_editing() ? 'gradeuseredit' : 'gradeuser'; 318 return get_string($headinglangstring, 'gradereport_singleview', fullname($this->item)); 319 } 320 321 /** 322 * Get the summary for this table. 323 * 324 * @return string 325 */ 326 public function summary(): string { 327 return get_string('summaryuser', 'gradereport_singleview'); 328 } 329 330 /** 331 * Default pager 332 * 333 * @return string 334 */ 335 public function pager(): string { 336 global $OUTPUT; 337 338 if (!$this->supports_paging()) { 339 return ''; 340 } 341 342 return $OUTPUT->paging_bar( 343 count($this->items), $this->page, $this->perpage, 344 new moodle_url('/grade/report/singleview/index.php', [ 345 'perpage' => $this->perpage, 346 'id' => $this->courseid, 347 'group' => $this->groupid, 348 'itemid' => $this->itemid, 349 'item' => 'user' 350 ]) 351 ); 352 } 353 354 /** 355 * Does this page require paging? 356 * 357 * @return bool 358 */ 359 public function supports_paging(): bool { 360 return $this->requirespaging; 361 } 362 363 364 /** 365 * Process the data from the form. 366 * 367 * @param array $data 368 * @return stdClass of warnings 369 */ 370 public function process($data): stdClass { 371 $bulk = new bulk_insert($this->item); 372 // Bulk insert messages the data to be passed in 373 // ie: for all grades of empty grades apply the specified value. 374 if ($bulk->is_applied($data)) { 375 $filter = $bulk->get_type($data); 376 $insertvalue = $bulk->get_insert_value($data); 377 378 $userid = $this->item->id; 379 foreach ($this->items as $gradeitemid => $gradeitem) { 380 $null = $gradeitem->gradetype == GRADE_TYPE_SCALE ? -1 : ''; 381 $field = "finalgrade_{$gradeitem->id}_{$this->itemid}"; 382 if (isset($data->$field)) { 383 continue; 384 } 385 386 $oldfinalgradefield = "oldfinalgrade_{$gradeitem->id}_{$this->itemid}"; 387 // Bulk grade changes for all grades need to be processed and shouldn't be skipped if they had a previous grade. 388 if ($gradeitem->is_course_item() || ($filter != 'all' && !empty($data->$oldfinalgradefield))) { 389 if ($gradeitem->is_course_item()) { 390 // The course total should not be overridden. 391 unset($data->$field); 392 unset($data->oldfinalgradefield); 393 $oldoverride = "oldoverride_{$gradeitem->id}_{$this->itemid}"; 394 unset($data->$oldoverride); 395 $oldfeedback = "oldfeedback_{$gradeitem->id}_{$this->itemid}"; 396 unset($data->$oldfeedback); 397 } 398 continue; 399 } 400 $grade = grade_grade::fetch([ 401 'itemid' => $gradeitemid, 402 'userid' => $userid 403 ]); 404 405 $data->$field = empty($grade) ? $null : $grade->finalgrade; 406 $data->{"old$field"} = $data->$field; 407 } 408 409 foreach ($data as $varname => $value) { 410 if (preg_match('/^oldoverride_(\d+)_(\d+)/', $varname, $matches)) { 411 // If we've selected overriding all grades. 412 if ($filter == 'all') { 413 $override = "override_{$matches[1]}_{$matches[2]}"; 414 $data->$override = '1'; 415 } 416 } 417 if (!preg_match('/^finalgrade_(\d+)_(\d+)/', $varname, $matches)) { 418 continue; 419 } 420 421 $gradeitem = grade_item::fetch([ 422 'courseid' => $this->courseid, 423 'id' => $matches[1], 424 ]); 425 426 $isscale = ($gradeitem->gradetype == GRADE_TYPE_SCALE); 427 428 $empties = (trim($value ?? '') === '' || ($isscale && $value == -1)); 429 430 if ($filter == 'all' || $empties) { 431 $data->$varname = ($isscale && empty($insertvalue)) ? -1 : $insertvalue; 432 } 433 } 434 } 435 return parent::process($data); 436 } 437 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body