file ongoing.html was added on branch MOODLE_15_STABLE on 2005-07-07 16:14:36 +0000
[moodle.git] / mod / quiz / restorelibpre15.php
blobc65c6bb7c69d47d3bb5f7c87c0d67fd9ee83c666
1 <?php //$Id$
2 //This php script contains all the stuff to backup/restore
3 //quiz mods
5 //To see, put your terminal to 160cc
7 //This is the "graphical" structure of the quiz mod:
8 //
9 // quiz quiz_categories
10 // (CL,pk->id) (CL,pk->id)
11 // | |
12 // ------------------------------------------------------------------- |
13 // | | | | |.......................................
14 // | | | | | .
15 // | | | | | .
16 // quiz_attempts quiz_grades quiz_question_grades quiz_question_versions | ----quiz_question_datasets---- .
17 // (UL,pk->id, fk->quiz) (UL,pk->id,fk->quiz) (CL,pk->id,fk->quiz) (CL,pk->id,fk->quiz) | | (CL,pk->id,fk->question, | .
18 // | | . | | fk->dataset_definition) | .
19 // | | . | | | .
20 // | | . | | | .
21 // | | . | | | .
22 // quiz_responses | quiz_questions quiz_dataset_definitions
23 // (UL,pk->id, fk->attempt)----------------------------------------------------(CL,pk->id,fk->category,files) (CL,pk->id,fk->category)
24 // | |
25 // | |
26 // | |
27 // | quiz_dataset_items
28 // | (CL,pk->id,fk->definition)
29 // |
30 // |
31 // |
32 // --------------------------------------------------------------------------------------------------------------
33 // | | | | | | |
34 // | | | | | | |
35 // | | | | quiz_calculated | | quiz_randomsamatch
36 // quiz_truefalse | quiz_multichoice | (CL,pl->id,fk->question) | |--(CL,pl->id,fk->question)
37 // (CL,pl->id,fk->question) | (CL,pl->id,fk->question) | . | |
38 // . | . | . | |
39 // . quiz_shortanswer . quiz_numerical . quiz_multianswer. |
40 // . (CL,pl->id,fk->question) . (CL,pl->id,fk->question) . (CL,pl->id,fk->question) | quiz_match
41 // . . . . . . |--(CL,pl->id,fk->question)
42 // . . . . . . | .
43 // . . . . . . | .
44 // . . . . . . | .
45 // . . . . . . | quiz_match_sub
46 // . . . . . . |--(CL,pl->id,fk->question)
47 // ........................................................................................ |
48 // . |
49 // . |
50 // . | quiz_numerical_units
51 // quiz_answers |--(CL,pl->id,fk->question)
52 // (CL,pk->id,fk->question)----------------------------------------------------------
54 // Meaning: pk->primary key field of the table
55 // fk->foreign key to link with parent
56 // nt->nested field (recursive data)
57 // CL->course level info
58 // UL->user level info
59 // files->table may have files
61 //-----------------------------------------------------------
63 //This module is special, because we make the restore in two steps:
64 // 1.-We restore every category and their questions (complete structure). It includes this tables:
65 // - quiz_categories
66 // - quiz_questions
67 // - quiz_truefalse
68 // - quiz_shortanswer
69 // - quiz_multianswer
70 // - quiz_multichoice
71 // - quiz_numerical
72 // - quiz_randomsamatch
73 // - quiz_match
74 // - quiz_match_sub
75 // - quiz_calculated
76 // - quiz_answers
77 // - quiz_numerical_units
78 // - quiz_question_datasets
79 // - quiz_dataset_definitions
80 // - quiz_dataset_items
81 // All this backup info have its own section in moodle.xml (QUESTION_CATEGORIES) and it's generated
82 // before every module backup standard invocation. And only if to restore quizzes has been selected !!
83 // It's invoked with quiz_restore_question_categories. (course independent).
85 // 2.-Standard module restore (Invoked via quiz_restore_mods). It includes this tables:
86 // - quiz
87 // - quiz_question_versions
88 // - quiz_question_grades
89 // - quiz_attempts
90 // - quiz_grades
91 // - quiz_responses
92 // This step is the standard mod backup. (course dependent).
94 //We are going to nedd quiz libs to be able to mimic the upgrade process
95 require_once("$CFG->dirroot/mod/quiz/locallib.php");
97 //STEP 1. Restore categories/questions and associated structures
98 // (course independent)
99 function quiz_restore_pre15_question_categories($category,$restore) {
101 global $CFG;
103 $status = true;
105 //Get record from backup_ids
106 $data = backup_getid($restore->backup_unique_code,"quiz_categories",$category->id);
108 if ($data) {
109 //Now get completed xmlized object
110 $info = $data->info;
111 //traverse_xmlize($info); //Debug
112 //print_object ($GLOBALS['traverse_array']); //Debug
113 //$GLOBALS['traverse_array']=""; //Debug
115 //Now, build the QUIZ_CATEGORIES record structure
116 $quiz_cat->course = $restore->course_id;
117 $quiz_cat->name = backup_todb($info['QUESTION_CATEGORY']['#']['NAME']['0']['#']);
118 $quiz_cat->info = backup_todb($info['QUESTION_CATEGORY']['#']['INFO']['0']['#']);
119 $quiz_cat->publish = backup_todb($info['QUESTION_CATEGORY']['#']['PUBLISH']['0']['#']);
120 $quiz_cat->stamp = backup_todb($info['QUESTION_CATEGORY']['#']['STAMP']['0']['#']);
121 $quiz_cat->parent = backup_todb($info['QUESTION_CATEGORY']['#']['PARENT']['0']['#']);
122 $quiz_cat->sortorder = backup_todb($info['QUESTION_CATEGORY']['#']['SORTORDER']['0']['#']);
124 if ($catfound = restore_get_best_quiz_category($quiz_cat, $restore->course_id)) {
125 $newid = $catfound;
126 } else {
127 if (!$quiz_cat->stamp) {
128 $quiz_cat->stamp = make_unique_id_code();
130 $newid = insert_record ("quiz_categories",$quiz_cat);
133 //Do some output
134 if ($newid) {
135 echo "<li>".get_string('category', 'quiz')." \"".$quiz_cat->name."\"<br />";
136 } else {
137 //We must never arrive here !!
138 echo "<li>".get_string('category', 'quiz')." \"".$quiz_cat->name."\" Error!<br />";
139 $status = false;
141 backup_flush(300);
143 //Here category has been created or selected, so save results in backup_ids and start with questions
144 if ($newid and $status) {
145 //We have the newid, update backup_ids
146 backup_putid($restore->backup_unique_code,"quiz_categories",
147 $category->id, $newid);
148 //Now restore quiz_questions
149 $status = quiz_restore_pre15_questions ($category->id, $newid,$info,$restore);
150 } else {
151 $status = false;
153 echo '</li>';
156 return $status;
159 function quiz_restore_pre15_questions ($old_category_id,$new_category_id,$info,$restore) {
161 global $CFG;
163 $status = true;
165 //Get the questions array
166 $questions = $info['QUESTION_CATEGORY']['#']['QUESTIONS']['0']['#']['QUESTION'];
168 //Iterate over questions
169 for($i = 0; $i < sizeof($questions); $i++) {
170 $question = new object;
171 $que_info = $questions[$i];
172 //traverse_xmlize($que_info); //Debug
173 //print_object ($GLOBALS['traverse_array']); //Debug
174 //$GLOBALS['traverse_array']=""; //Debug
176 //We'll need this later!!
177 $oldid = backup_todb($que_info['#']['ID']['0']['#']);
179 //Now, build the QUIZ_QUESTIONS record structure
180 $question->category = $new_category_id;
181 $question->parent = backup_todb($que_info['#']['PARENT']['0']['#']);
182 $question->name = backup_todb($que_info['#']['NAME']['0']['#']);
183 $question->questiontext = backup_todb($que_info['#']['QUESTIONTEXT']['0']['#']);
184 $question->questiontextformat = backup_todb($que_info['#']['QUESTIONTEXTFORMAT']['0']['#']);
185 $question->image = backup_todb($que_info['#']['IMAGE']['0']['#']);
186 $question->defaultgrade = backup_todb($que_info['#']['DEFAULTGRADE']['0']['#']);
187 if (isset($que_info['#']['PENALTY']['0']['#'])) { //Only if it's set, to apply DB default else.
188 $question->penalty = backup_todb($que_info['#']['PENALTY']['0']['#']);
190 $question->qtype = backup_todb($que_info['#']['QTYPE']['0']['#']);
191 if (isset($que_info['#']['LENGTH']['0']['#'])) { //Only if it's set, to apply DB default else.
192 $question->length = backup_todb($que_info['#']['LENGTH']['0']['#']);
194 $question->stamp = backup_todb($que_info['#']['STAMP']['0']['#']);
195 if (isset($que_info['#']['VERSION']['0']['#'])) { //Only if it's set, to apply DB default else.
196 $question->version = backup_todb($que_info['#']['VERSION']['0']['#']);
198 if (isset($que_info['#']['HIDDEN']['0']['#'])) { //Only if it's set, to apply DB default else.
199 $question->hidden = backup_todb($que_info['#']['HIDDEN']['0']['#']);
202 //Although only a few backups can have questions with parent, we try to recode it
203 //if it contains something
204 if ($question->parent and $parent = backup_getid($restore->backup_unique_code,"quiz_questions",$question->parent)) {
205 $question->parent = $parent->new_id;
208 // If it is a random question then hide it
209 if ($question->qtype == RANDOM) {
210 $question->hidden = 1;
213 //If it is a description question, length = 0
214 if ($question->qtype == DESCRIPTION) {
215 $question->length = 0;
218 //Check if the question exists
219 //by category and stamp
220 $question_exists = get_record ("quiz_questions","category",$question->category,
221 "stamp",$question->stamp);
222 //If the stamp doesn't exists, check if question exists
223 //by category, name and questiontext and calculate stamp
224 //Mantains pre Beta 1.1 compatibility !!
225 if (!$question->stamp) {
226 $question->stamp = make_unique_id_code();
227 $question->version = 1;
228 $question_exists = get_record ("quiz_questions","category",$question->category,
229 "name",$question->name,
230 "questiontext",$question->questiontext);
233 //If the question exists, only record its id
234 if ($question_exists) {
235 $newid = $question_exists->id;
236 $creatingnewquestion = false;
237 //Else, create a new question
238 } else {
239 //The structure is equal to the db, so insert the quiz_questions
240 $newid = insert_record ("quiz_questions",$question);
241 //If it is a random question, parent = id
242 if ($newid && $question->qtype == RANDOM) {
243 set_field ('quiz_questions', 'parent', $newid, 'id', $newid);
245 $creatingnewquestion = true;
248 //Do some output
249 if (($i+1) % 2 == 0) {
250 echo ".";
251 if (($i+1) % 40 == 0) {
252 echo "<br />";
254 backup_flush(300);
256 //Save newid to backup tables
257 if ($newid) {
258 //We have the newid, update backup_ids
259 backup_putid($restore->backup_unique_code,"quiz_questions",$oldid,
260 $newid);
262 //If it's a new question in the DB, restore it
263 if ($creatingnewquestion) {
264 //Now, restore every quiz_answers in this question
265 $status = quiz_restore_pre15_answers($oldid,$newid,$que_info,$restore);
266 //Now, depending of the type of questions, invoke different functions
267 if ($question->qtype == "1") {
268 $status = quiz_restore_pre15_shortanswer($oldid,$newid,$que_info,$restore);
269 } else if ($question->qtype == "2") {
270 $status = quiz_restore_pre15_truefalse($oldid,$newid,$que_info,$restore);
271 } else if ($question->qtype == "3") {
272 $status = quiz_restore_pre15_multichoice($oldid,$newid,$que_info,$restore);
273 } else if ($question->qtype == "4") {
274 //Random question. Nothing to do.
275 } else if ($question->qtype == "5") {
276 $status = quiz_restore_pre15_match($oldid,$newid,$que_info,$restore);
277 } else if ($question->qtype == "6") {
278 $status = quiz_restore_pre15_randomsamatch($oldid,$newid,$que_info,$restore);
279 } else if ($question->qtype == "7") {
280 //Description question. Nothing to do.
281 } else if ($question->qtype == "8") {
282 $status = quiz_restore_pre15_numerical($oldid,$newid,$que_info,$restore);
283 } else if ($question->qtype == "9") {
284 $status = quiz_restore_pre15_multianswer($oldid,$newid,$que_info,$restore);
285 } else if ($question->qtype == "10") {
286 $status = quiz_restore_pre15_calculated($oldid,$newid,$que_info,$restore);
288 } else {
289 //We are NOT creating the question, but we need to know every quiz_answers
290 //map between the XML file and the database to be able to restore the responses
291 //in each attempt.
292 $status = quiz_restore_pre15_map_answers($oldid,$newid,$que_info,$restore);
293 //Now, depending of the type of questions, invoke different functions
294 //to create the necessary mappings in backup_ids, because we are not
295 //creating the question, but need some records in backup table
296 if ($question->qtype == "1") {
297 //Shortanswer question. Nothing to remap
298 } else if ($question->qtype == "2") {
299 //Truefalse question. Nothing to remap
300 } else if ($question->qtype == "3") {
301 //Multichoice question. Nothing to remap
302 } else if ($question->qtype == "4") {
303 //Random question. Nothing to remap
304 } else if ($question->qtype == "5") {
305 $status = quiz_restore_pre15_map_match($oldid,$newid,$que_info,$restore);
306 } else if ($question->qtype == "6") {
307 //Randomsamatch question. Nothing to remap
308 } else if ($question->qtype == "7") {
309 //Description question. Nothing to remap
310 } else if ($question->qtype == "8") {
311 //Numerical question. Nothing to remap
312 } else if ($question->qtype == "9") {
313 //Multianswer question. Nothing to remap
314 } else if ($question->qtype == "10") {
315 //Calculated question. Nothing to remap
319 return $status;
322 function quiz_restore_pre15_answers ($old_question_id,$new_question_id,$info,$restore) {
324 global $CFG;
326 $status = true;
328 //Get the answers array
329 if (isset($info['#']['ANSWERS']['0']['#']['ANSWER'])) {
330 $answers = $info['#']['ANSWERS']['0']['#']['ANSWER'];
332 //Iterate over answers
333 for($i = 0; $i < sizeof($answers); $i++) {
334 $ans_info = $answers[$i];
335 //traverse_xmlize($ans_info); //Debug
336 //print_object ($GLOBALS['traverse_array']); //Debug
337 //$GLOBALS['traverse_array']=""; //Debug
339 //We'll need this later!!
340 $oldid = backup_todb($ans_info['#']['ID']['0']['#']);
342 //Now, build the QUIZ_ANSWERS record structure
343 $answer->question = $new_question_id;
344 $answer->answer = backup_todb($ans_info['#']['ANSWER_TEXT']['0']['#']);
345 $answer->fraction = backup_todb($ans_info['#']['FRACTION']['0']['#']);
346 $answer->feedback = backup_todb($ans_info['#']['FEEDBACK']['0']['#']);
348 //The structure is equal to the db, so insert the quiz_answers
349 $newid = insert_record ("quiz_answers",$answer);
351 //Do some output
352 if (($i+1) % 50 == 0) {
353 echo ".";
354 if (($i+1) % 1000 == 0) {
355 echo "<br />";
357 backup_flush(300);
360 if ($newid) {
361 //We have the newid, update backup_ids
362 backup_putid($restore->backup_unique_code,"quiz_answers",$oldid,
363 $newid);
364 } else {
365 $status = false;
370 return $status;
373 function quiz_restore_pre15_map_answers ($old_question_id,$new_question_id,$info,$restore) {
375 global $CFG;
377 $status = true;
379 if (!isset($info['#']['ANSWERS'])) { // No answers in this question (eg random)
380 return $status;
383 //Get the answers array
384 $answers = $info['#']['ANSWERS']['0']['#']['ANSWER'];
386 //Iterate over answers
387 for($i = 0; $i < sizeof($answers); $i++) {
388 $ans_info = $answers[$i];
389 //traverse_xmlize($ans_info); //Debug
390 //print_object ($GLOBALS['traverse_array']); //Debug
391 //$GLOBALS['traverse_array']=""; //Debug
393 //We'll need this later!!
394 $oldid = backup_todb($ans_info['#']['ID']['0']['#']);
396 //Now, build the QUIZ_ANSWERS record structure
397 $answer->question = $new_question_id;
398 $answer->answer = backup_todb($ans_info['#']['ANSWER_TEXT']['0']['#']);
399 $answer->fraction = backup_todb($ans_info['#']['FRACTION']['0']['#']);
400 $answer->feedback = backup_todb($ans_info['#']['FEEDBACK']['0']['#']);
402 //If we are in this method is because the question exists in DB, so its
403 //answers must exist too.
404 //Now, we are going to look for that answer in DB and to create the
405 //mappings in backup_ids to use them later where restoring responses (user level).
407 //Get the answer from DB (by question, answer and fraction)
408 $db_answer = get_record ("quiz_answers","question",$new_question_id,
409 "answer",$answer->answer,
410 "fraction",$answer->fraction);
412 //Do some output
413 if (($i+1) % 50 == 0) {
414 echo ".";
415 if (($i+1) % 1000 == 0) {
416 echo "<br />";
418 backup_flush(300);
421 if ($db_answer) {
422 //We have the database answer, update backup_ids
423 backup_putid($restore->backup_unique_code,"quiz_answers",$oldid,
424 $db_answer->id);
425 } else {
426 $status = false;
430 return $status;
433 function quiz_restore_pre15_shortanswer ($old_question_id,$new_question_id,$info,$restore,$restrictto = '') {
435 global $CFG;
437 $status = true;
439 //Get the shortanswers array
440 $shortanswers = $info['#']['SHORTANSWER'];
442 //Iterate over shortanswers
443 for($i = 0; $i < sizeof($shortanswers); $i++) {
444 $sho_info = $shortanswers[$i];
445 //traverse_xmlize($sho_info); //Debug
446 //print_object ($GLOBALS['traverse_array']); //Debug
447 //$GLOBALS['traverse_array']=""; //Debug
449 //Now, build the QUIZ_SHORTANSWER record structure
450 $shortanswer->question = $new_question_id;
451 $shortanswer->answers = backup_todb($sho_info['#']['ANSWERS']['0']['#']);
452 $shortanswer->usecase = backup_todb($sho_info['#']['USECASE']['0']['#']);
454 //We have to recode the answers field (a list of answers id)
455 //Extracts answer id from sequence
456 $answers_field = "";
457 $in_first = true;
458 $tok = strtok($shortanswer->answers,",");
459 while ($tok) {
460 //Get the answer from backup_ids
461 $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$tok);
462 if ($answer) {
463 if ($in_first) {
464 $answers_field .= $answer->new_id;
465 $in_first = false;
466 } else {
467 $answers_field .= ",".$answer->new_id;
470 //check for next
471 $tok = strtok(",");
473 //We have the answers field recoded to its new ids
474 $shortanswer->answers = $answers_field;
476 //The structure is equal to the db, so insert the quiz_shortanswer
477 //Only if there aren't restrictions or there are restriction concordance
478 if (empty($restrictto) || (!empty($restrictto) && $shortanswer->answers == $restrictto)) {
479 $newid = insert_record ("quiz_shortanswer",$shortanswer);
482 //Do some output
483 if (($i+1) % 50 == 0) {
484 echo ".";
485 if (($i+1) % 1000 == 0) {
486 echo "<br />";
488 backup_flush(300);
491 if (!$newid && !$restrictto) {
492 $status = false;
496 return $status;
499 function quiz_restore_pre15_truefalse ($old_question_id,$new_question_id,$info,$restore) {
501 global $CFG;
503 $status = true;
505 //Get the truefalse array
506 $truefalses = $info['#']['TRUEFALSE'];
508 //Iterate over truefalse
509 for($i = 0; $i < sizeof($truefalses); $i++) {
510 $tru_info = $truefalses[$i];
511 //traverse_xmlize($tru_info); //Debug
512 //print_object ($GLOBALS['traverse_array']); //Debug
513 //$GLOBALS['traverse_array']=""; //Debug
515 //Now, build the QUIZ_TRUEFALSE record structure
516 $truefalse->question = $new_question_id;
517 $truefalse->trueanswer = backup_todb($tru_info['#']['TRUEANSWER']['0']['#']);
518 $truefalse->falseanswer = backup_todb($tru_info['#']['FALSEANSWER']['0']['#']);
520 ////We have to recode the trueanswer field
521 $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$truefalse->trueanswer);
522 if ($answer) {
523 $truefalse->trueanswer = $answer->new_id;
526 ////We have to recode the falseanswer field
527 $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$truefalse->falseanswer);
528 if ($answer) {
529 $truefalse->falseanswer = $answer->new_id;
532 //The structure is equal to the db, so insert the quiz_truefalse
533 $newid = insert_record ("quiz_truefalse",$truefalse);
535 //Do some output
536 if (($i+1) % 50 == 0) {
537 echo ".";
538 if (($i+1) % 1000 == 0) {
539 echo "<br />";
541 backup_flush(300);
544 if (!$newid) {
545 $status = false;
549 return $status;
552 function quiz_restore_pre15_multichoice ($old_question_id,$new_question_id,$info,$restore, $restrictto = '') {
554 global $CFG;
556 $status = true;
558 //Get the multichoices array
559 $multichoices = $info['#']['MULTICHOICE'];
561 //Iterate over multichoices
562 for($i = 0; $i < sizeof($multichoices); $i++) {
563 $mul_info = $multichoices[$i];
564 //traverse_xmlize($mul_info); //Debug
565 //print_object ($GLOBALS['traverse_array']); //Debug
566 //$GLOBALS['traverse_array']=""; //Debug
568 //Now, build the QUIZ_MULTICHOICE record structure
569 $multichoice->question = $new_question_id;
570 $multichoice->layout = backup_todb($mul_info['#']['LAYOUT']['0']['#']);
571 $multichoice->answers = backup_todb($mul_info['#']['ANSWERS']['0']['#']);
572 $multichoice->single = backup_todb($mul_info['#']['SINGLE']['0']['#']);
574 //We have to recode the answers field (a list of answers id)
575 //Extracts answer id from sequence
576 $answers_field = "";
577 $in_first = true;
578 $tok = strtok($multichoice->answers,",");
579 while ($tok) {
580 //Get the answer from backup_ids
581 $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$tok);
582 if ($answer) {
583 if ($in_first) {
584 $answers_field .= $answer->new_id;
585 $in_first = false;
586 } else {
587 $answers_field .= ",".$answer->new_id;
590 //check for next
591 $tok = strtok(",");
593 //We have the answers field recoded to its new ids
594 $multichoice->answers = $answers_field;
596 //The structure is equal to the db, so insert the quiz_shortanswer
597 //Only if there aren't restrictions or there are restriction concordance
598 if (empty($restrictto) || (!empty($restrictto) && $multichoice->answers == $restrictto)) {
599 $newid = insert_record ("quiz_multichoice",$multichoice);
602 //Do some output
603 if (($i+1) % 50 == 0) {
604 echo ".";
605 if (($i+1) % 1000 == 0) {
606 echo "<br />";
608 backup_flush(300);
611 if (!$newid && !$restrictto) {
612 $status = false;
616 return $status;
619 function quiz_restore_pre15_match ($old_question_id,$new_question_id,$info,$restore) {
621 global $CFG;
623 $status = true;
625 //Get the matchs array
626 $matchs = $info['#']['MATCHS']['0']['#']['MATCH'];
628 //We have to build the subquestions field (a list of match_sub id)
629 $subquestions_field = "";
630 $in_first = true;
632 //Iterate over matchs
633 for($i = 0; $i < sizeof($matchs); $i++) {
634 $mat_info = $matchs[$i];
635 //traverse_xmlize($mat_info); //Debug
636 //print_object ($GLOBALS['traverse_array']); //Debug
637 //$GLOBALS['traverse_array']=""; //Debug
639 //We'll need this later!!
640 $oldid = backup_todb($mat_info['#']['ID']['0']['#']);
642 //Now, build the QUIZ_MATCH_SUB record structure
643 $match_sub->question = $new_question_id;
644 $match_sub->questiontext = backup_todb($mat_info['#']['QUESTIONTEXT']['0']['#']);
645 $match_sub->answertext = backup_todb($mat_info['#']['ANSWERTEXT']['0']['#']);
647 //The structure is equal to the db, so insert the quiz_match_sub
648 $newid = insert_record ("quiz_match_sub",$match_sub);
650 //Do some output
651 if (($i+1) % 50 == 0) {
652 echo ".";
653 if (($i+1) % 1000 == 0) {
654 echo "<br />";
656 backup_flush(300);
659 if ($newid) {
660 //We have the newid, update backup_ids
661 backup_putid($restore->backup_unique_code,"quiz_match_sub",$oldid,
662 $newid);
663 //We have a new match_sub, append it to subquestions_field
664 if ($in_first) {
665 $subquestions_field .= $newid;
666 $in_first = false;
667 } else {
668 $subquestions_field .= ",".$newid;
670 } else {
671 $status = false;
675 //We have created every match_sub, now create the match
676 $match->question = $new_question_id;
677 $match->subquestions = $subquestions_field;
679 //The structure is equal to the db, so insert the quiz_match_sub
680 $newid = insert_record ("quiz_match",$match);
682 if (!$newid) {
683 $status = false;
686 return $status;
689 function quiz_restore_pre15_map_match ($old_question_id,$new_question_id,$info,$restore) {
691 global $CFG;
693 $status = true;
695 //Get the matchs array
696 $matchs = $info['#']['MATCHS']['0']['#']['MATCH'];
698 //We have to build the subquestions field (a list of match_sub id)
699 $subquestions_field = "";
700 $in_first = true;
702 //Iterate over matchs
703 for($i = 0; $i < sizeof($matchs); $i++) {
704 $mat_info = $matchs[$i];
705 //traverse_xmlize($mat_info); //Debug
706 //print_object ($GLOBALS['traverse_array']); //Debug
707 //$GLOBALS['traverse_array']=""; //Debug
709 //We'll need this later!!
710 $oldid = backup_todb($mat_info['#']['ID']['0']['#']);
712 //Now, build the QUIZ_MATCH_SUB record structure
713 $match_sub->question = $new_question_id;
714 $match_sub->questiontext = backup_todb($mat_info['#']['QUESTIONTEXT']['0']['#']);
715 $match_sub->answertext = backup_todb($mat_info['#']['ANSWERTEXT']['0']['#']);
717 //If we are in this method is because the question exists in DB, so its
718 //match_sub must exist too.
719 //Now, we are going to look for that match_sub in DB and to create the
720 //mappings in backup_ids to use them later where restoring responses (user level).
722 //Get the match_sub from DB (by question, questiontext and answertext)
723 $db_match_sub = get_record ("quiz_match_sub","question",$new_question_id,
724 "questiontext",$match_sub->questiontext,
725 "answertext",$match_sub->answertext);
726 //Do some output
727 if (($i+1) % 50 == 0) {
728 echo ".";
729 if (($i+1) % 1000 == 0) {
730 echo "<br />";
732 backup_flush(300);
735 //We have the database match_sub, so update backup_ids
736 if ($db_match_sub) {
737 //We have the newid, update backup_ids
738 backup_putid($restore->backup_unique_code,"quiz_match_sub",$oldid,
739 $db_match_sub->id);
740 } else {
741 $status = false;
745 return $status;
748 function quiz_restore_pre15_randomsamatch ($old_question_id,$new_question_id,$info,$restore) {
750 global $CFG;
752 $status = true;
754 //Get the randomsamatchs array
755 $randomsamatchs = $info['#']['RANDOMSAMATCH'];
757 //Iterate over randomsamatchs
758 for($i = 0; $i < sizeof($randomsamatchs); $i++) {
759 $ran_info = $randomsamatchs[$i];
760 //traverse_xmlize($ran_info); //Debug
761 //print_object ($GLOBALS['traverse_array']); //Debug
762 //$GLOBALS['traverse_array']=""; //Debug
764 //Now, build the QUIZ_RANDOMSAMATCH record structure
765 $randomsamatch->question = $new_question_id;
766 $randomsamatch->choose = backup_todb($ran_info['#']['CHOOSE']['0']['#']);
768 //The structure is equal to the db, so insert the quiz_randomsamatch
769 $newid = insert_record ("quiz_randomsamatch",$randomsamatch);
771 //Do some output
772 if (($i+1) % 50 == 0) {
773 echo ".";
774 if (($i+1) % 1000 == 0) {
775 echo "<br />";
777 backup_flush(300);
780 if (!$newid) {
781 $status = false;
785 return $status;
788 function quiz_restore_pre15_numerical ($old_question_id,$new_question_id,$info,$restore, $restrictto = '') {
790 global $CFG;
792 $status = true;
794 //Get the numerical array
795 $numericals = $info['#']['NUMERICAL'];
797 //Iterate over numericals
798 for($i = 0; $i < sizeof($numericals); $i++) {
799 $num_info = $numericals[$i];
800 //traverse_xmlize($num_info); //Debug
801 //print_object ($GLOBALS['traverse_array']); //Debug
802 //$GLOBALS['traverse_array']=""; //Debug
804 //Now, build the QUIZ_NUMERICAL record structure
805 $numerical->question = $new_question_id;
806 $numerical->answer = backup_todb($num_info['#']['ANSWER']['0']['#']);
807 $numerical->min = backup_todb($num_info['#']['MIN']['0']['#']);
808 $numerical->max = backup_todb($num_info['#']['MAX']['0']['#']);
810 ////We have to recode the answer field
811 $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$numerical->answer);
812 if ($answer) {
813 $numerical->answer = $answer->new_id;
816 //Answer goes to answers in 1.5 (although it continues being only one!)
817 //Changed 12-05 (chating with Gustav and Julian this remains = pre15 = answer)
818 //$numerical->answers = $numerical->answer;
820 //We have to calculate the tolerance field of the numerical question
821 $numerical->tolerance = ($numerical->max - $numerical->min)/2;
823 //The structure is equal to the db, so insert the quiz_numerical
824 //Only if there aren't restrictions or there are restriction concordance
825 if (empty($restrictto) || (!empty($restrictto) && in_array($numerical->answer,explode(",",$restrictto)))) {
826 $newid = insert_record ("quiz_numerical",$numerical);
829 //Do some output
830 if (($i+1) % 50 == 0) {
831 echo ".";
832 if (($i+1) % 1000 == 0) {
833 echo "<br />";
835 backup_flush(300);
838 //Now restore numerical_units
839 if ($newid) {
840 $status = quiz_restore_pre15_numerical_units ($old_question_id,$new_question_id,$num_info,$restore);
843 if (!$newid && !$restrictto) {
844 $status = false;
848 return $status;
851 function quiz_restore_pre15_calculated ($old_question_id,$new_question_id,$info,$restore) {
853 global $CFG;
855 $status = true;
857 //Get the calculated-s array
858 $calculateds = $info['#']['CALCULATED'];
860 //Iterate over calculateds
861 for($i = 0; $i < sizeof($calculateds); $i++) {
862 $cal_info = $calculateds[$i];
863 //traverse_xmlize($cal_info); //Debug
864 //print_object ($GLOBALS['traverse_array']); //Debug
865 //$GLOBALS['traverse_array']=""; //Debug
867 //Now, build the QUIZ_CALCULATED record structure
868 $calculated->question = $new_question_id;
869 $calculated->answer = backup_todb($cal_info['#']['ANSWER']['0']['#']);
870 $calculated->tolerance = backup_todb($cal_info['#']['TOLERANCE']['0']['#']);
871 $calculated->tolerancetype = backup_todb($cal_info['#']['TOLERANCETYPE']['0']['#']);
872 $calculated->correctanswerlength = backup_todb($cal_info['#']['CORRECTANSWERLENGTH']['0']['#']);
873 $calculated->correctanswerformat = backup_todb($cal_info['#']['CORRECTANSWERFORMAT']['0']['#']);
875 ////We have to recode the answer field
876 $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$calculated->answer);
877 if ($answer) {
878 $calculated->answer = $answer->new_id;
881 //If we haven't correctanswerformat, it defaults to 2 (in DB)
882 if (empty($calculated->correctanswerformat)) {
883 $calculated->correctanswerformat = 2;
886 //The structure is equal to the db, so insert the quiz_calculated
887 $newid = insert_record ("quiz_calculated",$calculated);
889 //Do some output
890 if (($i+1) % 50 == 0) {
891 echo ".";
892 if (($i+1) % 1000 == 0) {
893 echo "<br />";
895 backup_flush(300);
898 //Now restore numerical_units
899 $status = quiz_restore_pre15_numerical_units ($old_question_id,$new_question_id,$cal_info,$restore);
901 //Now restore dataset_definitions
902 if ($status && $newid) {
903 $status = quiz_restore_pre15_dataset_definitions ($old_question_id,$new_question_id,$cal_info,$restore);
906 if (!$newid) {
907 $status = false;
911 return $status;
914 function quiz_restore_pre15_multianswer ($old_question_id,$new_question_id,$info,$restore) {
916 global $CFG;
918 $status = true;
920 //We need some question fields here so we get the full record from DB
921 $parentquestion = get_record('quiz_questions','id',$new_question_id);
923 //We need to store all the positions with their created questions
924 //to be able to calculate the sequence field
925 $createdquestions = array();
927 //Under 1.5, every multianswer record becomes a question itself
928 //with its parent set to the cloze question. And there is only
929 //ONE multianswer record with the sequence of questions used.
931 //Get the multianswers array
932 $multianswers_array = $info['#']['MULTIANSWERS']['0']['#']['MULTIANSWER'];
933 //Iterate over multianswers_array
934 for($i = 0; $i < sizeof($multianswers_array); $i++) {
935 $mul_info = $multianswers_array[$i];
936 //traverse_xmlize($mul_info); //Debug
937 //print_object ($GLOBALS['traverse_array']); //Debug
938 //$GLOBALS['traverse_array']=""; //Debug
940 //We need this later
941 $oldid = backup_todb($mul_info['#']['ID']['0']['#']);
943 //Now, build the QUIZ_MULTIANSWER record structure
944 $multianswer->question = $new_question_id;
945 $multianswer->answers = backup_todb($mul_info['#']['ANSWERS']['0']['#']);
946 $multianswer->positionkey = backup_todb($mul_info['#']['POSITIONKEY']['0']['#']);
947 $multianswer->answertype = backup_todb($mul_info['#']['ANSWERTYPE']['0']['#']);
948 $multianswer->norm = backup_todb($mul_info['#']['NORM']['0']['#']);
950 //Saving multianswer and positionkey to use them later restoring states
951 backup_putid ($restore->backup_unique_code,'multianswer-pos',$oldid,$multianswer->positionkey);
953 //We have to recode all the answers to their new ids
954 $ansarr = explode(",", $multianswer->answers);
955 foreach ($ansarr as $key => $value) {
956 //Get the answer from backup_ids
957 $answer = backup_getid($restore->backup_unique_code,'quiz_answers',$value);
958 $ansarr[$key] = $answer->new_id;
960 $multianswer->answers = implode(",",$ansarr);
962 //Build the new question structure
963 $question = new object;
964 $question->category = $parentquestion->category;
965 $question->parent = $parentquestion->id;
966 $question->name = $parentquestion->name;
967 $question->questiontextformat = $parentquestion->questiontextformat;
968 $question->defaultgrade = $multianswer->norm;
969 $question->penalty = $parentquestion->penalty;
970 $question->qtype = $multianswer->answertype;
971 $question->version = $parentquestion->version;
972 $question->hidden = $parentquestion->hidden;
973 $question->length = 0;
974 $question->questiontext = '';
975 $question->stamp = make_unique_id_code();
977 //Save the new question to DB
978 $newid = insert_record('quiz_questions', $question);
980 if ($newid) {
981 $createdquestions[$multianswer->positionkey] = $newid;
984 //Do some output
985 if (($i+1) % 50 == 0) {
986 echo ".";
987 if (($i+1) % 1000 == 0) {
988 echo "<br />";
990 backup_flush(300);
993 //Remap quiz_answers records from the original multianswer question
994 //to their newly created question
995 if ($newid) {
996 $answersdb = get_records_list('quiz_answers','id',$multianswer->answers);
997 foreach ($answersdb as $answerdb) {
998 set_field('quiz_answers','question',$newid,'id',$answerdb->id);
1002 //If we have created the quiz_questions record, now, depending of the
1003 //answertype, delegate the restore to every qtype function
1004 if ($newid) {
1005 if ($multianswer->answertype == "1") {
1006 $status = quiz_restore_pre15_shortanswer ($old_question_id,$newid,$mul_info,$restore,$multianswer->answers);
1007 } else if ($multianswer->answertype == "3") {
1008 $status = quiz_restore_pre15_multichoice ($old_question_id,$newid,$mul_info,$restore,$multianswer->answers);
1009 } else if ($multianswer->answertype == "8") {
1010 $status = quiz_restore_pre15_numerical ($old_question_id,$newid,$mul_info,$restore,$multianswer->answers);
1012 } else {
1013 $status = false;
1017 //Everything is created, just going to create the multianswer record
1018 if ($status) {
1019 ksort($createdquestions);
1021 $multianswerdb = new object;
1022 $multianswerdb->question = $parentquestion->id;
1023 $multianswerdb->sequence = implode(",",$createdquestions);
1024 $mid = insert_record('quiz_multianswers', $multianswerdb);
1026 if (!$mid) {
1027 $status = false;
1031 return $status;
1034 function quiz_restore_pre15_numerical_units ($old_question_id,$new_question_id,$info,$restore) {
1036 global $CFG;
1038 $status = true;
1040 //Get the numerical array
1041 $numerical_units = $info['#']['NUMERICAL_UNITS']['0']['#']['NUMERICAL_UNIT'];
1043 //Iterate over numerical_units
1044 for($i = 0; $i < sizeof($numerical_units); $i++) {
1045 $nu_info = $numerical_units[$i];
1046 //traverse_xmlize($nu_info); //Debug
1047 //print_object ($GLOBALS['traverse_array']); //Debug
1048 //$GLOBALS['traverse_array']=""; //Debug
1050 //Now, build the QUIZ_NUMERICAL_UNITS record structure
1051 $numerical_unit->question = $new_question_id;
1052 $numerical_unit->multiplier = backup_todb($nu_info['#']['MULTIPLIER']['0']['#']);
1053 $numerical_unit->unit = backup_todb($nu_info['#']['UNIT']['0']['#']);
1055 //The structure is equal to the db, so insert the quiz_numerical_units
1056 $newid = insert_record ("quiz_numerical_units",$numerical_unit);
1058 if (!$newid) {
1059 $status = false;
1063 return $status;
1066 function quiz_restore_pre15_dataset_definitions ($old_question_id,$new_question_id,$info,$restore) {
1068 global $CFG;
1070 $status = true;
1072 //Get the dataset_definitions array
1073 $dataset_definitions = $info['#']['DATASET_DEFINITIONS']['0']['#']['DATASET_DEFINITION'];
1075 //Iterate over dataset_definitions
1076 for($i = 0; $i < sizeof($dataset_definitions); $i++) {
1077 $dd_info = $dataset_definitions[$i];
1078 //traverse_xmlize($dd_info); //Debug
1079 //print_object ($GLOBALS['traverse_array']); //Debug
1080 //$GLOBALS['traverse_array']=""; //Debug
1082 //Now, build the QUIZ_DATASET_DEFINITION record structure
1083 $dataset_definition->category = backup_todb($dd_info['#']['CATEGORY']['0']['#']);
1084 $dataset_definition->name = backup_todb($dd_info['#']['NAME']['0']['#']);
1085 $dataset_definition->type = backup_todb($dd_info['#']['TYPE']['0']['#']);
1086 $dataset_definition->options = backup_todb($dd_info['#']['OPTIONS']['0']['#']);
1087 $dataset_definition->itemcount = backup_todb($dd_info['#']['ITEMCOUNT']['0']['#']);
1089 //We have to recode the category field (only if the category != 0)
1090 if ($dataset_definition->category != 0) {
1091 $category = backup_getid($restore->backup_unique_code,"quiz_categories",$dataset_definition->category);
1092 if ($category) {
1093 $dataset_definition->category = $category->new_id;
1097 //Now, we hace to decide when to create the new records or reuse an existing one
1098 $create_definition = false;
1100 //If the dataset_definition->category = 0, it's a individual question dataset_definition, so we'll create it
1101 if ($dataset_definition->category == 0) {
1102 $create_definition = true;
1103 } else {
1104 //The category isn't 0, so it's a category question dataset_definition, we have to see if it exists
1105 //Look for a definition with the same category, name and type
1106 if ($definitionrec = get_record_sql("SELECT d.*
1107 FROM {$CFG->prefix}quiz_dataset_definitions d
1108 WHERE d.category = '$dataset_definition->category' AND
1109 d.name = '$dataset_definition->name' AND
1110 d.type = '$dataset_definition->type'")) {
1111 //Such dataset_definition exist. Now we must check if it has enough itemcount
1112 if ($definitionrec->itemcount < $dataset_definition->itemcount) {
1113 //We haven't enough itemcount, so we have to create the definition as an individual question one.
1114 $dataset_definition->category = 0;
1115 $create_definition = true;
1116 } else {
1117 //We have enough itemcount, so we'll reuse the existing definition
1118 $create_definition = false;
1119 $newid = $definitionrec->id;
1121 } else {
1122 //Such dataset_definition doesn't exist. We'll create it.
1123 $create_definition = true;
1127 //If we've to create the definition, do it
1128 if ($create_definition) {
1129 //The structure is equal to the db, so insert the quiz_dataset_definitions
1130 $newid = insert_record ("quiz_dataset_definitions",$dataset_definition);
1131 if ($newid) {
1132 //Restore quiz_dataset_items
1133 $status = quiz_restore_pre15_dataset_items($newid,$dd_info,$restore);
1137 //Now, we must have a definition (created o reused). Its id is in newid. Create the quiz_question_datasets record
1138 //to join the question and the dataset_definition
1139 if ($newid) {
1140 $question_dataset->question = $new_question_id;
1141 $question_dataset->datasetdefinition = $newid;
1142 $newid = insert_record ("quiz_question_datasets",$question_dataset);
1145 if (!$newid) {
1146 $status = false;
1150 return $status;
1153 function quiz_restore_pre15_dataset_items ($definitionid,$info,$restore) {
1155 global $CFG;
1157 $status = true;
1159 //Get the items array
1160 $dataset_items = $info['#']['DATASET_ITEMS']['0']['#']['DATASET_ITEM'];
1162 //Iterate over dataset_items
1163 for($i = 0; $i < sizeof($dataset_items); $i++) {
1164 $di_info = $dataset_items[$i];
1165 //traverse_xmlize($di_info); //Debug
1166 //print_object ($GLOBALS['traverse_array']); //Debug
1167 //$GLOBALS['traverse_array']=""; //Debug
1169 //Now, build the QUIZ_DATASET_ITEMS record structure
1170 $dataset_item->definition = $definitionid;
1171 $dataset_item->number = backup_todb($di_info['#']['NUMBER']['0']['#']);
1172 $dataset_item->value = backup_todb($di_info['#']['VALUE']['0']['#']);
1174 //The structure is equal to the db, so insert the quiz_dataset_items
1175 $newid = insert_record ("quiz_dataset_items",$dataset_item);
1177 if (!$newid) {
1178 $status = false;
1182 return $status;
1185 //STEP 2. Restore quizzes and associated structures
1186 // (course dependent)
1187 function quiz_restore_pre15_mods($mod,$restore) {
1189 global $CFG;
1191 $status = true;
1193 //Get record from backup_ids
1194 $data = backup_getid($restore->backup_unique_code,$mod->modtype,$mod->id);
1196 if ($data) {
1197 //Now get completed xmlized object
1198 $info = $data->info;
1199 //traverse_xmlize($info); //Debug
1200 //print_object ($GLOBALS['traverse_array']); //Debug
1201 //$GLOBALS['traverse_array']=""; //Debug
1203 //Now, build the QUIZ record structure
1204 $quiz->course = $restore->course_id;
1205 $quiz->name = backup_todb($info['MOD']['#']['NAME']['0']['#']);
1206 $quiz->intro = backup_todb($info['MOD']['#']['INTRO']['0']['#']);
1207 $quiz->timeopen = backup_todb($info['MOD']['#']['TIMEOPEN']['0']['#']);
1208 $quiz->timeclose = backup_todb($info['MOD']['#']['TIMECLOSE']['0']['#']);
1209 $quiz->attempts = backup_todb($info['MOD']['#']['ATTEMPTS_NUMBER']['0']['#']);
1210 $quiz->attemptonlast = backup_todb($info['MOD']['#']['ATTEMPTONLAST']['0']['#']);
1211 $quiz->feedback = backup_todb($info['MOD']['#']['FEEDBACK']['0']['#']);
1212 $quiz->correctanswers = backup_todb($info['MOD']['#']['CORRECTANSWERS']['0']['#']);
1213 $quiz->grademethod = backup_todb($info['MOD']['#']['GRADEMETHOD']['0']['#']);
1214 if (isset($info['MOD']['#']['DECIMALPOINTS']['0']['#'])) { //Only if it's set, to apply DB default else.
1215 $quiz->decimalpoints = backup_todb($info['MOD']['#']['DECIMALPOINTS']['0']['#']);
1217 $quiz->review = backup_todb($info['MOD']['#']['REVIEW']['0']['#']);
1218 $quiz->questionsperpage = backup_todb($info['MOD']['#']['QUESTIONSPERPAGE']['0']['#']);
1219 $quiz->shufflequestions = backup_todb($info['MOD']['#']['SHUFFLEQUESTIONS']['0']['#']);
1220 $quiz->shuffleanswers = backup_todb($info['MOD']['#']['SHUFFLEANSWERS']['0']['#']);
1221 $quiz->questions = backup_todb($info['MOD']['#']['QUESTIONS']['0']['#']);
1222 $quiz->sumgrades = backup_todb($info['MOD']['#']['SUMGRADES']['0']['#']);
1223 $quiz->grade = backup_todb($info['MOD']['#']['GRADE']['0']['#']);
1224 $quiz->timecreated = backup_todb($info['MOD']['#']['TIMECREATED']['0']['#']);
1225 $quiz->timemodified = backup_todb($info['MOD']['#']['TIMEMODIFIED']['0']['#']);
1226 $quiz->timelimit = backup_todb($info['MOD']['#']['TIMELIMIT']['0']['#']);
1227 $quiz->password = backup_todb($info['MOD']['#']['PASSWORD']['0']['#']);
1228 $quiz->subnet = backup_todb($info['MOD']['#']['SUBNET']['0']['#']);
1229 $quiz->popup = backup_todb($info['MOD']['#']['POPUP']['0']['#']);
1231 //We have to recode the questions field (a list of questions id)
1232 $newquestions = array();
1233 if ($questionsarr = explode (",",$quiz->questions)) {
1234 foreach ($questionsarr as $key => $value) {
1235 if ($question = backup_getid($restore->backup_unique_code,"quiz_questions",$value)) {
1236 $newquestions[] = $question->new_id;
1240 $quiz->questions = implode (",", $newquestions);
1242 //Recalculate the questions field to include page breaks if necessary
1243 $quiz->questions = quiz_repaginate($quiz->questions, $quiz->questionsperpage);
1245 //Calculate the new review field contents (logic extracted from upgrade)
1246 $review = (QUIZ_REVIEW_IMMEDIATELY & (QUIZ_REVIEW_RESPONSES + QUIZ_REVIEW_SCORES));
1247 if ($quiz->feedback) {
1248 $review += (QUIZ_REVIEW_IMMEDIATELY & QUIZ_REVIEW_FEEDBACK);
1250 if ($quiz->correctanswers) {
1251 $review += (QUIZ_REVIEW_IMMEDIATELY & QUIZ_REVIEW_ANSWERS);
1253 if ($quiz->review & 1) {
1254 $review += QUIZ_REVIEW_CLOSED;
1256 if ($quiz->review & 2) {
1257 $review += QUIZ_REVIEW_OPEN;
1259 $quiz->review = $review;
1261 //The structure is equal to the db, so insert the quiz
1262 $newid = insert_record ("quiz",$quiz);
1264 //Do some output
1265 echo "<li>".get_string("modulename","quiz")." \"".format_string(stripslashes($quiz->name),true)."\"</li>";
1266 backup_flush(300);
1268 if ($newid) {
1269 //We have the newid, update backup_ids
1270 backup_putid($restore->backup_unique_code,$mod->modtype,
1271 $mod->id, $newid);
1272 //We have to restore the quiz_question_instances now (old quiz_question_grades, course level)
1273 $status = quiz_question_instances_restore_pre15_mods($newid,$info,$restore);
1274 //We have to restore the question_versions now (course level table)
1275 $status = quiz_question_versions_restore_pre15_mods($newid,$info,$restore);
1276 //Now check if want to restore user data and do it.
1277 if ($restore->mods['quiz']->userinfo) {
1278 //Restore quiz_attempts
1279 $status = quiz_attempts_restore_pre15_mods ($newid,$info,$restore, $quiz->questions);
1280 if ($status) {
1281 //Restore quiz_grades
1282 $status = quiz_grades_restore_pre15_mods ($newid,$info,$restore);
1285 } else {
1286 $status = false;
1288 } else {
1289 $status = false;
1292 return $status;
1295 //This function restores the quiz_question_instances (old quiz_question_grades)
1296 function quiz_question_instances_restore_pre15_mods($quiz_id,$info,$restore) {
1298 global $CFG;
1300 $status = true;
1302 //Get the quiz_question_grades array
1303 $grades = $info['MOD']['#']['QUESTION_GRADES']['0']['#']['QUESTION_GRADE'];
1305 //Iterate over question_grades
1306 for($i = 0; $i < sizeof($grades); $i++) {
1307 $gra_info = $grades[$i];
1308 //traverse_xmlize($gra_info); //Debug
1309 //print_object ($GLOBALS['traverse_array']); //Debug
1310 //$GLOBALS['traverse_array']=""; //Debug
1312 //We'll need this later!!
1313 $oldid = backup_todb($gra_info['#']['ID']['0']['#']);
1315 //Now, build the QUESTION_GRADES record structure
1316 $grade->quiz = $quiz_id;
1317 $grade->question = backup_todb($gra_info['#']['QUESTION']['0']['#']);
1318 $grade->grade = backup_todb($gra_info['#']['GRADE']['0']['#']);
1320 //We have to recode the question field
1321 $question = backup_getid($restore->backup_unique_code,"quiz_questions",$grade->question);
1322 if ($question) {
1323 $grade->question = $question->new_id;
1326 //The structure is equal to the db, so insert the quiz_question_grades
1327 $newid = insert_record ("quiz_question_instances",$grade);
1329 //Do some output
1330 if (($i+1) % 10 == 0) {
1331 echo ".";
1332 if (($i+1) % 200 == 0) {
1333 echo "<br />";
1335 backup_flush(300);
1338 if ($newid) {
1339 //We have the newid, update backup_ids
1340 backup_putid($restore->backup_unique_code,"quiz_question_instances",$oldid,
1341 $newid);
1342 } else {
1343 $status = false;
1347 return $status;
1350 //This function restores the quiz_question_versions
1351 function quiz_question_versions_restore_pre15_mods($quiz_id,$info,$restore) {
1353 global $CFG, $USER;
1355 $status = true;
1357 //Get the quiz_question_versions array
1358 $versions = $info['MOD']['#']['QUESTION_VERSIONS']['0']['#']['QUESTION_VERSION'];
1360 //Iterate over question_versions
1361 for($i = 0; $i < sizeof($versions); $i++) {
1362 $ver_info = $versions[$i];
1363 //traverse_xmlize($ver_info); //Debug
1364 //print_object ($GLOBALS['traverse_array']); //Debug
1365 //$GLOBALS['traverse_array']=""; //Debug
1367 //We'll need this later!!
1368 $oldid = backup_todb($ver_info['#']['ID']['0']['#']);
1370 //Now, build the QUESTION_VERSIONS record structure
1371 $version->quiz = $quiz_id;
1372 $version->oldquestion = backup_todb($ver_info['#']['OLDQUESTION']['0']['#']);
1373 $version->newquestion = backup_todb($ver_info['#']['NEWQUESTION']['0']['#']);
1374 $version->userid = backup_todb($ver_info['#']['USERID']['0']['#']);
1375 $version->timestamp = backup_todb($ver_info['#']['TIMESTAMP']['0']['#']);
1377 //We have to recode the oldquestion field
1378 $question = backup_getid($restore->backup_unique_code,"quiz_questions",$version->oldquestion);
1379 if ($question) {
1380 $version->oldquestion = $question->new_id;
1383 //We have to recode the newquestion field
1384 $question = backup_getid($restore->backup_unique_code,"quiz_questions",$version->newquestion);
1385 if ($question) {
1386 $version->newquestion = $question->new_id;
1389 //We have to recode the userid field
1390 $user = backup_getid($restore->backup_unique_code,"user",$version->userid);
1391 if ($user) {
1392 $version->userid = $user->new_id;
1393 } else { //Assign to current user
1394 $version->userid = $USER->id;
1397 //The structure is equal to the db, so insert the quiz_question_versions
1398 $newid = insert_record ("quiz_question_versions",$version);
1400 //Do some output
1401 if (($i+1) % 10 == 0) {
1402 echo ".";
1403 if (($i+1) % 200 == 0) {
1404 echo "<br />";
1406 backup_flush(300);
1409 if ($newid) {
1410 //We have the newid, update backup_ids
1411 backup_putid($restore->backup_unique_code,"quiz_question_versions",$oldid,
1412 $newid);
1413 } else {
1414 $status = false;
1418 return $status;
1421 //This function restores the quiz_attempts
1422 function quiz_attempts_restore_pre15_mods($quiz_id,$info,$restore,$quizquestions) {
1424 global $CFG;
1426 $status = true;
1428 //Get the quiz_attempts array
1429 $attempts = $info['MOD']['#']['ATTEMPTS']['0']['#']['ATTEMPT'];
1431 //Iterate over attempts
1432 for($i = 0; $i < sizeof($attempts); $i++) {
1433 $att_info = $attempts[$i];
1434 //traverse_xmlize($att_info); //Debug
1435 //print_object ($GLOBALS['traverse_array']); //Debug
1436 //$GLOBALS['traverse_array']=""; //Debug
1438 //We'll need this later!!
1439 $oldid = backup_todb($att_info['#']['ID']['0']['#']);
1440 $olduserid = backup_todb($att_info['#']['USERID']['0']['#']);
1442 //Now, build the ATTEMPTS record structure
1443 $attempt->quiz = $quiz_id;
1444 $attempt->userid = backup_todb($att_info['#']['USERID']['0']['#']);
1445 $attempt->attempt = backup_todb($att_info['#']['ATTEMPTNUM']['0']['#']);
1446 $attempt->sumgrades = backup_todb($att_info['#']['SUMGRADES']['0']['#']);
1447 $attempt->timestart = backup_todb($att_info['#']['TIMESTART']['0']['#']);
1448 $attempt->timefinish = backup_todb($att_info['#']['TIMEFINISH']['0']['#']);
1449 $attempt->timemodified = backup_todb($att_info['#']['TIMEMODIFIED']['0']['#']);
1451 //We have to recode the userid field
1452 $user = backup_getid($restore->backup_unique_code,"user",$attempt->userid);
1453 if ($user) {
1454 $attempt->userid = $user->new_id;
1457 //Set the layout field (inherited from quiz by default)
1458 $attempt->layout = $quizquestions;
1460 //Set the preview field (code from upgrade)
1461 if (isteacher($restore->course_id,$attempt->userid)) {
1462 $attempt->preview = 1;
1466 //The structure is equal to the db, so insert the quiz_attempts
1467 $newid = insert_record ("quiz_attempts",$attempt);
1469 //Do some output
1470 if (($i+1) % 10 == 0) {
1471 echo ".";
1472 if (($i+1) % 200 == 0) {
1473 echo "<br />";
1475 backup_flush(300);
1478 if ($newid) {
1479 //We have the newid, update backup_ids
1480 backup_putid($restore->backup_unique_code,"quiz_attempts",$oldid,
1481 $newid);
1482 //Now process quiz_states (old quiz_responses table)
1483 $status = quiz_states_restore_pre15_mods($newid,$att_info,$restore);
1484 } else {
1485 $status = false;
1489 return $status;
1492 //This function restores the quiz_states (old quiz_responses)
1493 function quiz_states_restore_pre15_mods($attempt_id,$info,$restore) {
1495 global $CFG;
1497 $status = true;
1499 //Get the quiz_responses array
1500 $responses = $info['#']['RESPONSES']['0']['#']['RESPONSE'];
1501 //Iterate over responses
1502 for($i = 0; $i < sizeof($responses); $i++) {
1503 $res_info = $responses[$i];
1504 //traverse_xmlize($res_info); //Debug
1505 //print_object ($GLOBALS['traverse_array']); //Debug
1506 //$GLOBALS['traverse_array']=""; //Debug
1508 //We'll need this later!!
1509 $oldid = backup_todb($res_info['#']['ID']['0']['#']);
1511 //Now, build the RESPONSES record structure
1512 $response->attempt = $attempt_id;
1513 $response->question = backup_todb($res_info['#']['QUESTION']['0']['#']);
1514 $response->originalquestion = backup_todb($res_info['#']['ORIGINALQUESTION']['0']['#']);
1515 $response->answer = backup_todb($res_info['#']['ANSWER']['0']['#']);
1516 $response->grade = backup_todb($res_info['#']['GRADE']['0']['#']);
1518 //We have to recode the question field
1519 $question = backup_getid($restore->backup_unique_code,"quiz_questions",$response->question);
1520 if ($question) {
1521 $response->question = $question->new_id;
1524 //We have to recode the originalquestion field
1525 $question = backup_getid($restore->backup_unique_code,"quiz_questions",$response->originalquestion);
1526 if ($question) {
1527 $response->originalquestion = $question->new_id;
1530 //Set the raw_grade field (default to the existing grade one, no penalty in pre15 backups)
1531 $response->raw_grade = $response->grade;
1533 //We have to recode the answer field
1534 //It depends of the question type !!
1535 //We get the question first
1536 $question = get_record("quiz_questions","id",$response->question);
1537 //It exists
1538 if ($question) {
1539 //Depending of the qtype, we make different recodes
1540 switch ($question->qtype) {
1541 case 1: //SHORTANSWER QTYPE
1542 //Nothing to do. The response is a text.
1543 break;
1544 case 2: //TRUEFALSE QTYPE
1545 //The answer is one answer id. We must recode it
1546 $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$response->answer);
1547 if ($answer) {
1548 $response->answer = $answer->new_id;
1550 break;
1551 case 3: //MULTICHOICE QTYPE
1552 //The answer is a comma separated list of answers. We must recode them
1553 $answer_field = "";
1554 $in_first = true;
1555 $tok = strtok($response->answer,",");
1556 while ($tok) {
1557 //Get the answer from backup_ids
1558 $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$tok);
1559 if ($answer) {
1560 if ($in_first) {
1561 $answer_field .= $answer->new_id;
1562 $in_first = false;
1563 } else {
1564 $answer_field .= ",".$answer->new_id;
1567 //check for next
1568 $tok = strtok(",");
1570 $response->answer = $answer_field;
1571 break;
1572 case 4: //RANDOM QTYPE
1573 //The answer links to another question id, we must recode it
1574 $answer_link = backup_getid($restore->backup_unique_code,"quiz_questions",$response->answer);
1575 if ($answer_link) {
1576 $response->answer = $answer_link->new_id;
1578 break;
1579 case 5: //MATCH QTYPE
1580 //The answer is a comma separated list of hypen separated math_subs (for question and answer)
1581 $answer_field = "";
1582 $in_first = true;
1583 $tok = strtok($response->answer,",");
1584 while ($tok) {
1585 //Extract the match_sub for the question and the answer
1586 $exploded = explode("-",$tok);
1587 $match_question_id = $exploded[0];
1588 $match_answer_id = $exploded[1];
1589 //Get the match_sub from backup_ids (for the question)
1590 $match_que = backup_getid($restore->backup_unique_code,"quiz_match_sub",$match_question_id);
1591 //Get the match_sub from backup_ids (for the answer)
1592 $match_ans = backup_getid($restore->backup_unique_code,"quiz_match_sub",$match_answer_id);
1593 if ($match_que) {
1594 //It the question hasn't response, it must be 0
1595 if (!$match_ans and $match_answer_id == 0) {
1596 $match_ans->new_id = 0;
1598 if ($in_first) {
1599 $answer_field .= $match_que->new_id."-".$match_ans->new_id;
1600 $in_first = false;
1601 } else {
1602 $answer_field .= ",".$match_que->new_id."-".$match_ans->new_id;
1605 //check for next
1606 $tok = strtok(",");
1608 $response->answer = $answer_field;
1609 break;
1610 case 6: //RANDOMSAMATCH QTYPE
1611 //The answer is a comma separated list of hypen separated question_id and answer_id. We must recode them
1612 $answer_field = "";
1613 $in_first = true;
1614 $tok = strtok($response->answer,",");
1615 while ($tok) {
1616 //Extract the question_id and the answer_id
1617 $exploded = explode("-",$tok);
1618 $question_id = $exploded[0];
1619 $answer_id = $exploded[1];
1620 //Get the question from backup_ids
1621 $que = backup_getid($restore->backup_unique_code,"quiz_questions",$question_id);
1622 //Get the answer from backup_ids
1623 $ans = backup_getid($restore->backup_unique_code,"quiz_answers",$answer_id);
1624 if ($que) {
1625 //It the question hasn't response, it must be 0
1626 if (!$ans and $answer_id == 0) {
1627 $ans->new_id = 0;
1629 if ($in_first) {
1630 $answer_field .= $que->new_id."-".$ans->new_id;
1631 $in_first = false;
1632 } else {
1633 $answer_field .= ",".$que->new_id."-".$ans->new_id;
1636 //check for next
1637 $tok = strtok(",");
1639 $response->answer = $answer_field;
1640 break;
1641 case 7: //DESCRIPTION QTYPE
1642 //Nothing to do (there is no awser to this qtype)
1643 //But this case must exist !!
1644 break;
1645 case 8: //NUMERICAL QTYPE
1646 //Nothing to do. The response is a text.
1647 break;
1648 case 9: //MULTIANSWER QTYPE
1649 //The answer is a comma separated list of hypen separated multianswer ids and answers. We must recode them.
1650 //We need to have the sequence of questions here to be able to detect qtypes
1651 $multianswerdb = get_record('quiz_multianswers','question',$response->question);
1652 //Make an array of sequence to easy access
1653 $sequencearr = explode(",",$multianswerdb->sequence);
1654 $answer_field = "";
1655 $in_first = true;
1656 $tok = strtok($response->answer,",");
1657 $counter = 1;
1658 while ($tok) {
1659 //Extract the multianswer_id and the answer
1660 $exploded = explode("-",$tok);
1661 $multianswer_id = $exploded[0];
1662 $answer = $exploded[1];
1663 //Get position key (if it fails, next iteration)
1664 if ($oldposrec = backup_getid($restore->backup_unique_code,'multianswer-pos',$multianswer_id)) {
1665 $positionkey = $oldposrec->new_id;
1666 } else {
1667 //Next iteration
1668 $tok = strtok(",");
1669 continue;
1671 //Calculate question type
1672 $questiondb = get_record('quiz_questions','id',$sequencearr[$counter-1]);
1673 $questiontype = $questiondb->qtype;
1674 //Now, depending of the answertype field in quiz_multianswers
1675 //we do diferent things
1676 if ($questiontype == "1") {
1677 //Shortanswer
1678 //The answer is text, do nothing
1679 } else if ($questiontype == "3") {
1680 //Multichoice
1681 //The answer is an answer_id, look for it in backup_ids
1682 $ans = backup_getid($restore->backup_unique_code,"quiz_answers",$answer);
1683 $answer = $ans->new_id;
1684 } else if ($questiontype == "8") {
1685 //Numeric
1686 //The answer is text, do nothing
1689 //Finaly, build the new answer field for each pair
1690 if ($in_first) {
1691 $answer_field .= $positionkey."-".$answer;
1692 $in_first = false;
1693 } else {
1694 $answer_field .= ",".$positionkey."-".$answer;
1696 //check for next
1697 $tok = strtok(",");
1698 $counter++;
1700 $response->answer = $answer_field;
1701 break;
1702 case 10: //CALCULATED QTYPE
1703 //Nothing to do. The response is a text.
1704 break;
1705 default: //UNMATCHED QTYPE.
1706 //This is an error (unimplemented qtype)
1707 $status = false;
1708 break;
1710 } else {
1711 $status = false;
1714 //The structure is equal to the db, so insert the quiz_states
1715 $newid = insert_record ("quiz_states",$response);
1717 //Do some output
1718 if (($i+1) % 10 == 0) {
1719 echo ".";
1720 if (($i+1) % 200 == 0) {
1721 echo "<br />";
1723 backup_flush(300);
1726 if ($newid) {
1727 //We have the newid, update backup_ids
1728 backup_putid($restore->backup_unique_code,"quiz_states",$oldid,
1729 $newid);
1730 } else {
1731 $status = false;
1735 return $status;
1738 //This function restores the quiz_grades
1739 function quiz_grades_restore_pre15_mods($quiz_id,$info,$restore) {
1741 global $CFG;
1743 $status = true;
1745 //Get the quiz_grades array
1746 $grades = $info['MOD']['#']['GRADES']['0']['#']['GRADE'];
1748 //Iterate over grades
1749 for($i = 0; $i < sizeof($grades); $i++) {
1750 $gra_info = $grades[$i];
1751 //traverse_xmlize($gra_info); //Debug
1752 //print_object ($GLOBALS['traverse_array']); //Debug
1753 //$GLOBALS['traverse_array']=""; //Debug
1755 //We'll need this later!!
1756 $oldid = backup_todb($gra_info['#']['ID']['0']['#']);
1757 $olduserid = backup_todb($gra_info['#']['USERID']['0']['#']);
1759 //Now, build the GRADES record structure
1760 $grade->quiz = $quiz_id;
1761 $grade->userid = backup_todb($gra_info['#']['USERID']['0']['#']);
1762 $grade->grade = backup_todb($gra_info['#']['GRADEVAL']['0']['#']);
1763 $grade->timemodified = backup_todb($gra_info['#']['TIMEMODIFIED']['0']['#']);
1765 //We have to recode the userid field
1766 $user = backup_getid($restore->backup_unique_code,"user",$grade->userid);
1767 if ($user) {
1768 $grade->userid = $user->new_id;
1771 //The structure is equal to the db, so insert the quiz_grades
1772 $newid = insert_record ("quiz_grades",$grade);
1774 //Do some output
1775 if (($i+1) % 10 == 0) {
1776 echo ".";
1777 if (($i+1) % 200 == 0) {
1778 echo "<br />";
1780 backup_flush(300);
1783 if ($newid) {
1784 //We have the newid, update backup_ids
1785 backup_putid($restore->backup_unique_code,"quiz_grades",$oldid,
1786 $newid);
1787 } else {
1788 $status = false;
1792 return $status;
1795 //This function converts texts in FORMAT_WIKI to FORMAT_MARKDOWN for
1796 //some texts in the module
1797 function quiz_restore_pre15_wiki2markdown ($restore) {
1799 global $CFG;
1801 $status = true;
1803 //Convert quiz_questions->questiontext
1804 if ($records = get_records_sql ("SELECT q.id, q.questiontext, q.questiontextformat
1805 FROM {$CFG->prefix}quiz_questions q,
1806 {$CFG->prefix}backup_ids b
1807 WHERE b.backup_code = $restore->backup_unique_code AND
1808 b.table_name = 'quiz_questions' AND
1809 q.id = b.new_id AND
1810 q.questiontextformat = ".FORMAT_WIKI)) {
1811 foreach ($records as $record) {
1812 //Rebuild wiki links
1813 $record->questiontext = restore_decode_wiki_content($record->questiontext, $restore);
1814 //Convert to Markdown
1815 $wtm = new WikiToMarkdown();
1816 $record->questiontext = $wtm->convert($record->questiontext, $restore->course_id);
1817 $record->questiontextformat = FORMAT_MARKDOWN;
1818 $status = update_record('quiz_questions', addslashes_object($record));
1819 //Do some output
1820 $i++;
1821 if (($i+1) % 1 == 0) {
1822 echo ".";
1823 if (($i+1) % 20 == 0) {
1824 echo "<br />";
1826 backup_flush(300);
1830 return $status;
1833 //This function returns a log record with all the necessay transformations
1834 //done. It's used by restore_log_module() to restore modules log.
1835 function quiz_restore_pre15_logs($restore,$log) {
1837 $status = false;
1839 //Depending of the action, we recode different things
1840 switch ($log->action) {
1841 case "add":
1842 if ($log->cmid) {
1843 //Get the new_id of the module (to recode the info field)
1844 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
1845 if ($mod) {
1846 $log->url = "view.php?id=".$log->cmid;
1847 $log->info = $mod->new_id;
1848 $status = true;
1851 break;
1852 case "update":
1853 if ($log->cmid) {
1854 //Get the new_id of the module (to recode the info field)
1855 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
1856 if ($mod) {
1857 $log->url = "view.php?id=".$log->cmid;
1858 $log->info = $mod->new_id;
1859 $status = true;
1862 break;
1863 case "view":
1864 if ($log->cmid) {
1865 //Get the new_id of the module (to recode the info field)
1866 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
1867 if ($mod) {
1868 $log->url = "view.php?id=".$log->cmid;
1869 $log->info = $mod->new_id;
1870 $status = true;
1873 break;
1874 case "view all":
1875 $log->url = "index.php?id=".$log->course;
1876 $status = true;
1877 break;
1878 case "report":
1879 if ($log->cmid) {
1880 //Get the new_id of the module (to recode the info field)
1881 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
1882 if ($mod) {
1883 $log->url = "report.php?id=".$log->cmid;
1884 $log->info = $mod->new_id;
1885 $status = true;
1888 break;
1889 case "attempt":
1890 if ($log->cmid) {
1891 //Get the new_id of the module (to recode the info field)
1892 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
1893 if ($mod) {
1894 //Extract the attempt id from the url field
1895 $attid = substr(strrchr($log->url,"="),1);
1896 //Get the new_id of the attempt (to recode the url field)
1897 $att = backup_getid($restore->backup_unique_code,"quiz_attempts",$attid);
1898 if ($att) {
1899 $log->url = "review.php?id=".$log->cmid."&amp;attempt=".$att->new_id;
1900 $log->info = $mod->new_id;
1901 $status = true;
1905 break;
1906 case "submit":
1907 if ($log->cmid) {
1908 //Get the new_id of the module (to recode the info field)
1909 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
1910 if ($mod) {
1911 //Extract the attempt id from the url field
1912 $attid = substr(strrchr($log->url,"="),1);
1913 //Get the new_id of the attempt (to recode the url field)
1914 $att = backup_getid($restore->backup_unique_code,"quiz_attempts",$attid);
1915 if ($att) {
1916 $log->url = "review.php?id=".$log->cmid."&amp;attempt=".$att->new_id;
1917 $log->info = $mod->new_id;
1918 $status = true;
1922 break;
1923 case "review":
1924 if ($log->cmid) {
1925 //Get the new_id of the module (to recode the info field)
1926 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
1927 if ($mod) {
1928 //Extract the attempt id from the url field
1929 $attid = substr(strrchr($log->url,"="),1);
1930 //Get the new_id of the attempt (to recode the url field)
1931 $att = backup_getid($restore->backup_unique_code,"quiz_attempts",$attid);
1932 if ($att) {
1933 $log->url = "review.php?id=".$log->cmid."&amp;attempt=".$att->new_id;
1934 $log->info = $mod->new_id;
1935 $status = true;
1939 break;
1940 case "editquestions":
1941 if ($log->cmid) {
1942 //Get the new_id of the module (to recode the url field)
1943 $mod = backup_getid($restore->backup_unique_code,$log->module,$log->info);
1944 if ($mod) {
1945 $log->url = "view.php?id=".$log->cmid;
1946 $log->info = $mod->new_id;
1947 $status = true;
1950 break;
1951 default:
1952 echo "action (".$log->module."-".$log->action.") unknow. Not restored<br />"; //Debug
1953 break;
1956 if ($status) {
1957 $status = $log;
1959 return $status;