2 //This php script contains all the stuff to restore questions
5 // the restoration of the parent and sortorder fields in the category table needs
6 // a lot more thought. We should probably use a library function to add the category
7 // rather than just writing it to the database
9 // whereever it says "/// We have to recode the .... field" we should put in a check
10 // to see if the recoding was successful and throw an appropriate error otherwise
12 //This is the "graphical" structure of the question database:
13 //To see, put your terminal to 160cc
15 // The following holds student-independent information about the questions
17 // question_categories
21 // |.......................................
24 // | -------question_datasets------ .
25 // | | (CL,pk->id,fk->question, | .
26 // | | fk->dataset_definition) | .
30 // | | question_dataset_definitions
31 // | | (CL,pk->id,fk->category)
33 // (CL,pk->id,fk->category,files) |
34 // | question_dataset_items
35 // | (CL,pk->id,fk->definition)
36 // | question_rqp_type
39 // -------------------------------------------------------------------------------------------------------------- |
40 // | | | | | | | question_rqp
41 // | | | | | | |--(CL,pk->id,fk->question)
42 // | | | | question_calculated | |
43 // question_truefalse | question_multichoice | (CL,pl->id,fk->question) | |
44 // (CL,pk->id,fk->question) | (CL,pk->id,fk->question) | . | | question_randomsamatch
45 // . | . | . | |--(CL,pk->id,fk->question)
46 // . question_shortanswer . question_numerical . question_multianswer. |
47 // . (CL,pk->id,fk->question) . (CL,pk->id,fk->question) . (CL,pk->id,fk->question) |
48 // . . . . . . | question_match
49 // . . . . . . |--(CL,pk->id,fk->question)
53 // . . . . . . | question_match_sub
54 // ........................................................................................ |--(CL,pk->id,fk->question)
57 // . | question_numerical_units
58 // question_answers |--(CL,pk->id,fk->question)
59 // (CL,pk->id,fk->question)----------------------------------------------------------
62 // The following holds the information about student interaction with the questions
65 // (UL,pk->id,fk->attempt,question)
69 // (UL,pk->id,fk->attempt,question)
71 // question_rqp_states
72 // (UL,pk->id,fk->stateid)
74 // Meaning: pk->primary key field of the table
75 // fk->foreign key to link with parent
76 // nt->nested field (recursive data)
77 // SL->site level info
78 // CL->course level info
79 // UL->user level info
80 // files->table may have files
82 //-----------------------------------------------------------
84 include_once($CFG->libdir
.'/questionlib.php');
86 function restore_question_categories($category,$restore) {
92 //Hook to call Moodle < 1.5 Quiz Restore
93 if ($restore->backup_version
< 2005043000) {
94 include_once($CFG->dirroot
.'/mod/quiz/restorelibpre15.php');
95 return quiz_restore_pre15_question_categories($category,$restore);
98 //Get record from backup_ids
99 $data = backup_getid($restore->backup_unique_code
,"question_categories",$category->id
);
102 //Now get completed xmlized object
104 //traverse_xmlize($info); //Debug
105 //print_object ($GLOBALS['traverse_array']); //Debug
106 //$GLOBALS['traverse_array']=""; //Debug
108 //Now, build the question_categories record structure
109 $question_cat = new stdClass
;
110 $question_cat->course
= $restore->course_id
;
111 $question_cat->name
= backup_todb($info['QUESTION_CATEGORY']['#']['NAME']['0']['#']);
112 $question_cat->info
= backup_todb($info['QUESTION_CATEGORY']['#']['INFO']['0']['#']);
113 $question_cat->publish
= backup_todb($info['QUESTION_CATEGORY']['#']['PUBLISH']['0']['#']);
114 $question_cat->stamp
= backup_todb($info['QUESTION_CATEGORY']['#']['STAMP']['0']['#']);
115 $question_cat->parent
= backup_todb($info['QUESTION_CATEGORY']['#']['PARENT']['0']['#']);
116 $question_cat->sortorder
= backup_todb($info['QUESTION_CATEGORY']['#']['SORTORDER']['0']['#']);
118 if ($catfound = restore_get_best_question_category($question_cat, $restore->course_id
)) {
121 if (!$question_cat->stamp
) {
122 $question_cat->stamp
= make_unique_id_code();
124 $newid = insert_record ("question_categories",$question_cat);
129 if (!defined('RESTORE_SILENTLY')) {
130 echo "<li>".get_string('category', 'quiz')." \"".$question_cat->name
."\"<br />";
133 //We must never arrive here !!
134 if (!defined('RESTORE_SILENTLY')) {
135 echo "<li>".get_string('category', 'quiz')." \"".$question_cat->name
."\" Error!<br />";
141 //Here category has been created or selected, so save results in backup_ids and start with questions
142 if ($newid and $status) {
143 //We have the newid, update backup_ids
144 backup_putid($restore->backup_unique_code
,"question_categories",
145 $category->id
, $newid);
146 //Now restore question
147 $status = restore_questions ($category->id
, $newid,$info,$restore);
151 if (!defined('RESTORE_SILENTLY')) {
155 echo 'Could not get backup info for question category'. $category->id
;
161 function restore_questions ($old_category_id,$new_category_id,$info,$restore) {
163 global $CFG, $QTYPES;
166 $restored_questions = array();
168 //Get the questions array
169 if (!empty($info['QUESTION_CATEGORY']['#']['QUESTIONS'])) {
170 $questions = $info['QUESTION_CATEGORY']['#']['QUESTIONS']['0']['#']['QUESTION'];
172 $questions = array();
175 //Iterate over questions
176 for($i = 0; $i < sizeof($questions); $i++
) {
177 $que_info = $questions[$i];
178 //traverse_xmlize($que_info); //Debug
179 //print_object ($GLOBALS['traverse_array']); //Debug
180 //$GLOBALS['traverse_array']=""; //Debug
182 //We'll need this later!!
183 $oldid = backup_todb($que_info['#']['ID']['0']['#']);
185 //Now, build the question record structure
186 $question = new object;
187 $question->category
= $new_category_id;
188 $question->parent
= backup_todb($que_info['#']['PARENT']['0']['#']);
189 $question->name
= backup_todb($que_info['#']['NAME']['0']['#']);
190 $question->questiontext
= backup_todb($que_info['#']['QUESTIONTEXT']['0']['#']);
191 $question->questiontextformat
= backup_todb($que_info['#']['QUESTIONTEXTFORMAT']['0']['#']);
192 $question->image
= backup_todb($que_info['#']['IMAGE']['0']['#']);
193 if (array_key_exists('GENERALFEEDBACK', $que_info['#'])) {
194 $question->generalfeedback
= backup_todb($que_info['#']['GENERALFEEDBACK']['0']['#']);
196 $question->generalfeedback
= '';
198 $question->defaultgrade
= backup_todb($que_info['#']['DEFAULTGRADE']['0']['#']);
199 $question->penalty
= backup_todb($que_info['#']['PENALTY']['0']['#']);
200 $question->qtype
= backup_todb($que_info['#']['QTYPE']['0']['#']);
201 $question->length
= backup_todb($que_info['#']['LENGTH']['0']['#']);
202 $question->stamp
= backup_todb($que_info['#']['STAMP']['0']['#']);
203 $question->version
= backup_todb($que_info['#']['VERSION']['0']['#']);
204 $question->hidden
= backup_todb($que_info['#']['HIDDEN']['0']['#']);
206 if ($restore->backup_version
< 2006032200) {
207 // The qtype was an integer that now needs to be converted to the name
208 $qtypenames = array(1=>'shortanswer',2=>'truefalse',3=>'multichoice',4=>'random',5=>'match',
209 6=>'randomsamatch',7=>'description',8=>'numerical',9=>'multianswer',10=>'calculated',
210 11=>'rqp',12=>'essay');
211 $question->qtype
= $qtypenames[$question->qtype
];
214 //Check if the question exists
215 //by category, stamp, and version
216 $question_exists = get_record ("question","category",$question->category
,
217 "stamp",$question->stamp
,"version",$question->version
);
219 //If the question exists, only record its id
220 if ($question_exists) {
221 $newid = $question_exists->id
;
222 $creatingnewquestion = false;
223 //Else, create a new question
225 //The structure is equal to the db, so insert the question
226 $newid = insert_record ("question",$question);
227 $creatingnewquestion = true;
230 //Save newid to backup tables
232 //We have the newid, update backup_ids
233 backup_putid($restore->backup_unique_code
,"question",$oldid,
237 $restored_questions[$i] = new stdClass
;
238 $restored_questions[$i]->newid
= $newid;
239 $restored_questions[$i]->oldid
= $oldid;
240 $restored_questions[$i]->qtype
= $question->qtype
;
241 $restored_questions[$i]->parent
= $question->parent
;
242 $restored_questions[$i]->is_new
= $creatingnewquestion;
245 // Loop again, now all the question id mappings exist, so everything can
247 for($i = 0; $i < sizeof($questions); $i++
) {
248 $que_info = $questions[$i];
250 $newid = $restored_questions[$i]->newid
;
251 $oldid = $restored_questions[$i]->oldid
;
253 $question = new object;
254 $question->qtype
= $restored_questions[$i]->qtype
;
255 $question->parent
= $restored_questions[$i]->parent
;
258 //If it's a new question in the DB, restore it
259 if ($restored_questions[$i]->is_new
) {
261 ////We have to recode the parent field
262 if ($question->parent
) {
263 if ($parent = backup_getid($restore->backup_unique_code
,"question",$question->parent
)) {
264 $question->parent
= $parent->new_id
;
265 } elseif ($question->parent
= $oldid) {
266 $question->parent
= $newid;
268 echo 'Could not recode parent '.$question->parent
.' for question '.$oldid.'<br />';
272 //Now, restore every question_answers in this question
273 $status = question_restore_answers($oldid,$newid,$que_info,$restore);
274 // Restore questiontype specific data
275 if (array_key_exists($question->qtype
, $QTYPES)) {
276 $status = $QTYPES[$question->qtype
]->restore($oldid,$newid,$que_info,$restore);
278 echo 'Unknown question type '.$question->qtype
.' for question '.$oldid.'<br />';
282 //We are NOT creating the question, but we need to know every question_answers
283 //map between the XML file and the database to be able to restore the states
285 $status = question_restore_map_answers($oldid,$newid,$que_info,$restore);
286 // Do the questiontype specific mapping
287 if (array_key_exists($question->qtype
, $QTYPES)) {
288 $status = $QTYPES[$question->qtype
]->restore_map($oldid,$newid,$que_info,$restore);
290 echo 'Unknown question type '.$question->qtype
.' for question '.$oldid.'<br />';
296 if (($i+
1) %
2 == 0) {
297 if (!defined('RESTORE_SILENTLY')) {
299 if (($i+
1) %
40 == 0) {
309 function question_restore_answers ($old_question_id,$new_question_id,$info,$restore) {
314 $qtype = backup_todb($info['#']['QTYPE']['0']['#']);
316 //Get the answers array
317 if (isset($info['#']['ANSWERS']['0']['#']['ANSWER'])) {
318 $answers = $info['#']['ANSWERS']['0']['#']['ANSWER'];
320 //Iterate over answers
321 for($i = 0; $i < sizeof($answers); $i++
) {
322 $ans_info = $answers[$i];
323 //traverse_xmlize($ans_info); //Debug
324 //print_object ($GLOBALS['traverse_array']); //Debug
325 //$GLOBALS['traverse_array']=""; //Debug
327 //We'll need this later!!
328 $oldid = backup_todb($ans_info['#']['ID']['0']['#']);
330 //Now, build the question_answers record structure
331 $answer = new stdClass
;
332 $answer->question
= $new_question_id;
333 $answer->answer
= backup_todb($ans_info['#']['ANSWER_TEXT']['0']['#']);
334 $answer->fraction
= backup_todb($ans_info['#']['FRACTION']['0']['#']);
335 $answer->feedback
= backup_todb($ans_info['#']['FEEDBACK']['0']['#']);
337 // Update 'match everything' answers for numerical questions coming from old backup files.
338 if ($qtype == 'numerical' && $answer->answer
== '') {
339 $answer->answer
= '*';
342 //The structure is equal to the db, so insert the question_answers
343 $newid = insert_record ("question_answers",$answer);
346 if (($i+
1) %
50 == 0) {
347 if (!defined('RESTORE_SILENTLY')) {
349 if (($i+
1) %
1000 == 0) {
357 //We have the newid, update backup_ids
358 backup_putid($restore->backup_unique_code
,"question_answers",$oldid,
369 function question_restore_map_answers ($old_question_id,$new_question_id,$info,$restore) {
375 if (!isset($info['#']['ANSWERS'])) { // No answers in this question (eg random)
379 //Get the answers array
380 $answers = $info['#']['ANSWERS']['0']['#']['ANSWER'];
382 //Iterate over answers
383 for($i = 0; $i < sizeof($answers); $i++
) {
384 $ans_info = $answers[$i];
385 //traverse_xmlize($ans_info); //Debug
386 //print_object ($GLOBALS['traverse_array']); //Debug
387 //$GLOBALS['traverse_array']=""; //Debug
389 //We'll need this later!!
390 $oldid = backup_todb($ans_info['#']['ID']['0']['#']);
392 //Now, build the question_answers record structure
393 $answer->question
= $new_question_id;
394 $answer->answer
= backup_todb($ans_info['#']['ANSWER_TEXT']['0']['#']);
395 $answer->fraction
= backup_todb($ans_info['#']['FRACTION']['0']['#']);
396 $answer->feedback
= backup_todb($ans_info['#']['FEEDBACK']['0']['#']);
398 //If we are in this method is because the question exists in DB, so its
399 //answers must exist too.
400 //Now, we are going to look for that answer in DB and to create the
401 //mappings in backup_ids to use them later where restoring states (user level).
403 //Get the answer from DB (by question and answer)
404 $db_answer = get_record ("question_answers","question",$new_question_id,
405 "answer",$answer->answer
);
408 if (($i+
1) %
50 == 0) {
409 if (!defined('RESTORE_SILENTLY')) {
411 if (($i+
1) %
1000 == 0) {
419 //We have the database answer, update backup_ids
420 backup_putid($restore->backup_unique_code
,"question_answers",$oldid,
430 function question_restore_numerical_units($old_question_id,$new_question_id,$info,$restore) {
436 //Get the numerical array
437 if (!empty($info['#']['NUMERICAL_UNITS'])) {
438 $numerical_units = $info['#']['NUMERICAL_UNITS']['0']['#']['NUMERICAL_UNIT'];
440 $numerical_units = array();
443 //Iterate over numerical_units
444 for($i = 0; $i < sizeof($numerical_units); $i++
) {
445 $nu_info = $numerical_units[$i];
446 //traverse_xmlize($nu_info); //Debug
447 //print_object ($GLOBALS['traverse_array']); //Debug
448 //$GLOBALS['traverse_array']=""; //Debug
450 // Check to see if this until already exists in the database, which it might, for
451 // Historical reasons.
452 $unit = backup_todb($nu_info['#']['UNIT']['0']['#']);
453 if (!record_exists('question_numerical_units', 'question', $new_question_id, 'unit', $unit)) {
455 //Now, build the question_numerical_UNITS record structure.
456 $numerical_unit = new stdClass
;
457 $numerical_unit->question
= $new_question_id;
458 $numerical_unit->multiplier
= backup_todb($nu_info['#']['MULTIPLIER']['0']['#']);
459 $numerical_unit->unit
= $unit;
461 //The structure is equal to the db, so insert the question_numerical_units
462 $newid = insert_record("question_numerical_units", $numerical_unit);
473 function question_restore_dataset_definitions ($old_question_id,$new_question_id,$info,$restore) {
479 //Get the dataset_definitions array
480 $dataset_definitions = $info['#']['DATASET_DEFINITIONS']['0']['#']['DATASET_DEFINITION'];
482 //Iterate over dataset_definitions
483 for($i = 0; $i < sizeof($dataset_definitions); $i++
) {
484 $dd_info = $dataset_definitions[$i];
485 //traverse_xmlize($dd_info); //Debug
486 //print_object ($GLOBALS['traverse_array']); //Debug
487 //$GLOBALS['traverse_array']=""; //Debug
489 //Now, build the question_dataset_DEFINITION record structure
490 $dataset_definition = new stdClass
;
491 $dataset_definition->category
= backup_todb($dd_info['#']['CATEGORY']['0']['#']);
492 $dataset_definition->name
= backup_todb($dd_info['#']['NAME']['0']['#']);
493 $dataset_definition->type
= backup_todb($dd_info['#']['TYPE']['0']['#']);
494 $dataset_definition->options
= backup_todb($dd_info['#']['OPTIONS']['0']['#']);
495 $dataset_definition->itemcount
= backup_todb($dd_info['#']['ITEMCOUNT']['0']['#']);
497 //We have to recode the category field (only if the category != 0)
498 if ($dataset_definition->category
!= 0) {
499 $category = backup_getid($restore->backup_unique_code
,"question_categories",$dataset_definition->category
);
501 $dataset_definition->category
= $category->new_id
;
503 echo 'Could not recode category id '.$dataset_definition->category
.' for dataset definition'.$dataset_definition->name
.'<br />';
507 //Now, we hace to decide when to create the new records or reuse an existing one
508 $create_definition = false;
510 //If the dataset_definition->category = 0, it's a individual question dataset_definition, so we'll create it
511 if ($dataset_definition->category
== 0) {
512 $create_definition = true;
514 //The category isn't 0, so it's a category question dataset_definition, we have to see if it exists
515 //Look for a definition with the same category, name and type
516 if ($definitionrec = get_record_sql("SELECT d.*
517 FROM {$CFG->prefix}question_dataset_definitions d
518 WHERE d.category = '$dataset_definition->category' AND
519 d.name = '$dataset_definition->name' AND
520 d.type = '$dataset_definition->type'")) {
521 //Such dataset_definition exist. Now we must check if it has enough itemcount
522 if ($definitionrec->itemcount
< $dataset_definition->itemcount
) {
523 //We haven't enough itemcount, so we have to create the definition as an individual question one.
524 $dataset_definition->category
= 0;
525 $create_definition = true;
527 //We have enough itemcount, so we'll reuse the existing definition
528 $create_definition = false;
529 $newid = $definitionrec->id
;
532 //Such dataset_definition doesn't exist. We'll create it.
533 $create_definition = true;
537 //If we've to create the definition, do it
538 if ($create_definition) {
539 //The structure is equal to the db, so insert the question_dataset_definitions
540 $newid = insert_record ("question_dataset_definitions",$dataset_definition);
542 //Restore question_dataset_items
543 $status = question_restore_dataset_items($newid,$dd_info,$restore);
547 //Now, we must have a definition (created o reused). Its id is in newid. Create the question_datasets record
548 //to join the question and the dataset_definition
550 $question_dataset = new stdClass
;
551 $question_dataset->question
= $new_question_id;
552 $question_dataset->datasetdefinition
= $newid;
553 $newid = insert_record ("question_datasets",$question_dataset);
564 function question_restore_dataset_items ($definitionid,$info,$restore) {
570 //Get the items array
571 $dataset_items = $info['#']['DATASET_ITEMS']['0']['#']['DATASET_ITEM'];
573 //Iterate over dataset_items
574 for($i = 0; $i < sizeof($dataset_items); $i++
) {
575 $di_info = $dataset_items[$i];
576 //traverse_xmlize($di_info); //Debug
577 //print_object ($GLOBALS['traverse_array']); //Debug
578 //$GLOBALS['traverse_array']=""; //Debug
580 //Now, build the question_dataset_ITEMS record structure
581 $dataset_item = new stdClass
;
582 $dataset_item->definition
= $definitionid;
583 $dataset_item->itemnumber
= backup_todb($di_info['#']['NUMBER']['0']['#']);
584 $dataset_item->value
= backup_todb($di_info['#']['VALUE']['0']['#']);
586 //The structure is equal to the db, so insert the question_dataset_items
587 $newid = insert_record ("question_dataset_items",$dataset_item);
598 //This function restores the question_states
599 function question_states_restore_mods($attempt_id,$info,$restore) {
601 global $CFG, $QTYPES;
605 //Get the question_states array
606 $states = $info['#']['STATES']['0']['#']['STATE'];
607 //Iterate over states
608 for($i = 0; $i < sizeof($states); $i++
) {
609 $res_info = $states[$i];
610 //traverse_xmlize($res_info); //Debug
611 //print_object ($GLOBALS['traverse_array']); //Debug
612 //$GLOBALS['traverse_array']=""; //Debug
614 //We'll need this later!!
615 $oldid = backup_todb($res_info['#']['ID']['0']['#']);
617 //Now, build the STATES record structure
618 $state = new stdClass
;
619 $state->attempt
= $attempt_id;
620 $state->question
= backup_todb($res_info['#']['QUESTION']['0']['#']);
621 $state->originalquestion
= backup_todb($res_info['#']['ORIGINALQUESTION']['0']['#']);
622 $state->seq_number
= backup_todb($res_info['#']['SEQ_NUMBER']['0']['#']);
623 $state->answer
= backup_todb($res_info['#']['ANSWER']['0']['#']);
624 $state->timestamp
= backup_todb($res_info['#']['TIMESTAMP']['0']['#']);
625 $state->event
= backup_todb($res_info['#']['EVENT']['0']['#']);
626 $state->grade
= backup_todb($res_info['#']['GRADE']['0']['#']);
627 $state->raw_grade
= backup_todb($res_info['#']['RAW_GRADE']['0']['#']);
628 $state->penalty
= backup_todb($res_info['#']['PENALTY']['0']['#']);
629 $state->oldid
= $oldid; // So it is available to restore_recode_answer.
631 //We have to recode the question field
632 $question = backup_getid($restore->backup_unique_code
,"question",$state->question
);
634 $state->question
= $question->new_id
;
636 echo 'Could not recode question id '.$state->question
.' for state '.$oldid.'<br />';
639 //We have to recode the originalquestion field if it is nonzero
640 if ($state->originalquestion
) {
641 $question = backup_getid($restore->backup_unique_code
,"question",$state->originalquestion
);
643 $state->originalquestion
= $question->new_id
;
645 echo 'Could not recode originalquestion id '.$state->question
.' for state '.$oldid.'<br />';
649 //We have to recode the answer field
650 //It depends of the question type !!
651 //We get the question first
652 if (!$question = get_record("question","id",$state->question
)) {
653 error("Can't find the record for question $state->question for which I am trying to restore a state");
655 //Depending on the qtype, we make different recodes
656 if ($state->answer
) {
657 $state->answer
= $QTYPES[$question->qtype
]->restore_recode_answer($state, $restore);
660 //The structure is equal to the db, so insert the question_states
661 $newid = insert_record ("question_states",$state);
664 if (($i+
1) %
10 == 0) {
665 if (!defined('RESTORE_SILENTLY')) {
667 if (($i+
1) %
200 == 0) {
675 //We have the newid, update backup_ids
676 backup_putid($restore->backup_unique_code
,"question_states",$oldid,
678 //Now process question type specific state information
679 $qtype = get_field('question', 'qtype', 'id', $state->question
);
680 $status = $QTYPES[$qtype]->restore_state($newid,$res_info,$restore);
686 //Get the question_sessions array
687 $sessions = $info['#']['NEWEST_STATES']['0']['#']['NEWEST_STATE'];
688 //Iterate over question_sessions
689 for($i = 0; $i < sizeof($sessions); $i++
) {
690 $res_info = $sessions[$i];
691 //traverse_xmlize($res_info); //Debug
692 //print_object ($GLOBALS['traverse_array']); //Debug
693 //$GLOBALS['traverse_array']=""; //Debug
695 //Now, build the NEWEST_STATES record structure
696 $session = new stdClass
;
697 $session->attemptid
= $attempt_id;
698 $session->questionid
= backup_todb($res_info['#']['QUESTIONID']['0']['#']);
699 $session->newest
= backup_todb($res_info['#']['NEWEST']['0']['#']);
700 $session->newgraded
= backup_todb($res_info['#']['NEWGRADED']['0']['#']);
701 $session->sumpenalty
= backup_todb($res_info['#']['SUMPENALTY']['0']['#']);
703 if ($res_info['#']['MANUALCOMMENT']['0']['#']) {
704 $session->manualcomment
= backup_todb($res_info['#']['MANUALCOMMENT']['0']['#']);
705 } else { // pre 1.7 backups
706 $session->manualcomment
= backup_todb($res_info['#']['COMMENT']['0']['#']);
709 //We have to recode the question field
710 $question = backup_getid($restore->backup_unique_code
,"question",$session->questionid
);
712 $session->questionid
= $question->new_id
;
714 echo 'Could not recode question id '.$session->questionid
.'<br />';
717 //We have to recode the newest field
718 $state = backup_getid($restore->backup_unique_code
,"question_states",$session->newest
);
720 $session->newest
= $state->new_id
;
722 echo 'Could not recode newest state id '.$session->newest
.'<br />';
725 //If the session has been graded we have to recode the newgraded field
726 if ($session->newgraded
) {
727 $state = backup_getid($restore->backup_unique_code
,"question_states",$session->newgraded
);
729 $session->newgraded
= $state->new_id
;
731 echo 'Could not recode newest graded state id '.$session->newgraded
.'<br />';
735 //The structure is equal to the db, so insert the question_sessions
736 $newid = insert_record ("question_sessions",$session);