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.
   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  namespace mod_quiz\local\reports;
  18  
  19  use context_module;
  20  use mod_quiz\quiz_attempt;
  21  use moodle_url;
  22  use stdClass;
  23  
  24  /**
  25   * Base class for the options that control what is visible in an {@see attempts_report}.
  26   *
  27   * @package   mod_quiz
  28   * @copyright 2012 The Open University
  29   * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  30   */
  31  class attempts_report_options {
  32  
  33      /** @var string the report mode. */
  34      public $mode;
  35  
  36      /** @var stdClass the settings for the quiz being reported on. */
  37      public $quiz;
  38  
  39      /** @var stdClass the course module objects for the quiz being reported on. */
  40      public $cm;
  41  
  42      /** @var stdClass the course settings for the course the quiz is in. */
  43      public $course;
  44  
  45      /**
  46       * @var array form field name => corresponding quiz_attempt:: state constant.
  47       */
  48      protected static $statefields = [
  49          'stateinprogress' => quiz_attempt::IN_PROGRESS,
  50          'stateoverdue'    => quiz_attempt::OVERDUE,
  51          'statefinished'   => quiz_attempt::FINISHED,
  52          'stateabandoned'  => quiz_attempt::ABANDONED,
  53      ];
  54  
  55      /**
  56       * @var string attempts_report::ALL_WITH, attempts_report::ENROLLED_WITH,
  57       *      attempts_report::ENROLLED_WITHOUT or attempts_report::ENROLLED_ALL
  58       */
  59      public $attempts = attempts_report::ENROLLED_WITH;
  60  
  61      /** @var int the currently selected group. 0 if no group is selected. */
  62      public $group = 0;
  63  
  64      /**
  65       * @var array|null of quiz_attempt::IN_PROGRESS, etc. constants. null means
  66       *      no restriction.
  67       */
  68      public $states = [quiz_attempt::IN_PROGRESS, quiz_attempt::OVERDUE,
  69              quiz_attempt::FINISHED, quiz_attempt::ABANDONED];
  70  
  71      /**
  72       * @var bool whether to show all finished attmepts, or just the one that gave
  73       *      the final grade for the user.
  74       */
  75      public $onlygraded = false;
  76  
  77      /** @var int Number of attempts to show per page. */
  78      public $pagesize = attempts_report::DEFAULT_PAGE_SIZE;
  79  
  80      /** @var string whether the data should be downloaded in some format, or '' to display it. */
  81      public $download = '';
  82  
  83      /** @var bool whether the current user has permission to see grades. */
  84      public $usercanseegrades;
  85  
  86      /** @var bool whether the report table should have a column of checkboxes. */
  87      public $checkboxcolumn = false;
  88  
  89      /**
  90       * Constructor.
  91       *
  92       * @param string $mode which report these options are for.
  93       * @param stdClass $quiz the settings for the quiz being reported on.
  94       * @param stdClass $cm the course module objects for the quiz being reported on.
  95       * @param stdClass $course the course settings for the coures this quiz is in.
  96       */
  97      public function __construct($mode, $quiz, $cm, $course) {
  98          $this->mode   = $mode;
  99          $this->quiz   = $quiz;
 100          $this->cm     = $cm;
 101          $this->course = $course;
 102  
 103          $this->usercanseegrades = quiz_report_should_show_grades($quiz, context_module::instance($cm->id));
 104      }
 105  
 106      /**
 107       * Get the URL parameters required to show the report with these options.
 108       * @return array URL parameter name => value.
 109       */
 110      protected function get_url_params() {
 111          $params = [
 112              'id'         => $this->cm->id,
 113              'mode'       => $this->mode,
 114              'attempts'   => $this->attempts,
 115              'onlygraded' => $this->onlygraded,
 116          ];
 117  
 118          if ($this->states) {
 119              $params['states'] = implode('-', $this->states);
 120          }
 121  
 122          if (groups_get_activity_groupmode($this->cm, $this->course)) {
 123              $params['group'] = $this->group;
 124          }
 125          return $params;
 126      }
 127  
 128      /**
 129       * Get the URL to show the report with these options.
 130       * @return moodle_url the URL.
 131       */
 132      public function get_url() {
 133          return new moodle_url('/mod/quiz/report.php', $this->get_url_params());
 134      }
 135  
 136      /**
 137       * Process the data we get when the settings form is submitted. This includes
 138       * updating the fields of this class, and updating the user preferences
 139       * where appropriate.
 140       * @param stdClass $fromform The data from $mform->get_data() from the settings form.
 141       */
 142      public function process_settings_from_form($fromform) {
 143          $this->setup_from_form_data($fromform);
 144          $this->resolve_dependencies();
 145          $this->update_user_preferences();
 146      }
 147  
 148      /**
 149       * Set up this preferences object using optional_param (using user_preferences
 150       * to set anything not specified by the params.
 151       */
 152      public function process_settings_from_params() {
 153          $this->setup_from_user_preferences();
 154          $this->setup_from_params();
 155          $this->resolve_dependencies();
 156      }
 157  
 158      /**
 159       * Get the current value of the settings to pass to the settings form.
 160       */
 161      public function get_initial_form_data() {
 162          $toform = new stdClass();
 163          $toform->attempts   = $this->attempts;
 164          $toform->onlygraded = $this->onlygraded;
 165          $toform->pagesize   = $this->pagesize;
 166  
 167          if ($this->states) {
 168              foreach (self::$statefields as $field => $state) {
 169                  $toform->$field = in_array($state, $this->states);
 170              }
 171          }
 172  
 173          return $toform;
 174      }
 175  
 176      /**
 177       * Set the fields of this object from the form data.
 178       * @param stdClass $fromform The data from $mform->get_data() from the settings form.
 179       */
 180      public function setup_from_form_data($fromform) {
 181          $this->attempts   = $fromform->attempts;
 182          $this->group      = groups_get_activity_group($this->cm, true);
 183          $this->onlygraded = !empty($fromform->onlygraded);
 184          $this->pagesize   = $fromform->pagesize;
 185  
 186          $this->states = [];
 187          foreach (self::$statefields as $field => $state) {
 188              if (!empty($fromform->$field)) {
 189                  $this->states[] = $state;
 190              }
 191          }
 192      }
 193  
 194      /**
 195       * Set the fields of this object from the URL parameters.
 196       */
 197      public function setup_from_params() {
 198          $this->attempts   = optional_param('attempts', $this->attempts, PARAM_ALPHAEXT);
 199          $this->group      = groups_get_activity_group($this->cm, true);
 200          $this->onlygraded = optional_param('onlygraded', $this->onlygraded, PARAM_BOOL);
 201          $this->pagesize   = optional_param('pagesize', $this->pagesize, PARAM_INT);
 202  
 203          $states = optional_param('states', '', PARAM_ALPHAEXT);
 204          if (!empty($states)) {
 205              $this->states = explode('-', $states);
 206          }
 207  
 208          $this->download   = optional_param('download', $this->download, PARAM_ALPHA);
 209      }
 210  
 211      /**
 212       * Set the fields of this object from the user's preferences.
 213       * (For those settings that are backed by user-preferences).
 214       */
 215      public function setup_from_user_preferences() {
 216          $this->pagesize = get_user_preferences('quiz_report_pagesize', $this->pagesize);
 217      }
 218  
 219      /**
 220       * Update the user preferences so they match the settings in this object.
 221       * (For those settings that are backed by user-preferences).
 222       */
 223      public function update_user_preferences() {
 224          set_user_preference('quiz_report_pagesize', $this->pagesize);
 225      }
 226  
 227      /**
 228       * Check the settings, and remove any 'impossible' combinations.
 229       */
 230      public function resolve_dependencies() {
 231          if ($this->group) {
 232              // Default for when a group is selected.
 233              if ($this->attempts === null || $this->attempts == attempts_report::ALL_WITH) {
 234                  $this->attempts = attempts_report::ENROLLED_WITH;
 235              }
 236  
 237          } else if (!$this->group && $this->course->id == SITEID) {
 238              // Force report on front page to show all, unless a group is selected.
 239              $this->attempts = attempts_report::ALL_WITH;
 240  
 241          } else if (!in_array($this->attempts, [attempts_report::ALL_WITH, attempts_report::ENROLLED_WITH,
 242                  attempts_report::ENROLLED_WITHOUT, attempts_report::ENROLLED_ALL])) {
 243              $this->attempts = attempts_report::ENROLLED_WITH;
 244          }
 245  
 246          $cleanstates = [];
 247          foreach (self::$statefields as $state) {
 248              if (in_array($state, $this->states)) {
 249                  $cleanstates[] = $state;
 250              }
 251          }
 252          $this->states = $cleanstates;
 253          if (count($this->states) == count(self::$statefields)) {
 254              // If all states have been selected, then there is no constraint
 255              // required in the SQL, so clear the array.
 256              $this->states = null;
 257          }
 258  
 259          if (!quiz_report_can_filter_only_graded($this->quiz)) {
 260              // A grading mode like 'average' has been selected, so we cannot do
 261              // the show the attempt that gave the final grade thing.
 262              $this->onlygraded = false;
 263          }
 264  
 265          if ($this->attempts == attempts_report::ENROLLED_WITHOUT) {
 266              $this->states = null;
 267              $this->onlygraded = false;
 268          }
 269  
 270          if (!$this->is_showing_finished_attempts()) {
 271              $this->onlygraded = false;
 272          }
 273  
 274          if ($this->pagesize < 1) {
 275              $this->pagesize = attempts_report::DEFAULT_PAGE_SIZE;
 276          }
 277      }
 278  
 279      /**
 280       * Whether the options are such that finished attempts are being shown.
 281       * @return boolean
 282       */
 283      protected function is_showing_finished_attempts() {
 284          return $this->states === null || in_array(quiz_attempt::FINISHED, $this->states);
 285      }
 286  }