Search moodle.org's
Developer Documentation

See Release Notes
Long Term Support Release

  • Bug fixes for general core bugs in 4.1.x will end 13 November 2023 (12 months).
  • Bug fixes for security issues in 4.1.x will end 10 November 2025 (36 months).
  • PHP version: minimum PHP 7.4.0 Note: minimum PHP version has increased since Moodle 4.0. PHP 8.0.x is supported too.

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