MDL-15094 fixed stats
[moodle.git] / question / type / match / questiontype.php
CommitLineData
516cf3eb 1<?php // $Id$
2
3/////////////
4/// MATCH ///
5/////////////
6
7/// QUESTION TYPE CLASS //////////////////
1976496e 8/**
9 * @package questionbank
10 * @subpackage questiontypes
7375c542 11 */
af3830ee 12class question_match_qtype extends default_questiontype {
516cf3eb 13
14 function name() {
15 return 'match';
16 }
17
18 function get_question_options(&$question) {
32a189d6 19 $question->options = get_record('question_match', 'question', $question->id);
f07d1d31 20 $question->options->subquestions = get_records('question_match_sub', 'question', $question->id, 'id ASC');
516cf3eb 21 return true;
22 }
23
24 function save_question_options($question) {
a58ffe3f 25 $result = new stdClass;
069a820a 26
32a189d6 27 if (!$oldsubquestions = get_records("question_match_sub", "question", $question->id, "id ASC")) {
516cf3eb 28 $oldsubquestions = array();
29 }
30
516cf3eb 31 // $subquestions will be an array with subquestion ids
32 $subquestions = array();
33
34 // Insert all the new question+answer pairs
35 foreach ($question->subquestions as $key => $questiontext) {
36 $answertext = $question->subanswers[$key];
ebf83e2c 37 if ($questiontext != '' || $answertext != '') {
516cf3eb 38 if ($subquestion = array_shift($oldsubquestions)) { // Existing answer, so reuse it
39 $subquestion->questiontext = $questiontext;
40 $subquestion->answertext = $answertext;
32a189d6 41 if (!update_record("question_match_sub", $subquestion)) {
7518b645 42 $result->error = "Could not insert match subquestion! (id=$subquestion->id)";
516cf3eb 43 return $result;
44 }
45 } else {
a58ffe3f 46 $subquestion = new stdClass;
516cf3eb 47 // Determine a unique random code
48 $subquestion->code = rand(1,999999999);
18bd0d68 49 while (record_exists('question_match_sub', 'code', $subquestion->code, 'question', $question->id)) {
516cf3eb 50 $subquestion->code = rand();
51 }
52 $subquestion->question = $question->id;
53 $subquestion->questiontext = $questiontext;
54 $subquestion->answertext = $answertext;
32a189d6 55 if (!$subquestion->id = insert_record("question_match_sub", $subquestion)) {
7518b645 56 $result->error = "Could not insert match subquestion!";
516cf3eb 57 return $result;
58 }
59 }
60 $subquestions[] = $subquestion->id;
61 }
ebf83e2c 62 if ($questiontext != '' && $answertext == '') {
a58ffe3f 63 $result->notice = get_string('nomatchinganswer', 'quiz', $questiontext);
64 }
516cf3eb 65 }
66
67 // delete old subquestions records
68 if (!empty($oldsubquestions)) {
69 foreach($oldsubquestions as $os) {
32a189d6 70 delete_records('question_match_sub', 'id', $os->id);
516cf3eb 71 }
72 }
73
32a189d6 74 if ($options = get_record("question_match", "question", $question->id)) {
516cf3eb 75 $options->subquestions = implode(",",$subquestions);
76 $options->shuffleanswers = $question->shuffleanswers;
32a189d6 77 if (!update_record("question_match", $options)) {
7518b645 78 $result->error = "Could not update match options! (id=$options->id)";
516cf3eb 79 return $result;
80 }
81 } else {
82 unset($options);
83 $options->question = $question->id;
84 $options->subquestions = implode(",",$subquestions);
85 $options->shuffleanswers = $question->shuffleanswers;
32a189d6 86 if (!insert_record("question_match", $options)) {
7518b645 87 $result->error = "Could not insert match options!";
516cf3eb 88 return $result;
89 }
90 }
a58ffe3f 91
92 if (!empty($result->notice)) {
93 return $result;
94 }
95
96 if (count($subquestions) < 3) {
97 $result->notice = get_string('notenoughanswers', 'quiz', 3);
98 return $result;
99 }
100
516cf3eb 101 return true;
102 }
103
104 /**
105 * Deletes question from the question-type specific tables
106 *
107 * @return boolean Success/Failure
108 * @param integer $question->id
109 */
90c3f310 110 function delete_question($questionid) {
111 delete_records("question_match", "question", $questionid);
112 delete_records("question_match_sub", "question", $questionid);
516cf3eb 113 return true;
114 }
115
116 function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
f07d1d31 117 if (!$state->options->subquestions = get_records('question_match_sub', 'question', $question->id, 'id ASC')) {
00c30069 118 notify('Error: Missing subquestions!');
119 return false;
516cf3eb 120 }
121
122 foreach ($state->options->subquestions as $key => $subquestion) {
123 // This seems rather over complicated, but it is useful for the
124 // randomsamatch questiontype, which can then inherit the print
125 // and grading functions. This way it is possible to define multiple
126 // answers per question, each with different marks and feedback.
127 $answer = new stdClass();
128 $answer->id = $subquestion->code;
129 $answer->answer = $subquestion->answertext;
130 $answer->fraction = 1.0;
131 $state->options->subquestions[$key]->options
00c30069 132 ->answers[$subquestion->code] = clone($answer);
516cf3eb 133
134 $state->responses[$key] = '';
135 }
136
137 // Shuffle the answers if required
138 if ($cmoptions->shuffleanswers and $question->options->shuffleanswers) {
139 $state->options->subquestions = swapshuffle_assoc($state->options->subquestions);
140 }
141
142 return true;
143 }
144
145 function restore_session_and_responses(&$question, &$state) {
146 // The serialized format for matching questions is a comma separated
147 // list of question answer pairs (e.g. 1-1,2-3,3-2), where the ids of
32a189d6 148 // both refer to the id in the table question_match_sub.
516cf3eb 149 $responses = explode(',', $state->responses['']);
150 $responses = array_map(create_function('$val',
151 'return explode("-", $val);'), $responses);
152
f07d1d31 153 if (!$questions = get_records('question_match_sub', 'question', $question->id, 'id ASC')) {
516cf3eb 154 notify('Error: Missing subquestions!');
155 return false;
156 }
157
158 // Restore the previous responses and place the questions into the state options
159 $state->responses = array();
160 $state->options->subquestions = array();
161 foreach ($responses as $response) {
162 $state->responses[$response[0]] = $response[1];
163 $state->options->subquestions[$response[0]] = $questions[$response[0]];
164 }
165
166 foreach ($state->options->subquestions as $key => $subquestion) {
167 // This seems rather over complicated, but it is useful for the
168 // randomsamatch questiontype, which can then inherit the print
169 // and grading functions. This way it is possible to define multiple
170 // answers per question, each with different marks and feedback.
171 $answer = new stdClass();
172 $answer->id = $subquestion->code;
29e959a5 173 $answer->answer = format_string($subquestion->answertext);
516cf3eb 174 $answer->fraction = 1.0;
175 $state->options->subquestions[$key]->options
176 ->answers[$subquestion->code] = clone($answer);
177 }
178
179 return true;
180 }
181
182 function save_session_and_responses(&$question, &$state) {
87ee4968 183 $subquestions = &$state->options->subquestions;
184
185 // Prepare an array to help when disambiguating equal answers.
186 $answertexts = array();
187 foreach ($subquestions as $subquestion) {
188 $ans = reset($subquestion->options->answers);
189 $answertexts[$ans->id] = $ans->answer;
190 }
069a820a 191
516cf3eb 192 // Serialize responses
193 $responses = array();
87ee4968 194 foreach ($subquestions as $key => $subquestion) {
7d6af8ca 195 $response = 0;
0c24ee0f 196 if ($subquestion->questiontext) {
87ee4968 197 if ($state->responses[$key]) {
198 $response = $state->responses[$key];
199 if (!array_key_exists($response, $subquestion->options->answers)) {
200 // If studen's answer did not match by id, but there may be
201 // two answers with the same text, but different ids,
202 // so we need to try matching the answer text.
203 $expected_answer = reset($subquestion->options->answers);
204 if ($answertexts[$response] == $expected_answer->answer) {
205 $response = $expected_answer->id;
206 $state->responses[$key] = $response;
207 }
208 }
87ee4968 209 }
0c24ee0f 210 }
7d6af8ca 211 $responses[] = $key.'-'.$response;
516cf3eb 212 }
213 $responses = implode(',', $responses);
214
215 // Set the legacy answer field
0c24ee0f 216 if (!set_field('question_states', 'answer', $responses, 'id', $state->id)) {
516cf3eb 217 return false;
218 }
219 return true;
220 }
221
222 function get_correct_responses(&$question, &$state) {
223 $responses = array();
224 foreach ($state->options->subquestions as $sub) {
225 foreach ($sub->options->answers as $answer) {
ebf83e2c 226 if (1 == $answer->fraction && $sub->questiontext != '') {
516cf3eb 227 $responses[$sub->id] = $answer->id;
228 }
229 }
230 }
231 return empty($responses) ? null : $responses;
232 }
233
234 function print_question_formulation_and_controls(&$question, &$state, $cmoptions, $options) {
37a12367 235 global $CFG;
516cf3eb 236 $subquestions = $state->options->subquestions;
237 $correctanswers = $this->get_correct_responses($question, $state);
238 $nameprefix = $question->name_prefix;
239 $answers = array();
0b4ce29d 240 $allanswers = array();
87ee4968 241 $answerids = array();
516cf3eb 242 $responses = &$state->responses;
243
069a820a 244 // Prepare a list of answers, removing duplicates.
516cf3eb 245 foreach ($subquestions as $subquestion) {
246 foreach ($subquestion->options->answers as $ans) {
0b4ce29d 247 $allanswers[$ans->id] = $ans->answer;
87ee4968 248 if (!in_array($ans->answer, $answers)) {
249 $answers[$ans->id] = $ans->answer;
250 $answerids[$ans->answer] = $ans->id;
87ee4968 251 }
516cf3eb 252 }
253 }
069a820a 254
0b4ce29d 255 // Fix up the ids of any responses that point the the eliminated duplicates.
256 foreach ($responses as $subquestionid => $ignored) {
257 if ($responses[$subquestionid]) {
258 $responses[$subquestionid] = $answerids[$allanswers[$responses[$subquestionid]]];
259 }
260 }
261 foreach ($correctanswers as $subquestionid => $ignored) {
262 $correctanswers[$subquestionid] = $answerids[$allanswers[$correctanswers[$subquestionid]]];
263 }
516cf3eb 264
265 // Shuffle the answers
266 $answers = draw_rand_array($answers, count($answers));
267
37a12367 268 // Print formulation
1b8a7434 269 $questiontext = $this->format_text($question->questiontext,
270 $question->questiontextformat, $cmoptions);
9fc3100f 271 $image = get_question_image($question);
516cf3eb 272
069a820a 273 // Print the input controls
516cf3eb 274 foreach ($subquestions as $key => $subquestion) {
ebf83e2c 275 if ($subquestion->questiontext != '') {
069a820a 276 // Subquestion text:
a58ffe3f 277 $a = new stdClass;
1b8a7434 278 $a->text = $this->format_text($subquestion->questiontext,
279 $question->questiontextformat, $cmoptions);
2b087056 280
069a820a 281 // Drop-down list:
a58ffe3f 282 $menuname = $nameprefix.$subquestion->id;
283 $response = isset($state->responses[$subquestion->id])
284 ? $state->responses[$subquestion->id] : '0';
2b087056 285
286 $a->class = ' ';
287 $a->feedbackimg = ' ';
288
069a820a 289 if ($options->readonly and $options->correct_responses) {
290 if (isset($correctanswers[$subquestion->id])
2b087056 291 and ($correctanswers[$subquestion->id] == $response)) {
069a820a 292 $correctresponse = 1;
293 } else {
294 $correctresponse = 0;
295 }
2b087056 296
1b16ecd1 297 if ($options->feedback && $response) {
069a820a 298 $a->class = question_get_feedback_class($correctresponse);
299 $a->feedbackimg = question_get_feedback_image($correctresponse);
300 }
2b087056 301 }
302
303 $a->control = choose_from_menu($answers, $menuname, $response, 'choose',
304 '', 0, true, $options->readonly);
069a820a 305
a58ffe3f 306 // Neither the editing interface or the database allow to provide
307 // fedback for this question type.
308 // However (as was pointed out in bug bug 3294) the randomsamatch
309 // type which reuses this method can have feedback defined for
310 // the wrapped shortanswer questions.
311 //if ($options->feedback
312 // && !empty($subquestion->options->answers[$responses[$key]]->feedback)) {
313 // print_comment($subquestion->options->answers[$responses[$key]]->feedback);
314 //}
2b087056 315
a58ffe3f 316 $anss[] = $a;
516cf3eb 317 }
516cf3eb 318 }
aaae75b0 319 include("$CFG->dirroot/question/type/match/display.html");
516cf3eb 320 }
321
322 function grade_responses(&$question, &$state, $cmoptions) {
323 $subquestions = &$state->options->subquestions;
324 $responses = &$state->responses;
325
87ee4968 326 // Prepare an array to help when disambiguating equal answers.
327 $answertexts = array();
328 foreach ($subquestions as $subquestion) {
329 $ans = reset($subquestion->options->answers);
330 $answertexts[$ans->id] = $ans->answer;
331 }
069a820a 332
87ee4968 333 // Add up the grades from each subquestion.
516cf3eb 334 $sumgrade = 0;
a58ffe3f 335 $totalgrade = 0;
516cf3eb 336 foreach ($subquestions as $key => $sub) {
a58ffe3f 337 if ($sub->questiontext) {
338 $totalgrade += 1;
87ee4968 339 $response = $responses[$key];
340 if ($response && !array_key_exists($response, $sub->options->answers)) {
341 // If studen's answer did not match by id, but there may be
342 // two answers with the same text, but different ids,
343 // so we need to try matching the answer text.
344 $expected_answer = reset($sub->options->answers);
345 if ($answertexts[$response] == $expected_answer->answer) {
346 $response = $expected_answer->id;
347 }
348 }
349 if (array_key_exists($response, $sub->options->answers)) {
350 $sumgrade += $sub->options->answers[$response]->fraction;
a58ffe3f 351 }
516cf3eb 352 }
353 }
354
a58ffe3f 355 $state->raw_grade = $sumgrade/$totalgrade;
516cf3eb 356 if (empty($state->raw_grade)) {
357 $state->raw_grade = 0;
358 }
359
360 // Make sure we don't assign negative or too high marks
361 $state->raw_grade = min(max((float) $state->raw_grade,
362 0.0), 1.0) * $question->maxgrade;
363 $state->penalty = $question->penalty * $question->maxgrade;
364
f30bbcaf 365 // mark the state as graded
366 $state->event = ($state->event == QUESTION_EVENTCLOSE) ? QUESTION_EVENTCLOSEANDGRADE : QUESTION_EVENTGRADE;
367
516cf3eb 368 return true;
369 }
370
b25486fc 371 function compare_responses($question, $state, $teststate) {
2c89cfb5 372 foreach ($state->responses as $i=>$sr) {
373 if (empty($teststate->responses[$i])) {
374 if (!empty($state->responses[$i])) {
375 return false;
376 }
377 } else if ($state->responses[$i] != $teststate->responses[$i]) {
b25486fc 378 return false;
379 }
380 }
381 return true;
382 }
383
516cf3eb 384 // ULPGC ecastro for stats report
385 function get_all_responses($question, $state) {
974383f9 386 $answers = array();
516cf3eb 387 if (is_array($question->options->subquestions)) {
645d7610 388 foreach ($question->options->subquestions as $aid => $answer) {
389 if ($answer->questiontext) {
390 $r = new stdClass;
391 $r->answer = $answer->questiontext . ": " . $answer->answertext;
392 $r->credit = 1;
393 $answers[$aid] = $r;
394 }
516cf3eb 395 }
516cf3eb 396 }
a58ffe3f 397 $result = new stdClass;
516cf3eb 398 $result->id = $question->id;
399 $result->responses = $answers;
400 return $result;
401 }
402
403 // ULPGC ecastro
404 function get_actual_response($question, $state) {
01bd54e0 405 $subquestions = &$state->options->subquestions;
406 $responses = &$state->responses;
407 $results=array();
408 foreach ($subquestions as $key => $sub) {
409 foreach ($responses as $ind => $code) {
410 if (isset($sub->options->answers[$code])) {
645d7610 411 $results[$ind] = $subquestions[$ind]->questiontext . ": " . $sub->options->answers[$code]->answer;
01bd54e0 412 }
413 }
414 }
415 return $results;
416 }
0a5b58af 417
418 function response_summary($question, $state, $length=80) {
419 // This should almost certainly be overridden
755bddf1 420 return substr(implode(', ', $this->get_actual_response($question, $state)), 0, $length);
0a5b58af 421 }
069a820a 422
c5d94c41 423/// BACKUP FUNCTIONS ////////////////////////////
424
425 /*
426 * Backup the data in the question
427 *
428 * This is used in question/backuplib.php
429 */
430 function backup($bf,$preferences,$question,$level=6) {
431
432 $status = true;
433
f07d1d31 434 $matchs = get_records('question_match_sub', 'question', $question, 'id ASC');
c5d94c41 435 //If there are matchs
436 if ($matchs) {
437 $status = fwrite ($bf,start_tag("MATCHS",6,true));
438 //Iterate over each match
439 foreach ($matchs as $match) {
440 $status = fwrite ($bf,start_tag("MATCH",7,true));
441 //Print match contents
442 fwrite ($bf,full_tag("ID",8,false,$match->id));
443 fwrite ($bf,full_tag("CODE",8,false,$match->code));
444 fwrite ($bf,full_tag("QUESTIONTEXT",8,false,$match->questiontext));
445 fwrite ($bf,full_tag("ANSWERTEXT",8,false,$match->answertext));
446 $status = fwrite ($bf,end_tag("MATCH",7,true));
447 }
448 $status = fwrite ($bf,end_tag("MATCHS",6,true));
449 }
450 return $status;
451 }
516cf3eb 452
315559d3 453/// RESTORE FUNCTIONS /////////////////
454
455 /*
456 * Restores the data in the question
457 *
458 * This is used in question/restorelib.php
459 */
460 function restore($old_question_id,$new_question_id,$info,$restore) {
9db7dab2 461 global $DB;
315559d3 462
463 $status = true;
464
465 //Get the matchs array
466 $matchs = $info['#']['MATCHS']['0']['#']['MATCH'];
467
468 //We have to build the subquestions field (a list of match_sub id)
469 $subquestions_field = "";
470 $in_first = true;
471
472 //Iterate over matchs
473 for($i = 0; $i < sizeof($matchs); $i++) {
474 $mat_info = $matchs[$i];
475
476 //We'll need this later!!
477 $oldid = backup_todb($mat_info['#']['ID']['0']['#']);
478
479 //Now, build the question_match_SUB record structure
a58ffe3f 480 $match_sub = new stdClass;
315559d3 481 $match_sub->question = $new_question_id;
1f4d6e9a 482 $match_sub->code = isset($mat_info['#']['CODE']['0']['#'])?backup_todb($mat_info['#']['CODE']['0']['#']):'';
315559d3 483 if (!$match_sub->code) {
484 $match_sub->code = $oldid;
485 }
486 $match_sub->questiontext = backup_todb($mat_info['#']['QUESTIONTEXT']['0']['#']);
487 $match_sub->answertext = backup_todb($mat_info['#']['ANSWERTEXT']['0']['#']);
488
489 //The structure is equal to the db, so insert the question_match_sub
9db7dab2 490 $newid = $DB->insert_record ("question_match_sub",$match_sub);
315559d3 491
492 //Do some output
493 if (($i+1) % 50 == 0) {
494 if (!defined('RESTORE_SILENTLY')) {
495 echo ".";
496 if (($i+1) % 1000 == 0) {
497 echo "<br />";
498 }
499 }
500 backup_flush(300);
501 }
502
503 if ($newid) {
504 //We have the newid, update backup_ids
505 backup_putid($restore->backup_unique_code,"question_match_sub",$oldid,
506 $newid);
507 //We have a new match_sub, append it to subquestions_field
508 if ($in_first) {
509 $subquestions_field .= $newid;
510 $in_first = false;
511 } else {
512 $subquestions_field .= ",".$newid;
513 }
514 } else {
515 $status = false;
516 }
517 }
518
519 //We have created every match_sub, now create the match
87ee4968 520 $match = new stdClass;
315559d3 521 $match->question = $new_question_id;
522 $match->subquestions = $subquestions_field;
523
524 //The structure is equal to the db, so insert the question_match_sub
9db7dab2 525 $newid = $DB->insert_record ("question_match",$match);
315559d3 526
527 if (!$newid) {
528 $status = false;
529 }
530
531 return $status;
532 }
533
534 function restore_map($old_question_id,$new_question_id,$info,$restore) {
535
536 $status = true;
537
538 //Get the matchs array
539 $matchs = $info['#']['MATCHS']['0']['#']['MATCH'];
540
541 //We have to build the subquestions field (a list of match_sub id)
542 $subquestions_field = "";
543 $in_first = true;
544
545 //Iterate over matchs
546 for($i = 0; $i < sizeof($matchs); $i++) {
547 $mat_info = $matchs[$i];
548
549 //We'll need this later!!
550 $oldid = backup_todb($mat_info['#']['ID']['0']['#']);
551
552 //Now, build the question_match_SUB record structure
553 $match_sub->question = $new_question_id;
554 $match_sub->questiontext = backup_todb($mat_info['#']['QUESTIONTEXT']['0']['#']);
555 $match_sub->answertext = backup_todb($mat_info['#']['ANSWERTEXT']['0']['#']);
556
557 //If we are in this method is because the question exists in DB, so its
558 //match_sub must exist too.
559 //Now, we are going to look for that match_sub in DB and to create the
560 //mappings in backup_ids to use them later where restoring states (user level).
561
562 //Get the match_sub from DB (by question, questiontext and answertext)
563 $db_match_sub = get_record ("question_match_sub","question",$new_question_id,
564 "questiontext",$match_sub->questiontext,
565 "answertext",$match_sub->answertext);
566 //Do some output
567 if (($i+1) % 50 == 0) {
568 if (!defined('RESTORE_SILENTLY')) {
569 echo ".";
570 if (($i+1) % 1000 == 0) {
571 echo "<br />";
572 }
573 }
574 backup_flush(300);
575 }
576
577 //We have the database match_sub, so update backup_ids
578 if ($db_match_sub) {
579 //We have the newid, update backup_ids
580 backup_putid($restore->backup_unique_code,"question_match_sub",$oldid,
581 $db_match_sub->id);
582 } else {
583 $status = false;
584 }
585 }
586
587 return $status;
588 }
589
590 function restore_recode_answer($state, $restore) {
591
592 //The answer is a comma separated list of hypen separated math_subs (for question and answer)
593 $answer_field = "";
594 $in_first = true;
595 $tok = strtok($state->answer,",");
596 while ($tok) {
597 //Extract the match_sub for the question and the answer
598 $exploded = explode("-",$tok);
599 $match_question_id = $exploded[0];
3ff8a187 600 $match_answer_id = $exploded[1];
315559d3 601 //Get the match_sub from backup_ids (for the question)
602 if (!$match_que = backup_getid($restore->backup_unique_code,"question_match_sub",$match_question_id)) {
3ff8a187 603 echo 'Could not recode question in question_match_sub '.$match_question_id.'<br />';
315559d3 604 }
3ff8a187 605 //Get the match_sub from backup_ids (for the answer)
606 if ($match_answer_id) { // only recode answer if not 0, not answered yet
607 if (!$match_ans = backup_getid($restore->backup_unique_code,"question_match_sub",$match_answer_id)) {
608 echo 'Could not recode answer in question_match_sub '.$match_answer_id.'<br />';
609 }
610 }
611
612 if ($match_que) {
613 //If the question hasn't response, it must be 0
614 if (!$match_ans and $match_answer_id == 0) {
615 $match_ans->new_id = 0;
616 }
617
618 if ($in_first) {
619 $answer_field .= $match_que->new_id."-".$match_ans->new_id;
620 $in_first = false;
621 } else {
622 $answer_field .= ",".$match_que->new_id."-".$match_ans->new_id;
623 }
315559d3 624 }
625 //check for next
626 $tok = strtok(",");
627 }
628 return $answer_field;
629 }
630
c85607f0 631 /**
632 * Decode links in question type specific tables.
633 * @return bool success or failure.
271e6dec 634 */
c85607f0 635 function decode_content_links_caller($questionids, $restore, &$i) {
44e1b7d7 636 global $DB;
637
e3b2eb60 638 $status = true;
639
c85607f0 640 // Decode links in the question_match_sub table.
44e1b7d7 641 if ($subquestions = $DB->get_records_list('question_match_sub', 'question', $questionids, '', 'id, questiontext')) {
c85607f0 642
643 foreach ($subquestions as $subquestion) {
644 $questiontext = restore_decode_content_links_worker($subquestion->questiontext, $restore);
645 if ($questiontext != $subquestion->questiontext) {
646 $subquestion->questiontext = addslashes($questiontext);
647 if (!update_record('question_match_sub', $subquestion)) {
648 $status = false;
649 }
650 }
651
652 // Do some output.
653 if (++$i % 5 == 0 && !defined('RESTORE_SILENTLY')) {
654 echo ".";
655 if ($i % 100 == 0) {
656 echo "<br />";
657 }
658 backup_flush(300);
659 }
660 }
661 }
e3b2eb60 662
663 return $status;
c85607f0 664 }
271e6dec 665
666 function find_file_links($question, $courseid){
667 // find links in the question_match_sub table.
668 $urls = array();
6f9ce926 669 if (isset($question->options->subquestions)){
670 foreach ($question->options->subquestions as $subquestion) {
671 $urls += question_find_file_links_from_html($subquestion->questiontext, $courseid);
672 }
271e6dec 673
6f9ce926 674 //set all the values of the array to the question object
675 if ($urls){
676 $urls = array_combine(array_keys($urls), array_fill(0, count($urls), array($question->id)));
677 }
271e6dec 678 }
679 $urls = array_merge_recursive($urls, parent::find_file_links($question, $courseid));
6f9ce926 680
271e6dec 681 return $urls;
682 }
683
684 function replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination){
685 parent::replace_file_links($question, $fromcourseid, $tocourseid, $url, $destination);
686 // replace links in the question_match_sub table.
687 if (isset($question->options->subquestions)){
688 foreach ($question->options->subquestions as $subquestion) {
689 $subquestionchanged = false;
690 $subquestion->questiontext = question_replace_file_links_in_html($subquestion->questiontext, $fromcourseid, $tocourseid, $url, $destination, $subquestionchanged);
691 if ($subquestionchanged){//need to update rec in db
692 if (!update_record('question_match_sub', addslashes_recursive($subquestion))) {
5a2a5331 693 print_error('Couldn\'t update \'question_match_sub\' record '.$subquestion->id);
271e6dec 694 }
695
696 }
697 }
698 }
699 }
516cf3eb 700}
701//// END OF CLASS ////
702
703//////////////////////////////////////////////////////////////////////////
704//// INITIATION - Without this line the question type is not in use... ///
705//////////////////////////////////////////////////////////////////////////
a2156789 706question_register_questiontype(new question_match_qtype());
516cf3eb 707?>