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