merging MOODLE_19_QUESTIONS with HEAD
[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);
25 // Test if we are continuing an attempt at a question
26 $continue = optional_param('continue', 0, PARAM_BOOL);
27 // Check for any of the submit buttons
28 $fillcorrect = optional_param('fillcorrect', 0, PARAM_BOOL);
29 $markall = optional_param('markall', 0, PARAM_BOOL);
30 $finishattempt = optional_param('finishattempt', 0, PARAM_BOOL);
31 $back = optional_param('back', 0, PARAM_BOOL);
32 $startagain = optional_param('startagain', 0, PARAM_BOOL);
33 // We are always continuing an attempt if a submit button was pressed with the
34 // exception of the start again button
35 if ($fillcorrect || $markall || $finishattempt || $back) {
36 $continue = true;
37 } else if ($startagain) {
38 $continue = false;
39 }
40
41 require_login();
42
d02eeded 43 // this might break things in the future
516cf3eb 44 if (!isteacherinanycourse()) {
45 error('This page is for teachers only');
46 }
47
48 if (!$continue) {
49 // Start a new attempt; delete the old session
50 unset($SESSION->quizpreview);
51 // Redirect to ourselves but with continue=1; prevents refreshing the page
52 // from restarting an attempt (needed so that random questions don't change)
7d87171b 53 $url = $CFG->wwwroot . '/question/preview.php?id=' . $id;
54 if ($quizid) {
55 $url .= '&amp;quizid=' . $quizid;
56 }
57 $url .= '&amp;continue=1';
58 redirect($url);
516cf3eb 59 }
60
61 if (empty($quizid)) {
219e92f2 62 $quiz = new cmoptions;
63 $quiz->id = 0;
6af1e0b2 64 $quiz->review = $CFG->quiz_review;
516cf3eb 65
66 } else if (!$quiz = get_record('quiz', 'id', $quizid)) {
67 error("Quiz id $quizid does not exist");
68 }
69
70 // Load the question information
4f48fb42 71 if (!$questions = get_records('question', 'id', $id)) {
516cf3eb 72 error('Could not load question');
73 }
74 if ($maxgrade = get_field('quiz_question_instances', 'grade', 'quiz', $quiz->id, 'question', $id)) {
75 $questions[$id]->maxgrade = $maxgrade;
76 } else {
77 $questions[$id]->maxgrade = $questions[$id]->defaultgrade;
78 }
79
80 $quiz->id = 0; // just for safety
81 $quiz->questions = $id;
82
dc1f00de 83 if (!$category = get_record("question_categories", "id", $questions[$id]->category)) {
516cf3eb 84 error("This question doesn't belong to a valid category!");
85 }
86
d02eeded 87 if (!has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $category->course)) and !$category->publish) {
516cf3eb 88 error("You can't preview these questions!");
89 }
90 $quiz->course = $category->course;
91
92 // Load the question type specific information
4f48fb42 93 if (!get_question_options($questions)) {
516cf3eb 94 error(get_string('newattemptfail', 'quiz'));
95 }
96
97 // Create a dummy quiz attempt
219e92f2 98 // TODO: find out what of the following we really need. What is $attempt
99 // really used for?
100 $timenow = time();
101 $attempt->quiz = $quiz->id;
102 $attempt->userid = $USER->id;
103 $attempt->attempt = 0;
104 $attempt->sumgrades = 0;
105 $attempt->timestart = $timenow;
106 $attempt->timefinish = 0;
107 $attempt->timemodified = $timenow;
b518c69e 108 $attempt->uniqueid = 0;
516cf3eb 109 $attempt->id = 0;
110
111 // Restore the history of question sessions from the moodle session or create
112 // new sessions. Make $states a reference to the states array in the moodle
113 // session.
114 if (isset($SESSION->quizpreview->states) and $SESSION->quizpreview->questionid
115 == $id) {
116 // Reload the question session history from the moodle session
117 $states =& $SESSION->quizpreview->states;
118 $historylength = count($states) - 1;
119 if ($back && $historylength > 0) {
120 // Go back one step in the history
121 unset($states[$historylength]);
122 $historylength--;
123 }
124 } else {
125 // Record the question id in the moodle session
126 $SESSION->quizpreview->questionid = $id;
127 // Create an empty session for the question
128 if (!$newstates =
4f48fb42 129 get_question_states($questions, $quiz, $attempt)) {
516cf3eb 130 error(get_string('newattemptfail', 'quiz'));
131 }
132 $SESSION->quizpreview->states = array($newstates);
133 $states =& $SESSION->quizpreview->states;
134 $historylength = 0;
135 }
136
137 if (!$fillcorrect && !$back && ($form = data_submitted())) {
138 $form = (array)$form;
139 $submitted = true;
140
141 // Create a new item in the history of question states (don't simplify!)
142 $states[$historylength + 1] = array();
143 $states[$historylength + 1][$id] = clone($states[$historylength][$id]);
144 $historylength++;
145 $curstate =& $states[$historylength][$id];
b518c69e 146 $curstate->changed = false;
516cf3eb 147
148 // Process the responses
149 unset($form['id']);
150 unset($form['quizid']);
151 unset($form['continue']);
152 unset($form['markall']);
153 unset($form['finishattempt']);
154 unset($form['back']);
155 unset($form['startagain']);
156
b518c69e 157 $event = $finishattempt ? QUESTION_EVENTCLOSE : QUESTION_EVENTSUBMIT;
4f48fb42 158 if ($actions = question_extract_responses($questions, $form, $event)) {
516cf3eb 159 $actions[$id]->timestamp = 0; // We do not care about timelimits here
b518c69e 160 question_process_responses($questions[$id], $curstate, $actions[$id], $quiz, $attempt);
161 if (!$curstate->changed) {
516cf3eb 162 // Update the current state rather than creating a new one
163 $historylength--;
164 unset($states[$historylength]);
165 $states = array_values($states);
166 $curstate =& $states[$historylength][$id];
167 }
168 }
169 } else {
170 $submitted = false;
171 $curstate =& $states[$historylength][$id];
172 }
173
66125eda 174 // TODO: should not use quiz-specific function here
175 $options = quiz_get_renderoptions($quiz->review, $curstate);
516cf3eb 176
177 // Fill in the correct responses (unless the question is in readonly mode)
178 if ($fillcorrect && !$options->readonly) {
f02c6f01 179 $curstate->responses = $QTYPES[$questions[$id]->qtype]
516cf3eb 180 ->get_correct_responses($questions[$id], $curstate);
181 }
182
70ed7667 183 $strpreview = get_string('preview', 'quiz').' '.format_string($questions[$id]->name);
7d87171b 184 $questionlist = array($id);
185 $headtags = get_html_head_contributions($questionlist, $questions, $states[$historylength]);
186 print_header($strpreview, '', '', '', $headtags);
516cf3eb 187 print_heading($strpreview);
188
3a5a6f59 189 if (!empty($quizid)) {
2139364f 190 echo '<p class="quemodname">'.get_string('modulename', 'quiz') . ': ';
516cf3eb 191 p($quiz->name);
3a5a6f59 192 echo "</p>\n";
516cf3eb 193 }
516cf3eb 194 $number = 1;
46a29ccf 195 echo '<form method="post" action="preview.php" enctype="multipart/form-data" id="responseform">', "\n";
4f48fb42 196 print_question($questions[$id], $curstate, $number, $quiz, $options);
516cf3eb 197 echo '<br />';
2697726a 198
199
2e7bdb51 200
2139364f 201 echo '<div class="controls">';
2697726a 202 echo "<input type=\"hidden\" name=\"id\" value=\"$id\" />\n";
203 echo "<input type=\"hidden\" name=\"quizid\" value=\"$quizid\" />\n";
204 echo "<input type=\"hidden\" name=\"continue\" value=\"1\" />\n";
516cf3eb 205
206 // Print the mark and finish attempt buttons
207 echo '<input name="markall" type="submit" value="' . get_string('markall',
208 'quiz') . "\" />\n";
209 echo '<input name="finishattempt" type="submit" value="' .
210 get_string('finishattempt', 'quiz') . "\" />\n";
211 echo '<br />';
212 echo '<br />';
213 // Print the fill correct button (unless the question is in readonly mode)
214 if (!$options->readonly) {
215 echo '<input name="fillcorrect" type="submit" value="' .
216 get_string('fillcorrect', 'quiz') . "\" />\n";
217 }
218 // Print the navigation buttons
219 if ($historylength > 0) {
220 echo '<input name="back" type="submit" value="' . get_string('previous',
221 'quiz') . "\" />\n";
222 }
223 // Print the start again button
224 echo '<input name="startagain" type="submit" value="' .
225 get_string('startagain', 'quiz') . "\" />\n";
226 // Print the close window button
227 echo '<input type="button" onclick="window.close()" value="' .
228 get_string('closepreview', 'quiz') . "\" />";
2139364f 229 echo '</div>';
516cf3eb 230 echo '</form>';
231 print_footer();
2697726a 232?>