quiz: fix debugging notice ->classes = to set_classes.
[moodle.git] / question / preview.php
CommitLineData
516cf3eb 1<?php // $Id$
2/**
4323d029 3 * This page displays a preview of a question
4 *
5 * The preview uses the option settings from the activity within which the question
6 * is previewed or the default settings if no activity is specified. The question session
7 * information is stored in the session as an array of subsequent states rather
8 * than in the database.
9 *
10 * TODO: make this work with activities other than quiz
11 *
12 * @author Alex Smith as part of the Serving Mathematics project
13 * {@link http://maths.york.ac.uk/serving_maths}
14 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
15 * @package questionbank
16 */
516cf3eb 17
e586cfb4 18 require_once("../config.php");
19 require_once($CFG->libdir.'/questionlib.php');
20 require_once($CFG->dirroot.'/mod/quiz/locallib.php'); // We really want to get rid of this
516cf3eb 21
22 $id = required_param('id', PARAM_INT); // question id
23 // if no quiz id is specified then a dummy quiz with default options is used
24 $quizid = optional_param('quizid', 0, PARAM_INT);
e7e62d45 25 // if no quiz id is specified then tell us the course
26 if (empty($quizid)) {
27 $courseid = required_param('courseid', PARAM_INT);
28 }
29
516cf3eb 30 // Test if we are continuing an attempt at a question
31 $continue = optional_param('continue', 0, PARAM_BOOL);
32 // Check for any of the submit buttons
33 $fillcorrect = optional_param('fillcorrect', 0, PARAM_BOOL);
34 $markall = optional_param('markall', 0, PARAM_BOOL);
35 $finishattempt = optional_param('finishattempt', 0, PARAM_BOOL);
36 $back = optional_param('back', 0, PARAM_BOOL);
37 $startagain = optional_param('startagain', 0, PARAM_BOOL);
38 // We are always continuing an attempt if a submit button was pressed with the
39 // exception of the start again button
40 if ($fillcorrect || $markall || $finishattempt || $back) {
41 $continue = true;
42 } else if ($startagain) {
43 $continue = false;
44 }
45
3a4a9233 46 $url = new moodle_url($CFG->wwwroot . '/question/preview.php');
47 $url->param('id', $id);
48 if ($quizid) {
49 $url->param('quizid', $quizid);
50 } else {
51 $url->param('courseid', $courseid);
52 }
53 $url->param('continue', 1);
516cf3eb 54 if (!$continue) {
55 // Start a new attempt; delete the old session
56 unset($SESSION->quizpreview);
57 // Redirect to ourselves but with continue=1; prevents refreshing the page
58 // from restarting an attempt (needed so that random questions don't change)
e42f153c 59 redirect($url);
516cf3eb 60 }
271e6dec 61 // Load the question information
f34488b2 62 if (!$questions = $DB->get_records('question', array('id' => $id))) {
ac93d63d 63 print_error('cannotloadquestion', 'question');
271e6dec 64 }
516cf3eb 65 if (empty($quizid)) {
219e92f2 66 $quiz = new cmoptions;
67 $quiz->id = 0;
0cd46577 68 $quiz->review = get_config('quiz', 'review');
e7e62d45 69 require_login($courseid, false);
70 $quiz->course = $courseid;
71990c7c 71 $quiz->decimalpoints = get_config('quiz', 'decimalpoints');
62e76c67 72 $context = get_context_instance(CONTEXT_COURSE, $courseid);
f34488b2 73 } else if (!$quiz = $DB->get_record('quiz', array('id' => $quizid))) {
ac93d63d 74 print_error('invalidquizid', 'quiz', '', $quizid);
271e6dec 75 } else {
62e76c67 76 $cm = get_coursemodule_from_instance('quiz', $quizid, $quiz->course);
77 require_login($quiz->course, false, $cm);
78 $context = get_context_instance(CONTEXT_MODULE, $cm->id);
516cf3eb 79 }
80
f34488b2 81 if ($maxgrade = $DB->get_field('quiz_question_instances', 'grade', array('quiz' => $quiz->id, 'question' => $id))) {
516cf3eb 82 $questions[$id]->maxgrade = $maxgrade;
83 } else {
84 $questions[$id]->maxgrade = $questions[$id]->defaultgrade;
85 }
86
87 $quiz->id = 0; // just for safety
88 $quiz->questions = $id;
89
f34488b2 90 if (!$category = $DB->get_record("question_categories", array("id" => $questions[$id]->category))) {
ac93d63d 91 print_error('invalidquestionid', 'quiz');
516cf3eb 92 }
93
271e6dec 94 if (!question_has_capability_on($questions[$id], 'use', $questions[$id]->category)){
ac93d63d 95 print_error('cannotpreview', 'question');
516cf3eb 96 }
271e6dec 97 if (isset($COURSE)){
98 $quiz->course = $COURSE->id;
99 }
516cf3eb 100
101 // Load the question type specific information
4f48fb42 102 if (!get_question_options($questions)) {
5a2a5331 103 print_error('newattemptfail', 'quiz');
516cf3eb 104 }
105
106 // Create a dummy quiz attempt
219e92f2 107 // TODO: find out what of the following we really need. What is $attempt
108 // really used for?
109 $timenow = time();
110 $attempt->quiz = $quiz->id;
111 $attempt->userid = $USER->id;
112 $attempt->attempt = 0;
113 $attempt->sumgrades = 0;
114 $attempt->timestart = $timenow;
115 $attempt->timefinish = 0;
116 $attempt->timemodified = $timenow;
b518c69e 117 $attempt->uniqueid = 0;
516cf3eb 118 $attempt->id = 0;
71990c7c 119 $attempt->layout = $id;
516cf3eb 120
121 // Restore the history of question sessions from the moodle session or create
122 // new sessions. Make $states a reference to the states array in the moodle
123 // session.
3a4a9233 124 if (isset($SESSION->quizpreview->states) and $SESSION->quizpreview->questionid == $id) {
516cf3eb 125 // Reload the question session history from the moodle session
126 $states =& $SESSION->quizpreview->states;
127 $historylength = count($states) - 1;
128 if ($back && $historylength > 0) {
129 // Go back one step in the history
130 unset($states[$historylength]);
131 $historylength--;
132 }
133 } else {
134 // Record the question id in the moodle session
135 $SESSION->quizpreview->questionid = $id;
136 // Create an empty session for the question
81d833ad 137 if (!$newstates = get_question_states($questions, $quiz, $attempt)) {
5a2a5331 138 print_error('newattemptfail', 'quiz');
516cf3eb 139 }
e056398a 140 $newstates[$id]->questionsessionid = 0;
516cf3eb 141 $SESSION->quizpreview->states = array($newstates);
142 $states =& $SESSION->quizpreview->states;
143 $historylength = 0;
144 }
145
146 if (!$fillcorrect && !$back && ($form = data_submitted())) {
147 $form = (array)$form;
148 $submitted = true;
149
150 // Create a new item in the history of question states (don't simplify!)
151 $states[$historylength + 1] = array();
152 $states[$historylength + 1][$id] = clone($states[$historylength][$id]);
153 $historylength++;
154 $curstate =& $states[$historylength][$id];
b518c69e 155 $curstate->changed = false;
516cf3eb 156
157 // Process the responses
158 unset($form['id']);
159 unset($form['quizid']);
160 unset($form['continue']);
161 unset($form['markall']);
162 unset($form['finishattempt']);
163 unset($form['back']);
164 unset($form['startagain']);
165
84857f8c 166 if ($finishattempt) {
167 $event = QUESTION_EVENTCLOSE;
168 } else if ($markall) {
169 $event = QUESTION_EVENTSUBMIT;
170 } else {
171 $event = QUESTION_EVENTSAVE;
172 }
4f48fb42 173 if ($actions = question_extract_responses($questions, $form, $event)) {
516cf3eb 174 $actions[$id]->timestamp = 0; // We do not care about timelimits here
373f0afd 175 if (!question_process_responses($questions[$id], $curstate, $actions[$id], $quiz, $attempt)) {
176 unset($SESSION->quizpreview);
177 print_error('errorprocessingresponses', 'question', $url->out());
178 }
b518c69e 179 if (!$curstate->changed) {
516cf3eb 180 // Update the current state rather than creating a new one
181 $historylength--;
182 unset($states[$historylength]);
183 $states = array_values($states);
184 $curstate =& $states[$historylength][$id];
185 }
186 }
187 } else {
188 $submitted = false;
189 $curstate =& $states[$historylength][$id];
190 }
191
66125eda 192 // TODO: should not use quiz-specific function here
62e76c67 193 $options = quiz_get_renderoptions($quiz, $attempt, $context, $curstate);
aafdb447 194 $options->noeditlink = true;
516cf3eb 195
196 // Fill in the correct responses (unless the question is in readonly mode)
197 if ($fillcorrect && !$options->readonly) {
f34488b2 198 $curstate->responses = $QTYPES[$questions[$id]->qtype]->get_correct_responses($questions[$id], $curstate);
516cf3eb 199 }
200
70ed7667 201 $strpreview = get_string('preview', 'quiz').' '.format_string($questions[$id]->name);
7d87171b 202 $questionlist = array($id);
d412354c 203 get_html_head_contributions($questionlist, $questions, $states[$historylength]);
204 $PAGE->set_title($strpreview);
205 echo $OUTPUT->header();
723d610c 206 echo $OUTPUT->heading($strpreview);
516cf3eb 207
3a5a6f59 208 if (!empty($quizid)) {
2139364f 209 echo '<p class="quemodname">'.get_string('modulename', 'quiz') . ': ';
29e959a5 210 p(format_string($quiz->name));
3a5a6f59 211 echo "</p>\n";
516cf3eb 212 }
516cf3eb 213 $number = 1;
3a4a9233 214 echo '<form method="post" action="'.$url->out(true).'" enctype="multipart/form-data" id="responseform">', "\n";
4f48fb42 215 print_question($questions[$id], $curstate, $number, $quiz, $options);
271e6dec 216
2139364f 217 echo '<div class="controls">';
3a4a9233 218 echo $url->hidden_params_out();
516cf3eb 219
220 // Print the mark and finish attempt buttons
221 echo '<input name="markall" type="submit" value="' . get_string('markall',
222 'quiz') . "\" />\n";
223 echo '<input name="finishattempt" type="submit" value="' .
224 get_string('finishattempt', 'quiz') . "\" />\n";
225 echo '<br />';
226 echo '<br />';
227 // Print the fill correct button (unless the question is in readonly mode)
228 if (!$options->readonly) {
229 echo '<input name="fillcorrect" type="submit" value="' .
230 get_string('fillcorrect', 'quiz') . "\" />\n";
231 }
232 // Print the navigation buttons
233 if ($historylength > 0) {
234 echo '<input name="back" type="submit" value="' . get_string('previous',
235 'quiz') . "\" />\n";
236 }
237 // Print the start again button
238 echo '<input name="startagain" type="submit" value="' .
239 get_string('startagain', 'quiz') . "\" />\n";
240 // Print the close window button
241 echo '<input type="button" onclick="window.close()" value="' .
242 get_string('closepreview', 'quiz') . "\" />";
2139364f 243 echo '</div>';
516cf3eb 244 echo '</form>';
9b59580b 245 echo $OUTPUT->footer();
29e959a5 246?>