Merged branch 'MDL-27692_master' of git://github.com/MaryE/moodle.git
[moodle.git] / question / previewlib.php
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/>.
17 /**
18  * Library functions used by question/preview.php.
19  *
20  * @package    moodlecore
21  * @subpackage questionengine
22  * @copyright  2010 The Open University
23  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
24  */
27 defined('MOODLE_INTERNAL') || die();
29 require_once($CFG->libdir . '/formslib.php');
32 /**
33  * Settings form for the preview options.
34  *
35  * @copyright  2009 The Open University
36  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37  */
38 class preview_options_form extends moodleform {
39     public function definition() {
40         $mform = $this->_form;
42         $hiddenofvisible = array(
43             question_display_options::HIDDEN => get_string('notshown', 'question'),
44             question_display_options::VISIBLE => get_string('shown', 'question'),
45         );
47         $mform->addElement('header', 'optionsheader', get_string('changeoptions', 'question'));
49         $behaviours = question_engine::get_behaviour_options(
50                 $this->_customdata['quba']->get_preferred_behaviour());
51         $mform->addElement('select', 'behaviour',
52                 get_string('howquestionsbehave', 'question'), $behaviours);
53         $mform->addHelpButton('behaviour', 'howquestionsbehave', 'question');
55         $mform->addElement('text', 'maxmark', get_string('markedoutof', 'question'),
56                 array('size' => '5'));
57         $mform->setType('maxmark', PARAM_NUMBER);
59         if ($this->_customdata['maxvariant'] > 1) {
60             $variants = range(1, $this->_customdata['maxvariant']);
61             $mform->addElement('select', 'variant', get_string('questionvariant', 'question'),
62                     array_combine($variants, $variants));
63         }
64         $mform->setType('maxmark', PARAM_INT);
66         $mform->addElement('select', 'correctness', get_string('whethercorrect', 'question'),
67                 $hiddenofvisible);
69         $marksoptions = array(
70             question_display_options::HIDDEN => get_string('notshown', 'question'),
71             question_display_options::MAX_ONLY => get_string('showmaxmarkonly', 'question'),
72             question_display_options::MARK_AND_MAX => get_string('showmarkandmax', 'question'),
73         );
74         $mform->addElement('select', 'marks', get_string('marks', 'question'), $marksoptions);
76         $mform->addElement('select', 'markdp', get_string('decimalplacesingrades', 'question'),
77                 question_engine::get_dp_options());
79         $mform->addElement('select', 'feedback',
80                 get_string('specificfeedback', 'question'), $hiddenofvisible);
82         $mform->addElement('select', 'generalfeedback',
83                 get_string('generalfeedback', 'question'), $hiddenofvisible);
85         $mform->addElement('select', 'rightanswer',
86                 get_string('rightanswer', 'question'), $hiddenofvisible);
88         $mform->addElement('select', 'history',
89                 get_string('responsehistory', 'question'), $hiddenofvisible);
91         $mform->addElement('submit', 'submit',
92                 get_string('restartwiththeseoptions', 'question'), $hiddenofvisible);
93     }
94 }
97 /**
98  * Displays question preview options as default and set the options
99  * Setting default, getting and setting user preferences in question preview options.
100  *
101  * @copyright  2010 The Open University
102  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
103  */
104 class question_preview_options extends question_display_options {
105     /** @var string the behaviour to use for this preview. */
106     public $behaviour;
108     /** @var number the maximum mark to use for this preview. */
109     public $maxmark;
111     /** @var int the variant of the question to preview. */
112     public $variant;
114     /** @var string prefix to append to field names to get user_preference names. */
115     const OPTIONPREFIX = 'question_preview_options_';
117     /**
118      * Constructor.
119      */
120     public function __construct($question) {
121         global $CFG;
122         $this->behaviour = 'deferredfeedback';
123         $this->maxmark = $question->defaultmark;
124         $this->variant = null;
125         $this->correctness = self::VISIBLE;
126         $this->marks = self::MARK_AND_MAX;
127         $this->markdp = get_config('quiz', 'decimalpoints');
128         $this->feedback = self::VISIBLE;
129         $this->numpartscorrect = $this->feedback;
130         $this->generalfeedback = self::VISIBLE;
131         $this->rightanswer = self::VISIBLE;
132         $this->history = self::HIDDEN;
133         $this->flags = self::HIDDEN;
134         $this->manualcomment = self::HIDDEN;
135     }
137     /**
138      * @return array names of the options we store in the user preferences table.
139      */
140     protected function get_user_pref_fields() {
141         return array('behaviour', 'correctness', 'marks', 'markdp', 'feedback',
142                 'generalfeedback', 'rightanswer', 'history');
143     }
145     /**
146      * @return array names and param types of the options we read from the request.
147      */
148     protected function get_field_types() {
149         return array(
150             'behaviour' => PARAM_ALPHA,
151             'maxmark' => PARAM_NUMBER,
152             'variant' => PARAM_INT,
153             'correctness' => PARAM_BOOL,
154             'marks' => PARAM_INT,
155             'markdp' => PARAM_INT,
156             'feedback' => PARAM_BOOL,
157             'generalfeedback' => PARAM_BOOL,
158             'rightanswer' => PARAM_BOOL,
159             'history' => PARAM_BOOL,
160         );
161     }
163     /**
164      * Load the value of the options from the user_preferences table.
165      */
166     public function load_user_defaults() {
167         foreach ($this->get_user_pref_fields() as $field) {
168             $this->$field = get_user_preferences(
169                     self::OPTIONPREFIX . $field, $this->$field);
170         }
171         $this->numpartscorrect = $this->feedback;
172     }
174     /**
175      * Save a change to the user's preview options to the database.
176      * @param object $newoptions
177      */
178     public function save_user_preview_options($newoptions) {
179         foreach ($this->get_user_pref_fields() as $field) {
180             if (isset($newoptions->$field)) {
181                 set_user_preference(self::OPTIONPREFIX . $field, $newoptions->$field);
182             }
183         }
184     }
186     /**
187      * Set the value of any fields included in the request.
188      */
189     public function set_from_request() {
190         foreach ($this->get_field_types() as $field => $type) {
191             $this->$field = optional_param($field, $this->$field, $type);
192         }
193         $this->numpartscorrect = $this->feedback;
194     }
196     /**
197      * @return string URL fragment. Parameters needed in the URL when continuing
198      * this preview.
199      */
200     public function get_url_params() {
201         $params = array();
202         foreach ($this->get_field_types() as $field => $notused) {
203             if ($field == 'behaviour' || $field == 'maxmark' || is_null($this->$field)) {
204                 continue;
205             }
206             $params[$field] = $this->$field;
207         }
208         return $params;
209     }
213 /**
214  * Called via pluginfile.php -> question_pluginfile to serve files belonging to
215  * a question in a question_attempt when that attempt is a preview.
216  *
217  * @param object $course course settings object
218  * @param object $context context object
219  * @param string $component the name of the component we are serving files for.
220  * @param string $filearea the name of the file area.
221  * @param int $qubaid the question_usage this image belongs to.
222  * @param int $slot the relevant slot within the usage.
223  * @param array $args the remaining bits of the file path.
224  * @param bool $forcedownload whether the user must be forced to download the file.
225  * @return bool false if file not found, does not return if found - justsend the file
226  */
227 function question_preview_question_pluginfile($course, $context, $component,
228         $filearea, $qubaid, $slot, $args, $forcedownload) {
229     global $USER, $DB, $CFG;
231     $quba = question_engine::load_questions_usage_by_activity($qubaid);
233     if ($quba->get_owning_context()->id != $context->id) {
234         send_file_not_found();
235     }
237     if (!question_has_capability_on($quba->get_question($slot), 'use')) {
238         send_file_not_found();
239     }
241     $options = new question_display_options();
242     $options->feedback = question_display_options::VISIBLE;
243     $options->numpartscorrect = question_display_options::VISIBLE;
244     $options->generalfeedback = question_display_options::VISIBLE;
245     $options->rightanswer = question_display_options::VISIBLE;
246     $options->manualcomment = question_display_options::VISIBLE;
247     $options->history = question_display_options::VISIBLE;
248     if (!$quba->check_file_access($slot, $options, $component,
249             $filearea, $args, $forcedownload)) {
250         send_file_not_found();
251     }
253     $fs = get_file_storage();
254     $relativepath = implode('/', $args);
255     $fullpath = "/$context->id/$component/$filearea/$relativepath";
256     if (!$file = $fs->get_file_by_hash(sha1($fullpath)) or $file->is_directory()) {
257         send_file_not_found();
258     }
260     send_stored_file($file, 0, 0, $forcedownload);
263 /**
264  * The the URL to use for actions relating to this preview.
265  * @param int $questionid the question being previewed.
266  * @param int $qubaid the id of the question usage for this preview.
267  * @param question_preview_options $options the options in use.
268  */
269 function question_preview_action_url($questionid, $qubaid,
270         question_preview_options $options) {
271     $params = array(
272         'id' => $questionid,
273         'previewid' => $qubaid,
274     );
275     $params = array_merge($params, $options->get_url_params());
276     return new moodle_url('/question/preview.php', $params);
279 /**
280  * Delete the current preview, if any, and redirect to start a new preview.
281  * @param int $previewid
282  * @param int $questionid
283  * @param object $displayoptions
284  */
285 function restart_preview($previewid, $questionid, $displayoptions) {
286     global $DB;
288     if ($previewid) {
289         $transaction = $DB->start_delegated_transaction();
290         question_engine::delete_questions_usage_by_activity($previewid);
291         $transaction->allow_commit();
292     }
293     redirect(question_preview_url($questionid, $displayoptions->behaviour,
294             $displayoptions->maxmark, $displayoptions, $displayoptions->variant));