Commit | Line | Data |
---|---|---|
aeb15530 | 1 | <?php |
d3603157 TH |
2 | // This file is part of Moodle - http://moodle.org/ |
3 | // | |
4 | // Moodle is free software: you can redistribute it and/or modify | |
5 | // it under the terms of the GNU General Public License as published by | |
6 | // the Free Software Foundation, either version 3 of the License, or | |
7 | // (at your option) any later version. | |
8 | // | |
9 | // Moodle is distributed in the hope that it will be useful, | |
10 | // but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
12 | // GNU General Public License for more details. | |
13 | // | |
14 | // You should have received a copy of the GNU General Public License | |
15 | // along with Moodle. If not, see <http://www.gnu.org/licenses/>. | |
b81d2dbe | 16 | |
41a89a07 | 17 | /** |
d3603157 TH |
18 | * Blackboard question importer. |
19 | * | |
8a8dd7d8 | 20 | * @package qformat_blackboard |
d3603157 TH |
21 | * @copyright 2003 Scott Elliott |
22 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
41a89a07 | 23 | */ |
84769fd8 | 24 | |
d3603157 | 25 | |
a17b297d TH |
26 | defined('MOODLE_INTERNAL') || die(); |
27 | ||
8a8dd7d8 | 28 | require_once($CFG->libdir . '/xmlize.php'); |
d3603157 TH |
29 | |
30 | ||
31 | /** | |
32 | * Blackboard question importer. | |
33 | * | |
34 | * @copyright 2003 Scott Elliott | |
35 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
36 | */ | |
8a8dd7d8 JMV |
37 | class qformat_blackboard extends qformat_based_on_xml { |
38 | // Is the current question's question text escaped HTML (true for most if not all Blackboard files). | |
39 | public $ishtml = true; | |
40 | ||
84769fd8 | 41 | |
c7df5006 | 42 | public function provide_import() { |
84769fd8 | 43 | return true; |
44 | } | |
45 | ||
9832fde1 JMV |
46 | /** |
47 | * Check if the given file is capable of being imported by this plugin. | |
48 | * As {@link file_storage::mimetype()} now uses finfo PHP extension if available, | |
49 | * the value returned by $file->get_mimetype for a .dat file is not the same on all servers. | |
50 | * So if the parent method fails we must use mimeinfo on the filename. | |
51 | * @param stored_file $file the file to check | |
52 | * @return bool whether this plugin can import the file | |
53 | */ | |
54 | public function can_import_file($file) { | |
55 | return parent::can_import_file($file) || mimeinfo('type', $file->get_filename()) == $this->mime_type(); | |
56 | } | |
57 | ||
8a8dd7d8 JMV |
58 | public function mime_type() { |
59 | return mimeinfo('type', '.dat'); | |
60 | } | |
61 | ||
62 | /** | |
63 | * Some softwares put entities in exported files. | |
64 | * This method try to clean up known problems. | |
65 | * @param string str string to correct | |
66 | * @return string the corrected string | |
67 | */ | |
68 | public function cleaninput($str) { | |
69 | if (!$this->ishtml) { | |
70 | return $str; | |
71 | } | |
72 | $html_code_list = array( | |
73 | "'" => "'", | |
74 | "’" => "'", | |
75 | "[" => "[", | |
76 | "“" => "\"", | |
77 | "”" => "\"", | |
78 | "]" => "]", | |
79 | "'" => "'", | |
80 | "–" => "-", | |
81 | "—" => "-", | |
82 | ); | |
83 | $str = strtr($str, $html_code_list); | |
84 | // Use textlib entities_to_utf8 function to convert only numerical entities. | |
85 | $str = textlib::entities_to_utf8($str, false); | |
86 | return $str; | |
87 | } | |
84769fd8 | 88 | |
8a8dd7d8 JMV |
89 | /** |
90 | * Parse the array of lines into an array of questions | |
91 | * this *could* burn memory - but it won't happen that much | |
92 | * so fingers crossed! | |
93 | * @param array of lines from the input file. | |
94 | * @param stdClass $context | |
95 | * @return array (of objects) question objects. | |
96 | */ | |
97 | protected function readquestions($lines) { | |
98 | ||
99 | $text = implode($lines, ' '); | |
100 | unset($lines); | |
101 | ||
102 | // This converts xml to big nasty data structure, | |
103 | // the 0 means keep white space as it is. | |
104 | try { | |
105 | $xml = xmlize($text, 0, 'UTF-8', true); | |
106 | } catch (xml_format_exception $e) { | |
107 | $this->error($e->getMessage(), ''); | |
108 | return false; | |
109 | } | |
84769fd8 | 110 | |
c7df5006 | 111 | $questions = array(); |
84769fd8 | 112 | |
c7df5006 TH |
113 | $this->process_tf($xml, $questions); |
114 | $this->process_mc($xml, $questions); | |
115 | $this->process_ma($xml, $questions); | |
116 | $this->process_fib($xml, $questions); | |
117 | $this->process_matching($xml, $questions); | |
118 | $this->process_essay($xml, $questions); | |
84769fd8 | 119 | |
c7df5006 TH |
120 | return $questions; |
121 | } | |
84769fd8 | 122 | |
8a8dd7d8 JMV |
123 | /** |
124 | * Do question import processing common to every qtype. | |
125 | * @param array $questiondata the xml tree related to the current question | |
126 | * @return object initialized question object. | |
127 | */ | |
128 | public function process_common($questiondata) { | |
129 | global $CFG; | |
130 | ||
131 | // This routine initialises the question object. | |
132 | $question = $this->defaultquestion(); | |
133 | ||
134 | // Determine if the question is already escaped html. | |
135 | $this->ishtml = $this->getpath($questiondata, | |
136 | array('#', 'BODY', 0, '#', 'FLAGS', 0, '#', 'ISHTML', 0, '@', 'value'), | |
137 | false, false); | |
138 | ||
139 | // Put questiontext in question object. | |
140 | $text = $this->getpath($questiondata, | |
141 | array('#', 'BODY', 0, '#', 'TEXT', 0, '#'), | |
142 | '', true, get_string('importnotext', 'qformat_blackboard')); | |
143 | ||
144 | if ($this->ishtml) { | |
145 | $question->questiontext = $this->cleaninput($text); | |
146 | $question->questiontextformat = FORMAT_HTML; | |
147 | $question->questiontextfiles = array(); | |
148 | ||
149 | } else { | |
150 | $question->questiontext = $text; | |
c7df5006 | 151 | } |
8a8dd7d8 JMV |
152 | // Put name in question object. We must ensure it is not empty and it is less than 250 chars. |
153 | $question->name = shorten_text(strip_tags($question->questiontext), 200); | |
154 | $question->name = substr($question->name, 0, 250); | |
155 | if (!$question->name) { | |
156 | $id = $this->getpath($questiondata, | |
157 | array('@', 'id'), '', true); | |
158 | $question->name = get_string('defaultname', 'qformat_blackboard' , $id); | |
c7df5006 | 159 | } |
aeb15530 | 160 | |
8a8dd7d8 JMV |
161 | $question->generalfeedback = ''; |
162 | $question->generalfeedbackformat = FORMAT_HTML; | |
163 | $question->generalfeedbackfiles = array(); | |
aeb15530 | 164 | |
8a8dd7d8 JMV |
165 | // TODO : read the mark from the POOL TITLE QUESTIONLIST section. |
166 | $question->defaultmark = 1; | |
167 | return $question; | |
168 | } | |
169 | ||
170 | /** | |
171 | * Process Essay Questions | |
172 | * @param array xml the xml tree | |
173 | * @param array questions the questions already parsed | |
174 | */ | |
175 | public function process_essay($xml, &$questions) { | |
176 | ||
177 | if ($this->getpath($xml, array('POOL', '#', 'QUESTION_ESSAY'), false, false)) { | |
178 | $essayquestions = $this->getpath($xml, | |
179 | array('POOL', '#', 'QUESTION_ESSAY'), false, false); | |
180 | } else { | |
181 | return; | |
182 | } | |
aeb15530 | 183 | |
8a8dd7d8 | 184 | foreach ($essayquestions as $thisquestion) { |
b81d2dbe | 185 | |
8a8dd7d8 | 186 | $question = $this->process_common($thisquestion); |
aeb15530 | 187 | |
8a8dd7d8 | 188 | $question->qtype = 'essay'; |
aeb15530 | 189 | |
c7df5006 | 190 | $question->answer = ''; |
8a8dd7d8 JMV |
191 | $answer = $this->getpath($thisquestion, |
192 | array('#', 'ANSWER', 0, '#', 'TEXT', 0, '#'), '', true); | |
193 | $question->graderinfo = $this->text_field($this->cleaninput($answer)); | |
c7df5006 | 194 | $question->feedback = ''; |
8a8dd7d8 JMV |
195 | $question->responseformat = 'editor'; |
196 | $question->responsefieldlines = 15; | |
197 | $question->attachments = 0; | |
c7df5006 | 198 | $question->fraction = 0; |
b81d2dbe | 199 | |
c7df5006 TH |
200 | $questions[] = $question; |
201 | } | |
eaaf06f1 | 202 | } |
84769fd8 | 203 | |
8a8dd7d8 JMV |
204 | /** |
205 | * Process True / False Questions | |
206 | * @param array xml the xml tree | |
207 | * @param array questions the questions already parsed | |
208 | */ | |
209 | public function process_tf($xml, &$questions) { | |
210 | ||
211 | if ($this->getpath($xml, array('POOL', '#', 'QUESTION_TRUEFALSE'), false, false)) { | |
212 | $tfquestions = $this->getpath($xml, | |
213 | array('POOL', '#', 'QUESTION_TRUEFALSE'), false, false); | |
214 | } else { | |
c7df5006 TH |
215 | return; |
216 | } | |
84769fd8 | 217 | |
8a8dd7d8 | 218 | foreach ($tfquestions as $thisquestion) { |
2e15284e | 219 | |
8a8dd7d8 | 220 | $question = $this->process_common($thisquestion); |
2e15284e | 221 | |
8a8dd7d8 JMV |
222 | $question->qtype = 'truefalse'; |
223 | $question->single = 1; // Only one answer is allowed. | |
84769fd8 | 224 | |
8a8dd7d8 | 225 | $choices = $this->getpath($thisquestion, array('#', 'ANSWER'), array(), false); |
84769fd8 | 226 | |
8a8dd7d8 JMV |
227 | $correct_answer = $this->getpath($thisquestion, |
228 | array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER', 0, '@', 'answer_id'), | |
229 | '', true); | |
84769fd8 | 230 | |
8a8dd7d8 JMV |
231 | // First choice is true, second is false. |
232 | $id = $this->getpath($choices[0], array('@', 'id'), '', true); | |
233 | $correctfeedback = $this->getpath($thisquestion, | |
234 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'), | |
235 | '', true); | |
236 | $incorrectfeedback = $this->getpath($thisquestion, | |
237 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'), | |
238 | '', true); | |
239 | if (strcmp($id, $correct_answer) == 0) { // True is correct. | |
c7df5006 | 240 | $question->answer = 1; |
8a8dd7d8 JMV |
241 | $question->feedbacktrue = $this->text_field($this->cleaninput($correctfeedback)); |
242 | $question->feedbackfalse = $this->text_field($this->cleaninput($incorrectfeedback)); | |
243 | } else { // False is correct. | |
c7df5006 | 244 | $question->answer = 0; |
8a8dd7d8 JMV |
245 | $question->feedbacktrue = $this->text_field($this->cleaninput($incorrectfeedback)); |
246 | $question->feedbackfalse = $this->text_field($this->cleaninput($correctfeedback)); | |
c7df5006 TH |
247 | } |
248 | $question->correctanswer = $question->answer; | |
249 | $questions[] = $question; | |
8a8dd7d8 | 250 | } |
eaaf06f1 | 251 | } |
84769fd8 | 252 | |
8a8dd7d8 JMV |
253 | /** |
254 | * Process Multiple Choice Questions with single answer | |
255 | * @param array xml the xml tree | |
256 | * @param array questions the questions already parsed | |
257 | */ | |
258 | public function process_mc($xml, &$questions) { | |
259 | ||
260 | if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MULTIPLECHOICE'), false, false)) { | |
261 | $mcquestions = $this->getpath($xml, | |
262 | array('POOL', '#', 'QUESTION_MULTIPLECHOICE'), false, false); | |
263 | } else { | |
c7df5006 TH |
264 | return; |
265 | } | |
84769fd8 | 266 | |
8a8dd7d8 JMV |
267 | foreach ($mcquestions as $thisquestion) { |
268 | ||
269 | $question = $this->process_common($thisquestion); | |
270 | ||
271 | $correctfeedback = $this->getpath($thisquestion, | |
272 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'), | |
273 | '', true); | |
274 | $incorrectfeedback = $this->getpath($thisquestion, | |
275 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'), | |
276 | '', true); | |
277 | $question->correctfeedback = $this->text_field($this->cleaninput($correctfeedback)); | |
278 | $question->partiallycorrectfeedback = $this->text_field(''); | |
279 | $question->incorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback)); | |
280 | ||
281 | $question->qtype = 'multichoice'; | |
282 | $question->single = 1; // Only one answer is allowed. | |
283 | ||
284 | $choices = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false); | |
285 | $correct_answer_id = $this->getpath($thisquestion, | |
286 | array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER', 0, '@', 'answer_id'), | |
287 | '', true); | |
288 | foreach ($choices as $choice) { | |
289 | $choicetext = $this->getpath($choice, array('#', 'TEXT', 0, '#'), '', true); | |
290 | // Put this choice in the question object. | |
291 | $question->answer[] = $this->text_field($this->cleaninput($choicetext)); | |
292 | ||
293 | $choice_id = $this->getpath($choice, array('@', 'id'), '', true); | |
294 | // If choice is the right answer, give 100% mark, otherwise give 0%. | |
295 | if (strcmp ($choice_id, $correct_answer_id) == 0) { | |
296 | $question->fraction[] = 1; | |
c7df5006 | 297 | } else { |
8a8dd7d8 | 298 | $question->fraction[] = 0; |
2e15284e | 299 | } |
8a8dd7d8 JMV |
300 | // There is never feedback specific to each choice. |
301 | $question->feedback[] = $this->text_field(''); | |
84769fd8 | 302 | } |
c7df5006 | 303 | $questions[] = $question; |
84769fd8 | 304 | } |
84769fd8 | 305 | } |
84769fd8 | 306 | |
8a8dd7d8 JMV |
307 | /** |
308 | * Process Multiple Choice Questions With Multiple Answers | |
309 | * @param array xml the xml tree | |
310 | * @param array questions the questions already parsed | |
311 | */ | |
312 | public function process_ma($xml, &$questions) { | |
313 | if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MULTIPLEANSWER'), false, false)) { | |
314 | $maquestions = $this->getpath($xml, | |
315 | array('POOL', '#', 'QUESTION_MULTIPLEANSWER'), false, false); | |
316 | } else { | |
c7df5006 TH |
317 | return; |
318 | } | |
84769fd8 | 319 | |
8a8dd7d8 JMV |
320 | foreach ($maquestions as $thisquestion) { |
321 | $question = $this->process_common($thisquestion); | |
322 | ||
323 | $correctfeedback = $this->getpath($thisquestion, | |
324 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'), | |
325 | '', true); | |
326 | $incorrectfeedback = $this->getpath($thisquestion, | |
327 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'), | |
328 | '', true); | |
329 | $question->correctfeedback = $this->text_field($this->cleaninput($correctfeedback)); | |
330 | // As there is no partially correct feedback we use incorrect one. | |
331 | $question->partiallycorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback)); | |
332 | $question->incorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback)); | |
333 | ||
334 | $question->qtype = 'multichoice'; | |
c7df5006 | 335 | $question->defaultmark = 1; |
8a8dd7d8 JMV |
336 | $question->single = 0; // More than one answers allowed. |
337 | ||
338 | $choices = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false); | |
339 | $correct_answer_ids = array(); | |
340 | foreach ($this->getpath($thisquestion, | |
341 | array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER'), false, false) as $correctanswer) { | |
342 | if ($correctanswer) { | |
343 | $correct_answer_ids[] = $this->getpath($correctanswer, | |
344 | array('@', 'answer_id'), | |
345 | '', true); | |
346 | } | |
c7df5006 | 347 | } |
8a8dd7d8 | 348 | $fraction = 1/count($correct_answer_ids); |
84769fd8 | 349 | |
8a8dd7d8 JMV |
350 | foreach ($choices as $choice) { |
351 | $choicetext = $this->getpath($choice, array('#', 'TEXT', 0, '#'), '', true); | |
352 | // Put this choice in the question object. | |
353 | $question->answer[] = $this->text_field($this->cleaninput($choicetext)); | |
84769fd8 | 354 | |
8a8dd7d8 | 355 | $choice_id = $this->getpath($choice, array('@', 'id'), '', true); |
84769fd8 | 356 | |
8a8dd7d8 | 357 | $iscorrect = in_array($choice_id, $correct_answer_ids); |
84769fd8 | 358 | |
c7df5006 | 359 | if ($iscorrect) { |
8a8dd7d8 | 360 | $question->fraction[] = $fraction; |
c7df5006 | 361 | } else { |
8a8dd7d8 | 362 | $question->fraction[] = 0; |
c7df5006 | 363 | } |
8a8dd7d8 JMV |
364 | // There is never feedback specific to each choice. |
365 | $question->feedback[] = $this->text_field(''); | |
84769fd8 | 366 | } |
c7df5006 TH |
367 | $questions[] = $question; |
368 | } | |
84769fd8 | 369 | } |
84769fd8 | 370 | |
8a8dd7d8 JMV |
371 | /** |
372 | * Process Fill in the Blank Questions | |
373 | * @param array xml the xml tree | |
374 | * @param array questions the questions already parsed | |
375 | */ | |
376 | public function process_fib($xml, &$questions) { | |
377 | if ($this->getpath($xml, array('POOL', '#', 'QUESTION_FILLINBLANK'), false, false)) { | |
378 | $fibquestions = $this->getpath($xml, | |
379 | array('POOL', '#', 'QUESTION_FILLINBLANK'), false, false); | |
380 | } else { | |
c7df5006 TH |
381 | return; |
382 | } | |
84769fd8 | 383 | |
8a8dd7d8 JMV |
384 | foreach ($fibquestions as $thisquestion) { |
385 | ||
386 | $question = $this->process_common($thisquestion); | |
387 | ||
388 | $question->qtype = 'shortanswer'; | |
389 | $question->usecase = 0; // Ignore case. | |
390 | ||
391 | $correctfeedback = $this->getpath($thisquestion, | |
392 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'), | |
393 | '', true); | |
394 | $incorrectfeedback = $this->getpath($thisquestion, | |
395 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'), | |
396 | '', true); | |
397 | $answers = $this->getpath($thisquestion, array('#', 'ANSWER'), false, false); | |
398 | foreach ($answers as $answer) { | |
399 | $question->answer[] = $this->getpath($answer, | |
400 | array('#', 'TEXT', 0, '#'), '', true); | |
401 | $question->fraction[] = 1; | |
402 | $question->feedback[] = $this->text_field($this->cleaninput($correctfeedback)); | |
c7df5006 | 403 | } |
8a8dd7d8 JMV |
404 | $question->answer[] = '*'; |
405 | $question->fraction[] = 0; | |
406 | $question->feedback[] = $this->text_field($this->cleaninput($incorrectfeedback)); | |
aeb15530 | 407 | |
c7df5006 TH |
408 | $questions[] = $question; |
409 | } | |
53a4d39f | 410 | } |
84769fd8 | 411 | |
8a8dd7d8 JMV |
412 | /** |
413 | * Process Matching Questions | |
414 | * @param array xml the xml tree | |
415 | * @param array questions the questions already parsed | |
416 | */ | |
417 | public function process_matching($xml, &$questions) { | |
418 | if ($this->getpath($xml, array('POOL', '#', 'QUESTION_MATCH'), false, false)) { | |
419 | $matchquestions = $this->getpath($xml, | |
420 | array('POOL', '#', 'QUESTION_MATCH'), false, false); | |
421 | } else { | |
c7df5006 TH |
422 | return; |
423 | } | |
8a8dd7d8 JMV |
424 | // Blackboard questions can't be imported in core Moodle without a loss in data, |
425 | // as core match question don't allow HTML in subanswers. The contributed ddmatch | |
426 | // question type support HTML in subanswers. | |
427 | // The ddmatch question type is not part of core, so we need to check if it is defined. | |
428 | $ddmatch_is_installed = question_bank::is_qtype_installed('ddmatch'); | |
429 | ||
430 | foreach ($matchquestions as $thisquestion) { | |
431 | ||
432 | $question = $this->process_common($thisquestion); | |
433 | if ($ddmatch_is_installed) { | |
434 | $question->qtype = 'ddmatch'; | |
435 | } else { | |
436 | $question->qtype = 'match'; | |
c7df5006 | 437 | } |
84769fd8 | 438 | |
8a8dd7d8 JMV |
439 | $correctfeedback = $this->getpath($thisquestion, |
440 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_CORRECT', 0, '#'), | |
441 | '', true); | |
442 | $incorrectfeedback = $this->getpath($thisquestion, | |
443 | array('#', 'GRADABLE', 0, '#', 'FEEDBACK_WHEN_INCORRECT', 0, '#'), | |
444 | '', true); | |
445 | $question->correctfeedback = $this->text_field($this->cleaninput($correctfeedback)); | |
446 | // As there is no partially correct feedback we use incorrect one. | |
447 | $question->partiallycorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback)); | |
448 | $question->incorrectfeedback = $this->text_field($this->cleaninput($incorrectfeedback)); | |
449 | ||
450 | $choices = $this->getpath($thisquestion, | |
451 | array('#', 'CHOICE'), false, false); // Blackboard "choices" are Moodle subanswers. | |
452 | $answers = $this->getpath($thisquestion, | |
453 | array('#', 'ANSWER'), false, false); // Blackboard "answers" are Moodle subquestions. | |
454 | $correctanswers = $this->getpath($thisquestion, | |
455 | array('#', 'GRADABLE', 0, '#', 'CORRECTANSWER'), false, false); // Mapping between choices and answers. | |
456 | $mappings = array(); | |
457 | foreach ($correctanswers as $correctanswer) { | |
458 | if ($correctanswer) { | |
459 | $correct_choice_id = $this->getpath($correctanswer, | |
460 | array('@', 'choice_id'), '', true); | |
461 | $correct_answer_id = $this->getpath($correctanswer, | |
462 | array('@', 'answer_id'), | |
463 | '', true); | |
464 | $mappings[$correct_answer_id] = $correct_choice_id; | |
465 | } | |
466 | } | |
84769fd8 | 467 | |
8a8dd7d8 JMV |
468 | foreach ($choices as $choice) { |
469 | if ($ddmatch_is_installed) { | |
470 | $choicetext = $this->text_field($this->cleaninput($this->getpath($choice, | |
471 | array('#', 'TEXT', 0, '#'), '', true))); | |
472 | } else { | |
473 | $choicetext = trim(strip_tags($this->getpath($choice, | |
474 | array('#', 'TEXT', 0, '#'), '', true))); | |
475 | } | |
84769fd8 | 476 | |
8a8dd7d8 JMV |
477 | if ($choicetext != '') { // Only import non empty subanswers. |
478 | $subquestion = ''; | |
479 | $choice_id = $this->getpath($choice, | |
480 | array('@', 'id'), '', true); | |
481 | $fiber = array_search($choice_id, $mappings); | |
482 | $fiber = array_keys ($mappings, $choice_id); | |
483 | foreach ($fiber as $correct_answer_id) { | |
484 | // We have found a correspondance for this choice so we need to take the associated answer. | |
485 | foreach ($answers as $answer) { | |
486 | $current_ans_id = $this->getpath($answer, | |
487 | array('@', 'id'), '', true); | |
488 | if (strcmp ($current_ans_id, $correct_answer_id) == 0) { | |
489 | $subquestion = $this->getpath($answer, | |
490 | array('#', 'TEXT', 0, '#'), '', true); | |
c7df5006 TH |
491 | break; |
492 | } | |
2befe778 | 493 | } |
8a8dd7d8 JMV |
494 | $question->subquestions[] = $this->text_field($this->cleaninput($subquestion)); |
495 | $question->subanswers[] = $choicetext; | |
496 | } | |
497 | ||
498 | if ($subquestion == '') { // Then in this case, $choice is a distractor. | |
499 | $question->subquestions[] = $this->text_field(''); | |
500 | $question->subanswers[] = $choicetext; | |
2befe778 | 501 | } |
2befe778 | 502 | } |
2befe778 | 503 | } |
aeb15530 | 504 | |
8a8dd7d8 JMV |
505 | // Verify that this matching question has enough subquestions and subanswers. |
506 | $subquestioncount = 0; | |
507 | $subanswercount = 0; | |
508 | $subanswers = $question->subanswers; | |
509 | foreach ($question->subquestions as $key => $subquestion) { | |
510 | $subquestion = $subquestion['text']; | |
511 | $subanswer = $subanswers[$key]; | |
512 | if ($subquestion != '') { | |
513 | $subquestioncount++; | |
514 | } | |
515 | $subanswercount++; | |
516 | } | |
517 | if ($subquestioncount < 2 || $subanswercount < 3) { | |
518 | $this->error(get_string('notenoughtsubans', 'qformat_blackboard', $question->questiontext)); | |
519 | } else { | |
520 | $questions[] = $question; | |
521 | } | |
aeb15530 | 522 | |
c7df5006 | 523 | } |
2befe778 | 524 | } |
84769fd8 | 525 | } |