|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00027 defined('MOODLE_INTERNAL') || die(); 00028 00029 00036 class qtype_multichoice extends question_type { 00037 public function get_question_options($question) { 00038 global $DB, $OUTPUT; 00039 $question->options = $DB->get_record('question_multichoice', 00040 array('question' => $question->id), '*', MUST_EXIST); 00041 parent::get_question_options($question); 00042 } 00043 00044 public function save_question_options($question) { 00045 global $DB; 00046 $context = $question->context; 00047 $result = new stdClass(); 00048 00049 $oldanswers = $DB->get_records('question_answers', 00050 array('question' => $question->id), 'id ASC'); 00051 00052 // following hack to check at least two answers exist 00053 $answercount = 0; 00054 foreach ($question->answer as $key => $answer) { 00055 if ($answer != '') { 00056 $answercount++; 00057 } 00058 } 00059 if ($answercount < 2) { // check there are at lest 2 answers for multiple choice 00060 $result->notice = get_string('notenoughanswers', 'qtype_multichoice', '2'); 00061 return $result; 00062 } 00063 00064 // Insert all the new answers 00065 $totalfraction = 0; 00066 $maxfraction = -1; 00067 $answers = array(); 00068 foreach ($question->answer as $key => $answerdata) { 00069 if (trim($answerdata['text']) == '') { 00070 continue; 00071 } 00072 00073 // Update an existing answer if possible. 00074 $answer = array_shift($oldanswers); 00075 if (!$answer) { 00076 $answer = new stdClass(); 00077 $answer->question = $question->id; 00078 $answer->answer = ''; 00079 $answer->feedback = ''; 00080 $answer->id = $DB->insert_record('question_answers', $answer); 00081 } 00082 00083 // Doing an import 00084 $answer->answer = $this->import_or_save_files($answerdata, 00085 $context, 'question', 'answer', $answer->id); 00086 $answer->answerformat = $answerdata['format']; 00087 $answer->fraction = $question->fraction[$key]; 00088 $answer->feedback = $this->import_or_save_files($question->feedback[$key], 00089 $context, 'question', 'answerfeedback', $answer->id); 00090 $answer->feedbackformat = $question->feedback[$key]['format']; 00091 00092 $DB->update_record('question_answers', $answer); 00093 $answers[] = $answer->id; 00094 00095 if ($question->fraction[$key] > 0) { 00096 $totalfraction += $question->fraction[$key]; 00097 } 00098 if ($question->fraction[$key] > $maxfraction) { 00099 $maxfraction = $question->fraction[$key]; 00100 } 00101 } 00102 00103 // Delete any left over old answer records. 00104 $fs = get_file_storage(); 00105 foreach ($oldanswers as $oldanswer) { 00106 $fs->delete_area_files($context->id, 'question', 'answerfeedback', $oldanswer->id); 00107 $DB->delete_records('question_answers', array('id' => $oldanswer->id)); 00108 } 00109 00110 $options = $DB->get_record('question_multichoice', array('question' => $question->id)); 00111 if (!$options) { 00112 $options = new stdClass(); 00113 $options->question = $question->id; 00114 $options->correctfeedback = ''; 00115 $options->partiallycorrectfeedback = ''; 00116 $options->incorrectfeedback = ''; 00117 $options->id = $DB->insert_record('question_multichoice', $options); 00118 } 00119 00120 $options->answers = implode(',', $answers); 00121 $options->single = $question->single; 00122 if (isset($question->layout)) { 00123 $options->layout = $question->layout; 00124 } 00125 $options->answernumbering = $question->answernumbering; 00126 $options->shuffleanswers = $question->shuffleanswers; 00127 $options = $this->save_combined_feedback_helper($options, $question, $context, true); 00128 $DB->update_record('question_multichoice', $options); 00129 00130 $this->save_hints($question, true); 00131 00132 // Perform sanity checks on fractional grades 00133 if ($options->single) { 00134 if ($maxfraction != 1) { 00135 $result->noticeyesno = get_string('fractionsnomax', 'qtype_multichoice', 00136 $maxfraction * 100); 00137 return $result; 00138 } 00139 } else { 00140 $totalfraction = round($totalfraction, 2); 00141 if ($totalfraction != 1) { 00142 $result->noticeyesno = get_string('fractionsaddwrong', 'qtype_multichoice', 00143 $totalfraction * 100); 00144 return $result; 00145 } 00146 } 00147 } 00148 00149 protected function make_question_instance($questiondata) { 00150 question_bank::load_question_definition_classes($this->name()); 00151 if ($questiondata->options->single) { 00152 $class = 'qtype_multichoice_single_question'; 00153 } else { 00154 $class = 'qtype_multichoice_multi_question'; 00155 } 00156 return new $class(); 00157 } 00158 00159 protected function make_hint($hint) { 00160 return question_hint_with_parts::load_from_record($hint); 00161 } 00162 00163 protected function initialise_question_instance(question_definition $question, $questiondata) { 00164 parent::initialise_question_instance($question, $questiondata); 00165 $question->shuffleanswers = $questiondata->options->shuffleanswers; 00166 $question->answernumbering = $questiondata->options->answernumbering; 00167 if (!empty($questiondata->options->layout)) { 00168 $question->layout = $questiondata->options->layout; 00169 } else { 00170 $question->layout = qtype_multichoice_single_question::LAYOUT_VERTICAL; 00171 } 00172 $this->initialise_combined_feedback($question, $questiondata, true); 00173 00174 $this->initialise_question_answers($question, $questiondata, false); 00175 } 00176 00177 public function delete_question($questionid, $contextid) { 00178 global $DB; 00179 $DB->delete_records('question_multichoice', array('question' => $questionid)); 00180 00181 parent::delete_question($questionid, $contextid); 00182 } 00183 00184 public function get_random_guess_score($questiondata) { 00185 if (!$questiondata->options->single) { 00186 // Pretty much impossible to compute for _multi questions. Don't try. 00187 return null; 00188 } 00189 00190 // Single choice questions - average choice fraction. 00191 $totalfraction = 0; 00192 foreach ($questiondata->options->answers as $answer) { 00193 $totalfraction += $answer->fraction; 00194 } 00195 return $totalfraction / count($questiondata->options->answers); 00196 } 00197 00198 public function get_possible_responses($questiondata) { 00199 if ($questiondata->options->single) { 00200 $responses = array(); 00201 00202 foreach ($questiondata->options->answers as $aid => $answer) { 00203 $responses[$aid] = new question_possible_response(html_to_text(format_text( 00204 $answer->answer, $answer->answerformat, array('noclean' => true)), 00205 0, false), $answer->fraction); 00206 } 00207 00208 $responses[null] = question_possible_response::no_response(); 00209 return array($questiondata->id => $responses); 00210 } else { 00211 $parts = array(); 00212 00213 foreach ($questiondata->options->answers as $aid => $answer) { 00214 $parts[$aid] = array($aid => 00215 new question_possible_response(html_to_text(format_text( 00216 $answer->answer, $answer->answerformat, array('noclean' => true)), 00217 0, false), $answer->fraction)); 00218 } 00219 00220 return $parts; 00221 } 00222 } 00223 00230 public static function get_numbering_styles() { 00231 $styles = array(); 00232 foreach (array('abc', 'ABCD', '123', 'iii', 'IIII', 'none') as $numberingoption) { 00233 $styles[$numberingoption] = 00234 get_string('answernumbering' . $numberingoption, 'qtype_multichoice'); 00235 } 00236 return $styles; 00237 } 00238 00239 public function move_files($questionid, $oldcontextid, $newcontextid) { 00240 parent::move_files($questionid, $oldcontextid, $newcontextid); 00241 $this->move_files_in_answers($questionid, $oldcontextid, $newcontextid, true); 00242 $this->move_files_in_combined_feedback($questionid, $oldcontextid, $newcontextid); 00243 } 00244 00245 protected function delete_files($questionid, $contextid) { 00246 parent::delete_files($questionid, $contextid); 00247 $this->delete_files_in_answers($questionid, $contextid, true); 00248 $this->delete_files_in_combined_feedback($questionid, $contextid); 00249 } 00250 }