Automatic installer.php lang files by installer_builder (20060913)
[moodle.git] / question / question.php
blobca4320b33ae6aacc017615113f1b606b06984d1d
1 <?php // $Id$
2 /*
3 * Page for editing questions
5 * This page shows the question editing form or processes the following actions:
6 * - create new question (category, qtype)
7 * - edit question (id, contextquiz (optional))
8 * - cancel (cancel)
10 * TODO: currently this still treats the quiz as special
11 * TODO: question versioning is not currently enabled
13 * @version $Id$
14 * @author Martin Dougiamas and many others. This has recently been extensively
15 * rewritten by members of the Serving Mathematics project
16 * {@link http://maths.york.ac.uk/serving_maths}
17 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
18 * @package question
21 require_once("../config.php");
22 // NOTE - is this correct? This is just about editing screens?
23 require_once( "editlib.php" );
24 require_once($CFG->libdir.'/filelib.php');
26 $id = optional_param('id', 0, PARAM_INT); // question id
28 $qtype = optional_param('qtype', '', PARAM_FILE);
29 $category = optional_param('category', 0, PARAM_INT);
32 $CFG->pagepath = 'question/type/'.$qtype;
35 // rqp questions set the type to rqp_nn where nn is the rqp_type id
36 if (substr($qtype, 0, 4) == 'rqp_') {
37 $typeid = (int) substr($qtype, 4);
38 $qtype = 'rqp';
41 if ($id) {
42 if (! $question = get_record("question", "id", $id)) {
43 error("This question doesn't exist");
45 if (!empty($category)) {
46 $question->category = $category;
48 if (! $category = get_record("question_categories", "id", $question->category)) {
49 error("This question doesn't belong to a valid category!");
51 if (! $course = get_record("course", "id", $category->course)) {
52 error("This question category doesn't belong to a valid course!");
55 $qtype = $question->qtype;
56 if (!isset($QTYPES[$qtype])) {
57 $qtype = 'missingtype';
60 } else if ($category) { // only for creating new questions
61 if (! $category = get_record("question_categories", "id", $category)) {
62 error("This wasn't a valid category!");
64 if (! $course = get_record("course", "id", $category->course)) {
65 error("This category doesn't belong to a valid course!");
68 $question->category = $category->id;
69 $question->qtype = $qtype;
71 } else {
72 error("Must specify question id or category");
75 if (!isset($SESSION->returnurl)) {
76 $SESSION->returnurl = 'edit.php?courseid='.$course->id;
79 // TODO: generalise this so it works for any activity
80 $contextquiz = isset($SESSION->modform->instance) ? $SESSION->modform->instance : 0;
82 if (isset($_REQUEST['cancel'])) {
83 redirect($SESSION->returnurl);
86 if (empty($qtype)) {
87 error("No question type was specified!");
88 } else if (!isset($QTYPES[$qtype])) {
89 error("Could not find question type: '$qtype'");
92 require_login($course->id, false);
94 if (!isteacheredit($course->id)) {
95 error("You can't modify these questions!");
98 // TODO: remove restriction to quiz
99 $streditingquestion = get_string('editingquestion', 'quiz');
100 if (isset($SESSION->modform->instance)) {
101 $strediting = '<a href="'.$SESSION->returnurl.'">'.get_string('editingquiz', 'quiz').'</a> -> '.
102 $streditingquestion;
103 } else {
104 $strediting = '<a href="edit.php?courseid='.$course->id.'">'.
105 get_string("editquestions", "quiz").'</a> -> '.$streditingquestion;
108 print_header_simple("$streditingquestion", "", $strediting);
110 if ($form = data_submitted() and confirm_sesskey()) {
112 if (isset($form->versioning) && isset($question->id) and false) { // disable versioning until it is fixed.
113 // use new code that handles whether to overwrite or copy a question
114 // and keeps track of the versions in the quiz_question_version table
116 // $replaceinquiz is an array with the ids of all quizzes in which
117 // the teacher has chosen to replace the old version
118 $replaceinquiz = array();
119 foreach($form as $key => $val) {
120 if ($tmp = quiz_parse_fieldname($key, 'q')) {
121 if ($tmp['mode'] == 'replace') {
122 $replaceinquiz[$tmp['id']] = $tmp['id'];
123 unset($form->$key);
128 // $quizlist is an array with the ids of quizzes which use this question
129 $quizlist = array();
130 if ($instances = get_records('quiz_question_instances', 'question', $question->id)) {
131 foreach($instances as $instance) {
132 $quizlist[$instance->quiz] = $instance->quiz;
136 if (isset($form->makecopy)) { // explicitly requested copies should be unhidden
137 $question->hidden = 0;
140 // Logic to determine whether old version should be overwritten
141 $makecopy = isset($form->makecopy) || (!$form->id); unset($form->makecopy);
142 if ($makecopy) {
143 $replaceold = false;
144 } else {
145 // this should be improved to exclude teacher preview responses and empty responses
146 // the current code leaves many unneeded questions in the database
147 $hasresponses = record_exists('question_states', 'question', $form->id) or
148 record_exists('question_states', 'originalquestion', $form->id);
149 $replaceinall = ($quizlist == $replaceinquiz); // question is being replaced in all quizzes
150 $replaceold = !$hasresponses && $replaceinall;
153 $oldquestionid = false;
154 if (!$replaceold) { // create a new question
155 $oldquestionid = $question->id;
156 if (!$makecopy) {
157 if (!set_field("question", 'hidden', 1, 'id', $question->id)) {
158 error("Could not hide question!");
161 unset($question->id);
163 unset($makecopy, $hasresponses, $replaceinall, $replaceold);
164 $question = $QTYPES[$qtype]->save_question($question, $form, $course);
165 if(!isset($question->id)) {
166 error("Failed to save the question!");
169 if(!empty($oldquestionid)) {
170 // create version entries for different quizzes
171 $version = new object();
172 $version->oldquestion = $oldquestionid;
173 $version->newquestion = $question->id;
174 $version->userid = $USER->id;
175 $version->timestamp = time();
177 foreach($replaceinquiz as $qid) {
178 $version->quiz = $qid;
179 if(!insert_record("quiz_question_versions", $version)) {
180 error("Could not store version information of question $oldquestionid in quiz $qid!");
184 /// now update the question references in the quizzes
185 if (!empty($replaceinquiz) and $quizzes = get_records_list("quiz", "id", implode(',', $replaceinquiz))) {
187 foreach($quizzes as $quiz) {
188 $questionlist = ",$quiz->questions,"; // a little hack with the commas here. not nice but effective
189 $questionlist = str_replace(",$oldquestionid,", ",$question->id,", $questionlist);
190 $questionlist = substr($questionlist, 1, -1); // and get rid of the surrounding commas again
191 if (!set_field("quiz", 'questions', $questionlist, 'id', $quiz->id)) {
192 error("Could not update questionlist in quiz $quiz->id!");
195 // the quiz_question_instances table needs to be updated too (aah, the joys of duplication :)
196 if (!set_field('quiz_question_instances', 'question', $question->id, 'quiz', $quiz->id, 'question', $oldquestionid)) {
197 error("Could not update question instance!");
199 if (isset($SESSION->modform) && (int)$SESSION->modform->instance === (int)$quiz->id) {
200 $SESSION->modform->questions = $questionlist;
201 $SESSION->modform->grades[$question->id] = $SESSION->modform->grades[$oldquestionid];
202 unset($SESSION->modform->grades[$oldquestionid]);
206 // change question in attempts
207 if ($attempts = get_records_list('quiz_attempts', 'quiz', implode(',', $replaceinquiz))) {
208 foreach ($attempts as $attempt) {
210 // replace question id in $attempt->layout
211 $questionlist = ",$attempt->layout,"; // a little hack with the commas here. not nice but effective
212 $questionlist = str_replace(",$oldquestionid,", ",$question->id,", $questionlist);
213 $questionlist = substr($questionlist, 1, -1); // and get rid of the surrounding commas again
214 if (!set_field('quiz_attempts', 'layout', $questionlist, 'id', $attempt->id)) {
215 error("Could not update layout in attempt $attempt->id!");
218 // set originalquestion in states
219 set_field('question_states', 'originalquestion', $oldquestionid, 'attempt', $attempt->uniqueid, 'question', $question->id, 'originalquestion', '0');
221 // replace question id in states
222 set_field('question_states', 'question', $question->id, 'attempt', $attempt->uniqueid, 'question', $oldquestionid);
224 // replace question id in sessions
225 set_field('question_sessions', 'questionid', $question->id, 'attemptid', $attempt->uniqueid, 'questionid', $oldquestionid);
229 // Now do anything question-type specific that is required to replace the question
230 // For example questions that use the question_answers table to hold part of their question will
231 // have to recode the answer ids in the states
232 $QTYPES[$question->qtype]->change_states_question($oldquestionid, $question, $attempts);
236 } else {
237 // use the old code which simply overwrites old versions
238 // it is also used for creating new questions
240 if (isset($form->makecopy)) {
241 $question->hidden = 0; // explicitly requested copies should be unhidden
242 $question->id = 0; // This will prompt save_question to create a new question
244 $question = $QTYPES[$qtype]->save_question($question, $form, $course);
245 $replaceinquiz = 'all';
248 if (empty($question->errors) && $QTYPES[$qtype]->finished_edit_wizard($form)) {
249 // DISABLED AUTOMATIC REGRADING
250 // Automagically regrade all attempts (and states) in the affected quizzes
251 //if (!empty($replaceinquiz)) {
252 // $QTYPES[$question->qtype]->get_question_options($question);
253 // quiz_regrade_question_in_quizzes($question, $replaceinquiz);
255 redirect($SESSION->returnurl);
259 // prepare the grades selector drop-down used by many question types
260 $creategrades = get_grade_options();
261 $gradeoptions = $creategrades->gradeoptions;
262 $gradeoptionsfull = $creategrades->gradeoptionsfull;
264 if (!$categories = question_category_menu($course->id, false)) {
265 error("No categories!");
269 make_upload_directory("$course->id"); // Just in case
270 $coursefiles = get_directory_list("$CFG->dataroot/$course->id", $CFG->moddata);
271 foreach ($coursefiles as $filename) {
272 if (mimeinfo("icon", $filename) == "image.gif") {
273 $images["$filename"] = $filename;
277 // Print the question editing form
279 if (empty($question->id)) {
280 $question->id = "";
282 if (empty($question->name)) {
283 $question->name = "";
285 if (empty($question->questiontext)) {
286 $question->questiontext = "";
288 if (empty($question->image)) {
289 $question->image = "";
291 if (!isset($question->penalty)) {
292 $question->penalty = 0.1;
294 if (!isset($question->defaultgrade)) {
295 $question->defaultgrade = 1;
298 // Set up some Richtext editing if necessary
299 if ($usehtmleditor = can_use_richtext_editor()) {
300 $defaultformat = FORMAT_HTML;
301 } else {
302 $defaultformat = FORMAT_MOODLE;
305 if (isset($question->errors)) {
306 $err = $question->errors;
309 echo '<br />';
310 print_simple_box_start('center');
311 require_once('type/'.$qtype.'/editquestion.php');
312 print_simple_box_end();
314 if ($usehtmleditor) {
315 use_html_editor('questiontext');
318 print_footer($course);