Issue:
[moodle-pu.git] / question / type / truefalse / questiontype.php
blobed485029c36d55d565de708d80ebb00fa02cc78c
1 <?php // $Id$
3 /////////////////
4 /// TRUEFALSE ///
5 /////////////////
7 /// QUESTION TYPE CLASS //////////////////
8 /**
9 * @package questionbank
10 * @subpackage questiontypes
12 class question_truefalse_qtype extends default_questiontype {
14 function name() {
15 return 'truefalse';
18 function save_question_options($question) {
19 $result = new stdClass;
21 // fetch old answer ids so that we can reuse them
22 if (!$oldanswers = get_records("question_answers", "question", $question->id, "id ASC")) {
23 $oldanswers = array();
26 // Save answer 'True'
27 if ($true = array_shift($oldanswers)) { // Existing answer, so reuse it
28 $true->answer = get_string("true", "quiz");
29 $true->fraction = $question->correctanswer;
30 $true->feedback = $question->feedbacktrue;
31 if (!update_record("question_answers", $true)) {
32 $result->error = "Could not update quiz answer \"true\")!";
33 return $result;
35 } else {
36 unset($true);
37 $true->answer = get_string("true", "quiz");
38 $true->question = $question->id;
39 $true->fraction = $question->correctanswer;
40 $true->feedback = $question->feedbacktrue;
41 if (!$true->id = insert_record("question_answers", $true)) {
42 $result->error = "Could not insert quiz answer \"true\")!";
43 return $result;
47 // Save answer 'False'
48 if ($false = array_shift($oldanswers)) { // Existing answer, so reuse it
49 $false->answer = get_string("false", "quiz");
50 $false->fraction = 1 - (int)$question->correctanswer;
51 $false->feedback = $question->feedbackfalse;
52 if (!update_record("question_answers", $false)) {
53 $result->error = "Could not insert quiz answer \"false\")!";
54 return $result;
56 } else {
57 unset($false);
58 $false->answer = get_string("false", "quiz");
59 $false->question = $question->id;
60 $false->fraction = 1 - (int)$question->correctanswer;
61 $false->feedback = $question->feedbackfalse;
62 if (!$false->id = insert_record("question_answers", $false)) {
63 $result->error = "Could not insert quiz answer \"false\")!";
64 return $result;
68 // delete any leftover old answer records (there couldn't really be any, but who knows)
69 if (!empty($oldanswers)) {
70 foreach($oldanswers as $oa) {
71 delete_records('question_answers', 'id', $oa->id);
75 // Save question options in question_truefalse table
76 if ($options = get_record("question_truefalse", "question", $question->id)) {
77 // No need to do anything, since the answer IDs won't have changed
78 // But we'll do it anyway, just for robustness
79 $options->trueanswer = $true->id;
80 $options->falseanswer = $false->id;
81 if (!update_record("question_truefalse", $options)) {
82 $result->error = "Could not update quiz truefalse options! (id=$options->id)";
83 return $result;
85 } else {
86 unset($options);
87 $options->question = $question->id;
88 $options->trueanswer = $true->id;
89 $options->falseanswer = $false->id;
90 if (!insert_record("question_truefalse", $options)) {
91 $result->error = "Could not insert quiz truefalse options!";
92 return $result;
95 return true;
98 /**
99 * Loads the question type specific options for the question.
101 function get_question_options(&$question) {
102 // Get additional information from database
103 // and attach it to the question object
104 if (!$question->options = get_record('question_truefalse', 'question', $question->id)) {
105 notify('Error: Missing question options!');
106 return false;
108 // Load the answers
109 if (!$question->options->answers = get_records('question_answers', 'question', $question->id, 'id ASC')) {
110 notify('Error: Missing question answers!');
111 return false;
114 return true;
118 * Deletes question from the question-type specific tables
120 * @return boolean Success/Failure
121 * @param object $question The question being deleted
123 function delete_question($questionid) {
124 delete_records("question_truefalse", "question", $questionid);
125 return true;
128 function get_correct_responses(&$question, &$state) {
129 // The correct answer is the one which gives full marks
130 foreach ($question->options->answers as $answer) {
131 if (((int) $answer->fraction) === 1) {
132 return array('' => $answer->id);
135 return null;
139 * Prints the main content of the question including any interactions
141 function print_question_formulation_and_controls(&$question, &$state,
142 $cmoptions, $options) {
143 global $CFG;
145 $readonly = $options->readonly ? ' disabled="disabled"' : '';
147 $formatoptions = new stdClass;
148 $formatoptions->noclean = true;
149 $formatoptions->para = false;
151 // Print question formulation
152 $questiontext = format_text($question->questiontext,
153 $question->questiontextformat,
154 $formatoptions, $cmoptions->course);
155 $image = get_question_image($question);
157 $answers = &$question->options->answers;
158 $trueanswer = &$answers[$question->options->trueanswer];
159 $falseanswer = &$answers[$question->options->falseanswer];
160 $correctanswer = ($trueanswer->fraction == 1) ? $trueanswer : $falseanswer;
162 $trueclass = '';
163 $falseclass = '';
164 $truefeedbackimg = '';
165 $falsefeedbackimg = '';
167 // Work out which radio button to select (if any)
168 if (isset($state->responses[''])) {
169 $response = $state->responses[''];
170 } else {
171 $response = '';
173 $truechecked = ($response == $trueanswer->id) ? ' checked="checked"' : '';
174 $falsechecked = ($response == $falseanswer->id) ? ' checked="checked"' : '';
176 // Work out visual feedback for answer correctness.
177 if ($options->feedback) {
178 if ($truechecked) {
179 $trueclass = question_get_feedback_class($trueanswer->fraction);
180 } else if ($falsechecked) {
181 $falseclass = question_get_feedback_class($falseanswer->fraction);
184 if ($options->feedback || $options->correct_responses) {
185 if (isset($answers[$response])) {
186 $truefeedbackimg = question_get_feedback_image($trueanswer->fraction, !empty($truechecked) && $options->feedback);
187 $falsefeedbackimg = question_get_feedback_image($falseanswer->fraction, !empty($falsechecked) && $options->feedback);
191 $inputname = ' name="'.$question->name_prefix.'" ';
192 $trueid = $question->name_prefix.'true';
193 $falseid = $question->name_prefix.'false';
195 $radiotrue = '<input type="radio"' . $truechecked . $readonly . $inputname
196 . 'id="'.$trueid . '" value="' . $trueanswer->id . '" alt="'
197 . s($trueanswer->answer) . '" /><label for="'.$trueid . '">'
198 . s($trueanswer->answer) . '</label>';
199 $radiofalse = '<input type="radio"' . $falsechecked . $readonly . $inputname
200 . 'id="'.$falseid . '" value="' . $falseanswer->id . '" alt="'
201 . s($falseanswer->answer) . '" /><label for="'.$falseid . '">'
202 . s($falseanswer->answer) . '</label>';
204 $feedback = '';
205 if ($options->feedback and isset($answers[$response])) {
206 $chosenanswer = $answers[$response];
207 $feedback = format_text($chosenanswer->feedback, true, $formatoptions, $cmoptions->course);
210 include("$CFG->dirroot/question/type/truefalse/display.html");
213 function grade_responses(&$question, &$state, $cmoptions) {
214 if (isset($state->responses['']) && isset($question->options->answers[$state->responses['']])) {
215 $state->raw_grade = $question->options->answers[$state->responses['']]->fraction * $question->maxgrade;
216 } else {
217 $state->raw_grade = 0;
219 // Only allow one attempt at the question
220 $state->penalty = 1 * $question->maxgrade;
222 // mark the state as graded
223 $state->event = ($state->event == QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
225 return true;
228 function response_summary($question, $state, $length=80) {
229 if (isset($question->options->answers[$state->answer])) {
230 $responses = $question->options->answers[$state->answer]->answer;
231 } else {
232 $responses = '';
234 return $responses;
237 function get_actual_response($question, $state) {
238 if (isset($question->options->answers[$state->responses['']])) {
239 $responses[] = $question->options->answers[$state->responses['']]->answer;
240 } else {
241 $responses[] = '';
243 return $responses;
246 /// BACKUP FUNCTIONS ////////////////////////////
249 * Backup the data in a truefalse question
251 * This is used in question/backuplib.php
253 function backup($bf,$preferences,$question,$level=6) {
255 $status = true;
257 $truefalses = get_records("question_truefalse","question",$question,"id");
258 //If there are truefalses
259 if ($truefalses) {
260 //Iterate over each truefalse
261 foreach ($truefalses as $truefalse) {
262 $status = fwrite ($bf,start_tag("TRUEFALSE",$level,true));
263 //Print truefalse contents
264 fwrite ($bf,full_tag("TRUEANSWER",$level+1,false,$truefalse->trueanswer));
265 fwrite ($bf,full_tag("FALSEANSWER",$level+1,false,$truefalse->falseanswer));
266 $status = fwrite ($bf,end_tag("TRUEFALSE",$level,true));
268 //Now print question_answers
269 $status = question_backup_answers($bf,$preferences,$question);
271 return $status;
274 /// RESTORE FUNCTIONS /////////////////
277 * Restores the data in the question
279 * This is used in question/restorelib.php
281 function restore($old_question_id,$new_question_id,$info,$restore) {
283 $status = true;
285 //Get the truefalse array
286 $truefalses = $info['#']['TRUEFALSE'];
288 //Iterate over truefalse
289 for($i = 0; $i < sizeof($truefalses); $i++) {
290 $tru_info = $truefalses[$i];
292 //Now, build the question_truefalse record structure
293 $truefalse = new stdClass;
294 $truefalse->question = $new_question_id;
295 $truefalse->trueanswer = backup_todb($tru_info['#']['TRUEANSWER']['0']['#']);
296 $truefalse->falseanswer = backup_todb($tru_info['#']['FALSEANSWER']['0']['#']);
298 ////We have to recode the trueanswer field
299 $answer = backup_getid($restore->backup_unique_code,"question_answers",$truefalse->trueanswer);
300 if ($answer) {
301 $truefalse->trueanswer = $answer->new_id;
304 ////We have to recode the falseanswer field
305 $answer = backup_getid($restore->backup_unique_code,"question_answers",$truefalse->falseanswer);
306 if ($answer) {
307 $truefalse->falseanswer = $answer->new_id;
310 //The structure is equal to the db, so insert the question_truefalse
311 $newid = insert_record ("question_truefalse", $truefalse);
313 //Do some output
314 if (($i+1) % 50 == 0) {
315 if (!defined('RESTORE_SILENTLY')) {
316 echo ".";
317 if (($i+1) % 1000 == 0) {
318 echo "<br />";
321 backup_flush(300);
324 if (!$newid) {
325 $status = false;
329 return $status;
332 function restore_recode_answer($state, $restore) {
333 $answer = backup_getid($restore->backup_unique_code,"question_answers",$state->answer);
334 if ($answer) {
335 return $answer->new_id;
336 } else {
337 echo 'Could not recode truefalse answer id '.$state->answer.' for state '.$state->oldid.'<br />';
339 return '';
343 //// END OF CLASS ////
345 //////////////////////////////////////////////////////////////////////////
346 //// INITIATION - Without this line the question type is not in use... ///
347 //////////////////////////////////////////////////////////////////////////
348 question_register_questiontype(new question_truefalse_qtype());