Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.3.x will end 7 October 2024 (12 months).
  • Bug fixes for security issues in 4.3.x will end 21 April 2025 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.2.x is supported too.

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 screen with a list of users.
  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_report;
  28  use gradereport_singleview\local\ui\range;
  29  use gradereport_singleview\local\ui\bulk_insert;
  30  use grade_grade;
  31  use grade_item;
  32  use moodle_url;
  33  use pix_icon;
  34  use html_writer;
  35  use gradereport_singleview;
  36  
  37  defined('MOODLE_INTERNAL') || die;
  38  
  39  /**
  40   * The screen with a list of users.
  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  class grade extends tablelike implements selectable_items, filterable_items {
  47  
  48      /**
  49       * Used for paging
  50       * @var int $totalitemcount
  51       */
  52      private $totalitemcount = 0;
  53  
  54      /**
  55       * True if this is a manual grade item
  56       * @var bool $requiresextra
  57       */
  58      private $requiresextra = false;
  59  
  60      /**
  61       * True if there are more users than our limit.
  62       * @var bool $requirepaging
  63       */
  64      private $requirespaging = true;
  65  
  66      /**
  67       * To store UI element that generates a grade_item min/max range.
  68       * @var range;
  69       */
  70      protected $range;
  71  
  72      /**
  73       * Returns a grade_item instance or false if none found.
  74       * @var grade_item|bool
  75       */
  76      public $item;
  77  
  78      /**
  79       * True if $CFG->grade_overridecat is true
  80       *
  81       * @return bool
  82       */
  83      public static function allowcategories(): bool {
  84          return get_config('moodle', 'grade_overridecat');
  85      }
  86  
  87      /**
  88       * Filter the list excluding category items (if required)?
  89       * @param grade_item $item The grade item.
  90       * @return bool
  91       */
  92      public static function filter($item): bool {
  93          return get_config('moodle', 'grade_overridecat') ||
  94                  !($item->is_course_item() || $item->is_category_item());
  95      }
  96  
  97      /**
  98       * Get the label for the select box that chooses items for this page.
  99       * @return string
 100       */
 101      public function select_label(): string {
 102          return get_string('selectuser', 'gradereport_singleview');
 103      }
 104  
 105      /**
 106       * Get the description of this page
 107       * @return string
 108       */
 109      public function description(): string {
 110          return get_string('users');
 111      }
 112  
 113      /**
 114       * Convert this list of items into an options list
 115       *
 116       * @return array
 117       */
 118      public function options(): array {
 119          $options = [];
 120          foreach ($this->items as $userid => $user) {
 121              $options[$userid] = fullname($user);
 122          }
 123  
 124          return $options;
 125      }
 126  
 127      /**
 128       * Return the type of the things in this list.
 129       * @return string
 130       */
 131      public function item_type(): string {
 132          return 'user';
 133      }
 134  
 135      /**
 136       * Get the original settings for this item
 137       * @return array
 138       */
 139      public function original_definition(): array {
 140          return [
 141              'finalgrade',
 142              'feedback',
 143              'override',
 144              'exclude'
 145          ];
 146      }
 147  
 148      /**
 149       * Init this page
 150       *
 151       * @param bool $selfitemisempty True if we have not selected a user.
 152       */
 153      public function init($selfitemisempty = false) {
 154  
 155          $this->items = grade_report::get_gradable_users($this->courseid, $this->groupid);
 156          $this->totalitemcount = count($this->items);
 157  
 158          if ($selfitemisempty) {
 159              return;
 160          }
 161  
 162          // If we change perpage on pagination we might end up with a page that doesn't exist.
 163          if ($this->perpage) {
 164              $numpages = intval($this->totalitemcount / $this->perpage) + 1;
 165              if ($numpages <= $this->page) {
 166                  $this->page = 0;
 167              }
 168          } else {
 169              $this->page = 0;
 170          }
 171  
 172          $params = [
 173              'id' => $this->itemid,
 174              'courseid' => $this->courseid
 175          ];
 176  
 177          $this->item = grade_item::fetch($params);
 178          if (!self::filter($this->item)) {
 179              $this->items = [];
 180              $this->set_init_error(get_string('gradeitemcannotbeoverridden', 'gradereport_singleview'));
 181          }
 182  
 183          $this->requiresextra = !$this->item->is_manual_item();
 184  
 185          $this->setup_structure();
 186  
 187          $this->set_definition($this->original_definition());
 188          $this->set_headers($this->original_headers());
 189      }
 190  
 191      /**
 192       * Get the table headers
 193       *
 194       * @return array
 195       */
 196      public function original_headers() {
 197          return [
 198              get_string('fullnameuser', 'core'),
 199              '', // For filter icon.
 200              get_string('grade', 'grades'),
 201              get_string('range', 'grades'),
 202              get_string('feedback', 'grades'),
 203              get_string('override', 'gradereport_singleview'),
 204              get_string('exclude', 'gradereport_singleview'),
 205          ];
 206      }
 207  
 208      /**
 209       * Format a row in the table
 210       *
 211       * @param stdClass $item
 212       * @return array
 213       */
 214      public function format_line($item): array {
 215          global $OUTPUT;
 216  
 217          $grade = $this->fetch_grade_or_default($this->item, $item->id);
 218  
 219          $gradestatus = '';
 220          $context = [
 221              'hidden' => $grade->is_hidden(),
 222              'locked' => $grade->is_locked(),
 223          ];
 224  
 225          if (in_array(true, $context)) {
 226              $context['classes'] = 'gradestatus';
 227              $gradestatus = $OUTPUT->render_from_template('core_grades/status_icons', $context);
 228          }
 229  
 230          if (has_capability('moodle/site:viewfullnames', \context_course::instance($this->courseid))) {
 231              $fullname = fullname($item, true);
 232          } else {
 233              $fullname = fullname($item);
 234          }
 235  
 236          $item->imagealt = $fullname;
 237          $url = new moodle_url("/user/view.php", ['id' => $item->id, 'course' => $this->courseid]);
 238          $grade->label = $fullname;
 239          $userpic = $OUTPUT->user_picture($item, ['link' => false, 'visibletoscreenreaders' => false]);
 240  
 241          $formatteddefinition = $this->format_definition($grade);
 242  
 243          $line = [
 244              html_writer::link($url, $userpic . $fullname),
 245              $this->get_user_action_menu($item),
 246              $formatteddefinition['finalgrade'] . $gradestatus,
 247              $this->item_range(),
 248              $formatteddefinition['feedback'],
 249              $formatteddefinition['override'],
 250              $formatteddefinition['exclude'],
 251          ];
 252          $lineclasses = [
 253              'user',
 254              'action',
 255              'grade',
 256              'range',
 257          ];
 258          $outputline = [];
 259          $i = 0;
 260          foreach ($line as $key => $value) {
 261              $cell = new \html_table_cell($value);
 262              if ($isheader = $i == 0) {
 263                  $cell->header = $isheader;
 264                  $cell->scope = "row";
 265              }
 266              if (array_key_exists($key, $lineclasses)) {
 267                  $cell->attributes['class'] = $lineclasses[$key];
 268              }
 269              $outputline[] = $cell;
 270              $i++;
 271          }
 272  
 273          return $outputline;
 274      }
 275  
 276      /**
 277       * Get the range ui element for this grade_item
 278       *
 279       * @return element;
 280       */
 281      public function item_range() {
 282          if (empty($this->range)) {
 283              $this->range = new range($this->item);
 284          }
 285  
 286          return $this->range;
 287      }
 288  
 289      /**
 290       * Does this page require paging?
 291       *
 292       * @return bool
 293       */
 294      public function supports_paging(): bool {
 295          return $this->requirespaging;
 296      }
 297  
 298      /**
 299       * Get the pager for this page.
 300       *
 301       * @return string
 302       */
 303      public function pager(): string {
 304          global $OUTPUT;
 305  
 306          return $OUTPUT->paging_bar(
 307              $this->totalitemcount, $this->page, $this->perpage,
 308              new moodle_url('/grade/report/singleview/index.php', [
 309                  'perpage' => $this->perpage,
 310                  'id' => $this->courseid,
 311                  'group' => $this->groupid,
 312                  'itemid' => $this->itemid,
 313                  'item' => 'grade'
 314              ])
 315          );
 316      }
 317  
 318      /**
 319       * Get the heading for this page.
 320       *
 321       * @return string
 322       */
 323      public function heading(): string {
 324          global $PAGE;
 325          $headinglangstring = $PAGE->user_is_editing() ? 'gradeitemedit' : 'gradeitem';
 326          return get_string($headinglangstring, 'gradereport_singleview', $this->item->get_name());
 327      }
 328  
 329      /**
 330       * Get the summary for this table.
 331       *
 332       * @return string
 333       */
 334      public function summary(): string {
 335          return get_string('summarygrade', 'gradereport_singleview');
 336      }
 337  
 338      /**
 339       * Process the data from the form.
 340       *
 341       * @param array $data
 342       * @return \stdClass of warnings
 343       */
 344      public function process($data): \stdClass {
 345          $bulk = new bulk_insert($this->item);
 346          // Bulk insert messages the data to be passed in
 347          // ie: for all grades of empty grades apply the specified value.
 348          if ($bulk->is_applied($data)) {
 349              $filter = $bulk->get_type($data);
 350              $insertvalue = $bulk->get_insert_value($data);
 351              // Appropriately massage data that may not exist.
 352              if ($this->supports_paging()) {
 353                  $gradeitem = grade_item::fetch([
 354                      'courseid' => $this->courseid,
 355                      'id' => $this->item->id
 356                  ]);
 357  
 358                  $null = $gradeitem->gradetype == GRADE_TYPE_SCALE ? -1 : '';
 359  
 360                  foreach ($this->items as $itemid => $item) {
 361                      $field = "finalgrade_{$gradeitem->id}_{$itemid}";
 362                      if (isset($data->$field)) {
 363                          continue;
 364                      }
 365  
 366                      $grade = grade_grade::fetch([
 367                          'itemid' => $gradeitem->id,
 368                          'userid' => $itemid
 369                      ]);
 370  
 371                      $data->$field = empty($grade) ? $null : $grade->finalgrade;
 372                      $data->{"old$field"} = $data->$field;
 373                  }
 374              }
 375  
 376              foreach ($data as $varname => $value) {
 377                  if (preg_match('/^oldoverride_(\d+)_(\d+)/', $varname, $matches)) {
 378                      // If we've selected overriding all grades.
 379                      if ($filter == 'all') {
 380                          $override = "override_{$matches[1]}_{$matches[2]}";
 381                          $data->$override = '1';
 382                      }
 383                  }
 384                  if (!preg_match('/^finalgrade_(\d+)_/', $varname, $matches)) {
 385                      continue;
 386                  }
 387  
 388                  $gradeitem = grade_item::fetch([
 389                      'courseid' => $this->courseid,
 390                      'id' => $matches[1]
 391                  ]);
 392  
 393                  $isscale = ($gradeitem->gradetype == GRADE_TYPE_SCALE);
 394  
 395                  $empties = (trim($value) === '' || ($isscale && $value == -1));
 396  
 397                  if ($filter == 'all' || $empties) {
 398                      $data->$varname = ($isscale && empty($insertvalue)) ?
 399                          -1 : $insertvalue;
 400                  }
 401              }
 402          }
 403          return parent::process($data);
 404      }
 405  
 406      /**
 407       * Return the action menu HTML for the user item.
 408       *
 409       * @param \stdClass $user
 410       * @return mixed
 411       */
 412      private function get_user_action_menu(\stdClass $user) {
 413          global $OUTPUT;
 414  
 415          $menuitems = [];
 416          $url = new moodle_url($this->format_link('user', $user->id));
 417          $title = get_string('showallgrades', 'core_grades');
 418          $menuitems[] = new \action_menu_link_secondary($url, null, $title);
 419          $menu = new \action_menu($menuitems);
 420          $icon = $OUTPUT->pix_icon('i/moremenu', get_string('actions'));
 421          $extraclasses = 'btn btn-link btn-icon icon-size-3 d-flex align-items-center justify-content-center';
 422          $menu->set_menu_trigger($icon, $extraclasses);
 423          $menu->set_menu_left();
 424          $menu->set_boundary('window');
 425  
 426          return $OUTPUT->render($menu);
 427      }
 428  }