Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.

Differences Between: [Versions 310 and 401] [Versions 310 and 402] [Versions 310 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 = array();
  51  
  52      /** @var int $requirespaging Do we have more items than the paging limit? */
  53      private $requirespaging = true;
  54  
  55      /**
  56       * Get the label for the select box that chooses items for this page.
  57       * @return string
  58       */
  59      public function select_label() {
  60          return get_string('selectgrade', 'gradereport_singleview');
  61      }
  62  
  63      /**
  64       * Get the description for the screen.
  65       *
  66       * @return string
  67       */
  68      public function description() {
  69          return get_string('gradeitems', 'grades');
  70      }
  71  
  72      /**
  73       * Convert the list of items to a list of options.
  74       *
  75       * @return array
  76       */
  77      public function options() {
  78          $result = array();
  79          foreach ($this->items as $itemid => $item) {
  80              $result[$itemid] = $item->get_name();
  81          }
  82          return $result;
  83      }
  84  
  85      /**
  86       * Get the type of items on this screen.
  87       *
  88       * @return string
  89       */
  90      public function item_type() {
  91          return 'grade';
  92      }
  93  
  94      /**
  95       * Init the screen
  96       *
  97       * @param bool $selfitemisempty Have we selected an item yet?
  98       */
  99      public function init($selfitemisempty = false) {
 100          global $DB;
 101  
 102          if (!$selfitemisempty) {
 103              $validusers = $this->load_users();
 104              if (!isset($validusers[$this->itemid])) {
 105                  // If the passed user id is not valid, show the first user from the list instead.
 106                  $this->item = reset($validusers);
 107                  $this->itemid = $this->item->id;
 108              } else {
 109                  $this->item = $validusers[$this->itemid];
 110              }
 111          }
 112  
 113          $params = array('courseid' => $this->courseid);
 114  
 115          $seq = new grade_seq($this->courseid, true);
 116  
 117          $this->items = array();
 118          foreach ($seq->items as $itemid => $item) {
 119              if (grade::filter($item)) {
 120                  $this->items[$itemid] = $item;
 121              }
 122          }
 123  
 124          $this->requirespaging = count($this->items) > $this->perpage;
 125  
 126          $this->setup_structure();
 127  
 128          $this->definition = array(
 129              'finalgrade', 'feedback', 'override', 'exclude'
 130          );
 131          $this->set_headers($this->original_headers());
 132      }
 133  
 134      /**
 135       * Get the list of headers for the table.
 136       *
 137       * @return array List of headers
 138       */
 139      public function original_headers() {
 140          return array(
 141              '', // For filter icon.
 142              get_string('assessmentname', 'gradereport_singleview'),
 143              get_string('gradecategory', 'grades'),
 144              get_string('range', 'grades'),
 145              get_string('grade', 'grades'),
 146              get_string('feedback', 'grades'),
 147              $this->make_toggle_links('override'),
 148              $this->make_toggle_links('exclude')
 149          );
 150      }
 151  
 152      /**
 153       * Format each row of the table.
 154       *
 155       * @param grade_item $item
 156       * @return string
 157       */
 158      public function format_line($item) {
 159          global $OUTPUT;
 160  
 161          $grade = $this->fetch_grade_or_default($item, $this->item->id);
 162          $lockicon = '';
 163  
 164          $lockeditem = $lockeditemgrade = 0;
 165          if (!empty($grade->locked)) {
 166              $lockeditem = 1;
 167          }
 168          if (!empty($grade->grade_item->locked)) {
 169              $lockeditemgrade = 1;
 170          }
 171          // Check both grade and grade item.
 172          if ($lockeditem || $lockeditemgrade) {
 173               $lockicon = $OUTPUT->pix_icon('t/locked', 'grade is locked');
 174          }
 175  
 176          $iconstring = get_string('filtergrades', 'gradereport_singleview', $item->get_name());
 177  
 178          // Create a fake gradetreeitem so we can call get_element_header().
 179          // The type logic below is from grade_category->_get_children_recursion().
 180          $gradetreeitem = array();
 181          if (in_array($item->itemtype, array('course', 'category'))) {
 182              $gradetreeitem['type'] = $item->itemtype.'item';
 183          } else {
 184              $gradetreeitem['type'] = 'item';
 185          }
 186          $gradetreeitem['object'] = $item;
 187          $gradetreeitem['userid'] = $this->item->id;
 188  
 189          $itemlabel = $this->structure->get_element_header($gradetreeitem, true, false, false, false, true);
 190          $grade->label = $item->get_name();
 191  
 192          $line = array(
 193              $OUTPUT->action_icon($this->format_link('grade', $item->id), new pix_icon('t/editstring', ''), null,
 194                      ['title' => $iconstring, 'aria-label' => $iconstring]),
 195              $this->format_icon($item) . $lockicon . $itemlabel,
 196              $this->category($item),
 197              new range($item)
 198          );
 199          $lineclasses = array(
 200              "action",
 201              "gradeitem",
 202              "category",
 203              "range"
 204          );
 205  
 206          $outputline = array();
 207          $i = 0;
 208          foreach ($line as $key => $value) {
 209              $cell = new \html_table_cell($value);
 210              if ($isheader = $i == 1) {
 211                  $cell->header = $isheader;
 212                  $cell->scope = "row";
 213              }
 214              if (array_key_exists($key, $lineclasses)) {
 215                  $cell->attributes['class'] = $lineclasses[$key];
 216              }
 217              $outputline[] = $cell;
 218              $i++;
 219          }
 220  
 221          return $this->format_definition($outputline, $grade);
 222      }
 223  
 224      /**
 225       * Helper to get the icon for an item.
 226       *
 227       * @param grade_item $item
 228       * @return string
 229       */
 230      private function format_icon($item) {
 231          $element = array('type' => 'item', 'object' => $item);
 232          return $this->structure->get_element_icon($element);
 233      }
 234  
 235      /**
 236       * Helper to get the category for an item.
 237       *
 238       * @param grade_item $item
 239       * @return grade_category
 240       */
 241      private function category($item) {
 242          global $DB;
 243  
 244          if (empty($item->categoryid)) {
 245  
 246              if ($item->itemtype == 'course') {
 247                  return $this->course->fullname;
 248              }
 249  
 250              $params = array('id' => $item->iteminstance);
 251              $elem = $DB->get_record('grade_categories', $params);
 252  
 253              return $elem->fullname;
 254          }
 255  
 256          if (!isset($this->categories[$item->categoryid])) {
 257              $category = $item->get_parent_category();
 258  
 259              $this->categories[$category->id] = $category;
 260          }
 261  
 262          return $this->categories[$item->categoryid]->get_name();
 263      }
 264  
 265      /**
 266       * Get the heading for the page.
 267       *
 268       * @return string
 269       */
 270      public function heading() {
 271          return get_string('gradeuser', 'gradereport_singleview', fullname($this->item));
 272      }
 273  
 274      /**
 275       * Get the summary for this table.
 276       *
 277       * @return string
 278       */
 279      public function summary() {
 280          return get_string('summaryuser', 'gradereport_singleview');
 281      }
 282  
 283      /**
 284       * Default pager
 285       *
 286       * @return string
 287       */
 288      public function pager() {
 289          global $OUTPUT;
 290  
 291          if (!$this->supports_paging()) {
 292              return '';
 293          }
 294  
 295          return $OUTPUT->paging_bar(
 296              count($this->items), $this->page, $this->perpage,
 297              new moodle_url('/grade/report/singleview/index.php', array(
 298                  'perpage' => $this->perpage,
 299                  'id' => $this->courseid,
 300                  'group' => $this->groupid,
 301                  'itemid' => $this->itemid,
 302                  'item' => 'user'
 303              ))
 304          );
 305      }
 306  
 307      /**
 308       * Does this page require paging?
 309       *
 310       * @return bool
 311       */
 312      public function supports_paging() {
 313          return $this->requirespaging;
 314      }
 315  
 316  
 317      /**
 318       * Process the data from the form.
 319       *
 320       * @param array $data
 321       * @return array of warnings
 322       */
 323      public function process($data) {
 324          $bulk = new bulk_insert($this->item);
 325          // Bulk insert messages the data to be passed in
 326          // ie: for all grades of empty grades apply the specified value.
 327          if ($bulk->is_applied($data)) {
 328              $filter = $bulk->get_type($data);
 329              $insertvalue = $bulk->get_insert_value($data);
 330  
 331              $userid = $this->item->id;
 332              foreach ($this->items as $gradeitemid => $gradeitem) {
 333                  $null = $gradeitem->gradetype == GRADE_TYPE_SCALE ? -1 : '';
 334                  $field = "finalgrade_{$gradeitem->id}_{$this->itemid}";
 335                  if (isset($data->$field)) {
 336                      continue;
 337                  }
 338  
 339                  $oldfinalgradefield = "oldfinalgrade_{$gradeitem->id}_{$this->itemid}";
 340                  // Bulk grade changes for all grades need to be processed and shouldn't be skipped if they had a previous grade.
 341                  if ($gradeitem->is_course_item() || ($filter != 'all' && !empty($data->$oldfinalgradefield))) {
 342                      if ($gradeitem->is_course_item()) {
 343                          // The course total should not be overridden.
 344                          unset($data->$field);
 345                          unset($data->oldfinalgradefield);
 346                          $oldoverride = "oldoverride_{$gradeitem->id}_{$this->itemid}";
 347                          unset($data->$oldoverride);
 348                          $oldfeedback = "oldfeedback_{$gradeitem->id}_{$this->itemid}";
 349                          unset($data->$oldfeedback);
 350                      }
 351                      continue;
 352                  }
 353                  $grade = grade_grade::fetch(array(
 354                      'itemid' => $gradeitemid,
 355                      'userid' => $userid
 356                  ));
 357  
 358                  $data->$field = empty($grade) ? $null : $grade->finalgrade;
 359                  $data->{"old$field"} = $data->$field;
 360              }
 361  
 362              foreach ($data as $varname => $value) {
 363                  if (preg_match('/^oldoverride_(\d+)_(\d+)/', $varname, $matches)) {
 364                      // If we've selected overriding all grades.
 365                      if ($filter == 'all') {
 366                          $override = "override_{$matches[1]}_{$matches[2]}";
 367                          $data->$override = '1';
 368                      }
 369                  }
 370                  if (!preg_match('/^finalgrade_(\d+)_(\d+)/', $varname, $matches)) {
 371                      continue;
 372                  }
 373  
 374                  $gradeitem = grade_item::fetch(array(
 375                      'courseid' => $this->courseid,
 376                      'id' => $matches[1]
 377                  ));
 378  
 379                  $isscale = ($gradeitem->gradetype == GRADE_TYPE_SCALE);
 380  
 381                  $empties = (trim($value) === '' or ($isscale and $value == -1));
 382  
 383                  if ($filter == 'all' or $empties) {
 384                      $data->$varname = ($isscale and empty($insertvalue)) ?
 385                          -1 : $insertvalue;
 386                  }
 387              }
 388          }
 389          return parent::process($data);
 390      }
 391  }