|
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 require_once($CFG->libdir . '/questionlib.php'); 00030 require_once($CFG->dirroot . '/question/engine/lib.php'); 00031 00032 00039 class qtype_match extends question_type { 00040 00041 public function get_question_options($question) { 00042 global $DB; 00043 parent::get_question_options($question); 00044 $question->options = $DB->get_record('question_match', array('question' => $question->id)); 00045 $question->options->subquestions = $DB->get_records('question_match_sub', 00046 array('question' => $question->id), 'id ASC'); 00047 return true; 00048 } 00049 00050 public function save_question_options($question) { 00051 global $DB; 00052 $context = $question->context; 00053 $result = new stdClass(); 00054 00055 $oldsubquestions = $DB->get_records('question_match_sub', 00056 array('question' => $question->id), 'id ASC'); 00057 00058 // $subquestions will be an array with subquestion ids 00059 $subquestions = array(); 00060 00061 // Insert all the new question+answer pairs 00062 foreach ($question->subquestions as $key => $questiontext) { 00063 if ($questiontext['text'] == '' && trim($question->subanswers[$key]) == '') { 00064 continue; 00065 } 00066 if ($questiontext['text'] != '' && trim($question->subanswers[$key]) == '') { 00067 $result->notice = get_string('nomatchinganswer', 'qtype_match', $questiontext); 00068 } 00069 00070 // Update an existing subquestion if possible. 00071 $subquestion = array_shift($oldsubquestions); 00072 if (!$subquestion) { 00073 $subquestion = new stdClass(); 00074 // Determine a unique random code 00075 $subquestion->code = rand(1, 999999999); 00076 while ($DB->record_exists('question_match_sub', 00077 array('code' => $subquestion->code, 'question' => $question->id))) { 00078 $subquestion->code = rand(1, 999999999); 00079 } 00080 $subquestion->question = $question->id; 00081 $subquestion->questiontext = ''; 00082 $subquestion->answertext = ''; 00083 $subquestion->id = $DB->insert_record('question_match_sub', $subquestion); 00084 } 00085 00086 $subquestion->questiontext = $this->import_or_save_files($questiontext, 00087 $context, 'qtype_match', 'subquestion', $subquestion->id); 00088 $subquestion->questiontextformat = $questiontext['format']; 00089 $subquestion->answertext = trim($question->subanswers[$key]); 00090 00091 $DB->update_record('question_match_sub', $subquestion); 00092 00093 $subquestions[] = $subquestion->id; 00094 } 00095 00096 // Delete old subquestions records 00097 $fs = get_file_storage(); 00098 foreach ($oldsubquestions as $oldsub) { 00099 $fs->delete_area_files($context->id, 'qtype_match', 'subquestion', $oldsub->id); 00100 $DB->delete_records('question_match_sub', array('id' => $oldsub->id)); 00101 } 00102 00103 // Save the question options. 00104 $options = $DB->get_record('question_match', array('question' => $question->id)); 00105 if (!$options) { 00106 $options = new stdClass(); 00107 $options->question = $question->id; 00108 $options->correctfeedback = ''; 00109 $options->partiallycorrectfeedback = ''; 00110 $options->incorrectfeedback = ''; 00111 $options->id = $DB->insert_record('question_match', $options); 00112 } 00113 00114 $options->subquestions = implode(',', $subquestions); 00115 $options->shuffleanswers = $question->shuffleanswers; 00116 $options = $this->save_combined_feedback_helper($options, $question, $context, true); 00117 $DB->update_record('question_match', $options); 00118 00119 $this->save_hints($question, true); 00120 00121 if (!empty($result->notice)) { 00122 return $result; 00123 } 00124 00125 if (count($subquestions) < 3) { 00126 $result->notice = get_string('notenoughanswers', 'question', 3); 00127 return $result; 00128 } 00129 00130 return true; 00131 } 00132 00133 protected function initialise_question_instance(question_definition $question, $questiondata) { 00134 parent::initialise_question_instance($question, $questiondata); 00135 00136 $question->shufflestems = $questiondata->options->shuffleanswers; 00137 $this->initialise_combined_feedback($question, $questiondata, true); 00138 00139 $question->stems = array(); 00140 $question->choices = array(); 00141 $question->right = array(); 00142 00143 foreach ($questiondata->options->subquestions as $matchsub) { 00144 $ans = $matchsub->answertext; 00145 $key = array_search($matchsub->answertext, $question->choices); 00146 if ($key === false) { 00147 $key = $matchsub->id; 00148 $question->choices[$key] = $matchsub->answertext; 00149 } 00150 00151 if ($matchsub->questiontext !== '') { 00152 $question->stems[$matchsub->id] = $matchsub->questiontext; 00153 $question->stemformat[$matchsub->id] = $matchsub->questiontextformat; 00154 $question->right[$matchsub->id] = $key; 00155 } 00156 } 00157 } 00158 00159 protected function make_hint($hint) { 00160 return question_hint_with_parts::load_from_record($hint); 00161 } 00162 00163 public function delete_question($questionid, $contextid) { 00164 global $DB; 00165 $DB->delete_records('question_match', array('question' => $questionid)); 00166 $DB->delete_records('question_match_sub', array('question' => $questionid)); 00167 00168 parent::delete_question($questionid, $contextid); 00169 } 00170 00171 public function get_random_guess_score($questiondata) { 00172 $q = $this->make_question($questiondata); 00173 return 1 / count($q->choices); 00174 } 00175 00176 public function get_possible_responses($questiondata) { 00177 $subqs = array(); 00178 00179 $q = $this->make_question($questiondata); 00180 00181 foreach ($q->stems as $stemid => $stem) { 00182 00183 $responses = array(); 00184 foreach ($q->choices as $choiceid => $choice) { 00185 $responses[$choiceid] = new question_possible_response( 00186 $q->html_to_text($stem, $q->stemformat[$stemid]) . ': ' . $choice, 00187 ($choiceid == $q->right[$stemid]) / count($q->stems)); 00188 } 00189 $responses[null] = question_possible_response::no_response(); 00190 00191 $subqs[$stemid] = $responses; 00192 } 00193 00194 return $subqs; 00195 } 00196 00197 public function move_files($questionid, $oldcontextid, $newcontextid) { 00198 global $DB; 00199 $fs = get_file_storage(); 00200 00201 parent::move_files($questionid, $oldcontextid, $newcontextid); 00202 00203 $subquestionids = $DB->get_records_menu('question_match_sub', 00204 array('question' => $questionid), 'id', 'id,1'); 00205 foreach ($subquestionids as $subquestionid => $notused) { 00206 $fs->move_area_files_to_new_context($oldcontextid, 00207 $newcontextid, 'qtype_match', 'subquestion', $subquestionid); 00208 } 00209 00210 $this->move_files_in_combined_feedback($questionid, $oldcontextid, $newcontextid); 00211 } 00212 00213 protected function delete_files($questionid, $contextid) { 00214 global $DB; 00215 $fs = get_file_storage(); 00216 00217 parent::delete_files($questionid, $contextid); 00218 00219 $subquestionids = $DB->get_records_menu('question_match_sub', 00220 array('question' => $questionid), 'id', 'id,1'); 00221 foreach ($subquestionids as $subquestionid => $notused) { 00222 $fs->delete_area_files($contextid, 'qtype_match', 'subquestion', $subquestionid); 00223 } 00224 00225 $this->delete_files_in_combined_feedback($questionid, $contextid); 00226 } 00227 }