From: stronk7 Date: Sat, 28 Jun 2003 23:18:37 +0000 (+0000) Subject: Now categories and questions are recovered completely (STEP1) X-Git-Url: http://git.mjollnir.org/gw?a=commitdiff_plain;h=56f56ca0b2531a278af131de6c781d60eaf11fa8;p=moodle.git Now categories and questions are recovered completely (STEP1) --- diff --git a/backup/STATUS.txt b/backup/STATUS.txt index 5d52d9d5d1..971bdad484 100644 --- a/backup/STATUS.txt +++ b/backup/STATUS.txt @@ -147,9 +147,9 @@ Restore Details: - None.........................................DONE - Course.......................................DONE - All..........................................DONE - - Categories and Questions.(STEP 1)..................NO EXISTS - + categories......................................NO EXISTS - + questions structure.............................NO EXISTS + - Categories and Questions.(STEP 1)..................DONE + + categories......................................DONE + + questions structure.............................DONE - Mods Info Prepare..................................DONE x read modules zone...............................DONE x separate every mod..............................DONE diff --git a/backup/mod/quiz/restorelib.php b/backup/mod/quiz/restorelib.php new file mode 100644 index 0000000000..5fca8840ec --- /dev/null +++ b/backup/mod/quiz/restorelib.php @@ -0,0 +1,545 @@ +id) (CL,pk->id) + // | | + // ----------------------------------------------- | + // | | | | + // | | | | + // | | | | + // quiz_attempts quiz_grades quiz_question_grades | + // (UL,pk->id, fk->quiz) (UL,pk->id,fk->quiz) (CL,pk->id,fk->quiz) | + // | | | + // | | | + // | | | + // quiz_responses | quiz_questions + // (UL,pk->id, fk->attempt)----------------------------------------------------(CL,pk->id,fk->category,files) + // | + // | + // | + // ------------------------------------------------------------------------------------------------------ + // | | | | + // | | | | + // | | | | quiz_randomsamatch + // quiz_truefalse quiz_shortanswer quiz_multichoice |---------(CL,pl->id,fk->question) + // (CL,pl->id,fk->question) (CL,pl->id,fk->question) (CL,pl->id,fk->question) | + // . . . | + // . . . | + // . . . | quiz_match + // .................................................... |---------(CL,pl->id,fk->question) + // . | . + // . | . + // . | . + // quiz_answers | quiz_match_sub + // (CL,pk->id,fk->question)----------------------------|---------(CL,pl->id,fk->question) + // + // Meaning: pk->primary key field of the table + // fk->foreign key to link with parent + // nt->nested field (recursive data) + // CL->course level info + // UL->user level info + // files->table may have files + // + //----------------------------------------------------------- + + //This module is special, because we make the restore in two steps: + // 1.-We restore every category and their questions (complete structure). It includes this tables: + // - quiz_categories + // - quiz_questions + // - quiz_truefalse + // - quiz_shortanswer + // - quiz_multichoice + // - quiz_randomsamatch + // - quiz_match + // - quiz_match_sub + // - quiz_answers + // All this backup info have its own section in moodle.xml (QUESTION_CATEGORIES) and it's generated + // before every module backup standard invocation. And only if to restore quizzes has been selected !! + // It's invoked with quiz_restore_question_categories. (course independent). + + // 2.-Standard module restore (Invoked via quiz_restore_mods). It includes this tables: + // - quiz + // - quiz_question_grades + // - quiz_attempts + // - quiz_grades + // - quiz_responses + // This step is the standard mod backup. (course dependent). + + //STEP 1. Restore categories/questions and associated structures + // (course independent) + function quiz_restore_question_categories($category,$restore) { + + global $CFG; + + $status = true; + + //Get record from backup_ids + $data = backup_getid($restore->backup_unique_code,"quiz_categories",$category->id); + + if ($data) { + //Now get completed xmlized object + $info = $data->info; + //traverse_xmlize($info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //Now, build the QUIZ_CATEGORIES record structure + $quiz_cat->course = $restore->course_id; + $quiz_cat->name = backup_todb($info['QUESTION_CATEGORY']['#']['NAME']['0']['#']); + $quiz_cat->info = backup_todb($info['QUESTION_CATEGORY']['#']['INFO']['0']['#']); + $quiz_cat->publish = backup_todb($info['QUESTION_CATEGORY']['#']['PUBLISH']['0']['#']); + + //Now search it that category exists !! + $cat = get_record("quiz_categories","name",$quiz_cat->name); + //Create it if doesn't exists + if (!$cat) { + //The structure is equal to the db, so insert the quiz_categories + $newid = insert_record ("quiz_categories",$quiz_cat); + } else { + //Exists, so get its id + $newid = $cat->id; + } + + //Do some output + echo ""; + } + + return $status; + } + + function quiz_restore_questions ($old_category_id,$new_category_id,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the questions array + $questions = $info['QUESTION_CATEGORY']['#']['QUESTIONS']['0']['#']['QUESTION']; + + //Iterate over questions + for($i = 0; $i < sizeof($questions); $i++) { + $que_info = $questions[$i]; + //traverse_xmlize($que_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //We'll need this later!! + $oldid = backup_todb($que_info['#']['ID']['0']['#']); + + //Now, build the QUIZ_QUESTIONS record structure + $question->category = $new_category_id; + $question->name = backup_todb($que_info['#']['NAME']['0']['#']); + $question->questiontext = backup_todb($que_info['#']['QUESTIONTEXT']['0']['#']); + $question->image = backup_todb($que_info['#']['IMAGE']['0']['#']); + $question->defaultgrade = backup_todb($que_info['#']['DEFAULTGRADE']['0']['#']); + $question->qtype = backup_todb($que_info['#']['QTYPE']['0']['#']); + + //The structure is equal to the db, so insert the quiz_questions + $newid = insert_record ("quiz_questions",$question); + + //Do some output + if (($i+1) % 2 == 0) { + echo "."; + if (($i+1) % 40 == 0) { + echo "
"; + } + backup_flush(300); + } + + if ($newid) { + //We have the newid, update backup_ids + backup_putid($restore->backup_unique_code,"quiz_questions",$oldid, + $newid); + //Now, restore every quiz_answers in this question + $status = quiz_restore_answers($oldid,$newid,$que_info,$restore); + //Now, depending of the type of questions, invoke different functions + if ($question->qtype == "1") { + $status = quiz_restore_shortanswer($oldid,$newid,$que_info,$restore); + } else if ($question->qtype == "2") { + $status = quiz_restore_truefalse($oldid,$newid,$que_info,$restore); + } else if ($question->qtype == "3") { + $status = quiz_restore_multichoice($oldid,$newid,$que_info,$restore); + } else if ($question->qtype == "4") { + //Random question. Nothing to do. + } else if ($question->qtype == "5") { + $status = quiz_restore_match($oldid,$newid,$que_info,$restore); + } else if ($question->qtype == "6") { + $status = quiz_restore_randomsamatch($oldid,$newid,$que_info,$restore); + } + } else { + $status = false; + } + } + + return $status; + } + + function quiz_restore_answers ($old_question_id,$new_question_id,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the answers array + $answers = $info['#']['ANSWERS']['0']['#']['ANSWER']; + + //Iterate over answers + for($i = 0; $i < sizeof($answers); $i++) { + $ans_info = $answers[$i]; + //traverse_xmlize($ans_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //We'll need this later!! + $oldid = backup_todb($ans_info['#']['ID']['0']['#']); + + //Now, build the QUIZ_ANSWERS record structure + $answer->question = $new_question_id; + $answer->answer = backup_todb($ans_info['#']['ANSWER_TEXT']['0']['#']); + $answer->fraction = backup_todb($ans_info['#']['FRACTION']['0']['#']); + $answer->feedback = backup_todb($ans_info['#']['FEEDBACK']['0']['#']); + + //The structure is equal to the db, so insert the quiz_answers + $newid = insert_record ("quiz_answers",$answer); + + //Do some output + if (($i+1) % 50 == 0) { + echo "."; + if (($i+1) % 1000 == 0) { + echo "
"; + } + backup_flush(300); + } + + if ($newid) { + //We have the newid, update backup_ids + backup_putid($restore->backup_unique_code,"quiz_answers",$oldid, + $newid); + } else { + $status = false; + } + } + + return $status; + } + + function quiz_restore_shortanswer ($old_question_id,$new_question_id,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the shortanswers array + $shortanswers = $info['#']['SHORTANSWER']; + + //Iterate over shortanswers + for($i = 0; $i < sizeof($shortanswers); $i++) { + $sho_info = $shortanswers[$i]; + //traverse_xmlize($sho_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //Now, build the QUIZ_SHORTANSWER record structure + $shortanswer->question = $new_question_id; + $shortanswer->answers = backup_todb($sho_info['#']['ANSWERS']['0']['#']); + $shortanswer->usecase = backup_todb($sho_info['#']['USECASE']['0']['#']); + + //We have to recode the answers field (a list of answers id) + //Extracts answer id from sequence + $answers_field = ""; + $in_first = true; + $tok = strtok($shortanswer->answers,","); + while ($tok) { + //Get the answer from backup_ids + $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$tok); + if ($answer) { + if ($in_first) { + $answers_field .= $answer->new_id; + $in_first = false; + } else { + $answers_field .= ",".$answer->new_id; + } + } + //check for next + $tok = strtok(","); + } + //We have the answers field recoded to its new ids + $shortanswer->answers = $answers_field; + + //The structure is equal to the db, so insert the quiz_shortanswer + $newid = insert_record ("quiz_shortanswer",$shortanswer); + + //Do some output + if (($i+1) % 50 == 0) { + echo "."; + if (($i+1) % 1000 == 0) { + echo "
"; + } + backup_flush(300); + } + + if (!$newid) { + $status = false; + } + } + + return $status; + } + + function quiz_restore_truefalse ($old_question_id,$new_question_id,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the truefalse array + $truefalses = $info['#']['TRUEFALSE']; + + //Iterate over truefalse + for($i = 0; $i < sizeof($truefalses); $i++) { + $tru_info = $truefalses[$i]; + //traverse_xmlize($tru_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //Now, build the QUIZ_TRUEFALSE record structure + $truefalse->question = $new_question_id; + $truefalse->trueanswer = backup_todb($tru_info['#']['TRUEANSWER']['0']['#']); + $truefalse->falseanswer = backup_todb($tru_info['#']['FALSEANSWER']['0']['#']); + + ////We have to recode the trueanswer field + $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$truefalse->trueanswer); + if ($answer) { + $truefalse->trueanswer = $answer->new_id; + } + + ////We have to recode the falseanswer field + $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$truefalse->falseanswer); + if ($answer) { + $truefalse->falseanswer = $answer->new_id; + } + + //The structure is equal to the db, so insert the quiz_truefalse + $newid = insert_record ("quiz_truefalse",$truefalse); + + //Do some output + if (($i+1) % 50 == 0) { + echo "."; + if (($i+1) % 1000 == 0) { + echo "
"; + } + backup_flush(300); + } + + if (!$newid) { + $status = false; + } + } + + return $status; + } + + function quiz_restore_multichoice ($old_question_id,$new_question_id,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the multichoices array + $multichoices = $info['#']['MULTICHOICE']; + + //Iterate over multichoices + for($i = 0; $i < sizeof($multichoices); $i++) { + $mul_info = $multichoices[$i]; + //traverse_xmlize($mul_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //Now, build the QUIZ_MULTICHOICE record structure + $multichoice->question = $new_question_id; + $multichoice->layout = backup_todb($mul_info['#']['LAYOUT']['0']['#']); + $multichoice->answers = backup_todb($mul_info['#']['ANSWERS']['0']['#']); + $multichoice->single = backup_todb($mul_info['#']['SINGLE']['0']['#']); + + //We have to recode the answers field (a list of answers id) + //Extracts answer id from sequence + $answers_field = ""; + $in_first = true; + $tok = strtok($multichoice->answers,","); + while ($tok) { + //Get the answer from backup_ids + $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$tok); + if ($answer) { + if ($in_first) { + $answers_field .= $answer->new_id; + $in_first = false; + } else { + $answers_field .= ",".$answer->new_id; + } + } + //check for next + $tok = strtok(","); + } + //We have the answers field recoded to its new ids + $multichoice->answers = $answers_field; + + //The structure is equal to the db, so insert the quiz_shortanswer + $newid = insert_record ("quiz_multichoice",$multichoice); + + //Do some output + if (($i+1) % 50 == 0) { + echo "."; + if (($i+1) % 1000 == 0) { + echo "
"; + } + backup_flush(300); + } + + if (!$newid) { + $status = false; + } + } + + return $status; + } + + function quiz_restore_match ($old_question_id,$new_question_id,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the matchs array + $matchs = $info['#']['MATCHS']['0']['#']['MATCH']; + + //We have to build the subquestions field (a list of match_sub id) + $subquestions_field = ""; + $in_first = true; + + //Iterate over matchs + for($i = 0; $i < sizeof($matchs); $i++) { + $mat_info = $matchs[$i]; + //traverse_xmlize($mat_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //Now, build the QUIZ_MATCH_SUB record structure + $match_sub->question = $new_question_id; + $match_sub->questiontext = backup_todb($mat_info['#']['QUESTIONTEXT']['0']['#']); + $match_sub->answertext = backup_todb($mat_info['#']['ANSWERTEXT']['0']['#']); + + //The structure is equal to the db, so insert the quiz_match_sub + $newid = insert_record ("quiz_match_sub",$match_sub); + + //Do some output + if (($i+1) % 50 == 0) { + echo "."; + if (($i+1) % 1000 == 0) { + echo "
"; + } + backup_flush(300); + } + + if ($newid) { + //We have a new match_sub, append it to subquestions_field + if ($in_first) { + $subquestions_field .= $newid; + $in_first = false; + } else { + $subquestions_field .= ",".$newid; + } + } else { + $status = false; + } + } + + //We have created every match_sub, now create the match + $match->question = $new_question_id; + $match->subquestions = $subquestions_field; + + //The structure is equal to the db, so insert the quiz_match_sub + $newid = insert_record ("quiz_match",$match); + + if (!$newid) { + $status = false; + } + + return $status; + } + + function quiz_restore_randomsamatch ($old_question_id,$new_question_id,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the randomsamatchs array + $randomsamatchs = $info['#']['RANDOMSAMATCH']; + + //Iterate over randomsamatchs + for($i = 0; $i < sizeof($randomsamatchs); $i++) { + $ran_info = $randomsamatchs[$i]; + //traverse_xmlize($ran_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //Now, build the QUIZ_RANDOMSAMATCH record structure + $randomsamatch->question = $new_question_id; + $randomsamatch->choose = backup_todb($mul_info['#']['CHOOSE']['0']['#']); + + //The structure is equal to the db, so insert the quiz_randomsamatch + $newid = insert_record ("quiz_randomsamatch",$randomsamatch); + + //Do some output + if (($i+1) % 50 == 0) { + echo "."; + if (($i+1) % 1000 == 0) { + echo "
"; + } + backup_flush(300); + } + + if (!$newid) { + $status = false; + } + } + + return $status; + } + + + + + //STEP 2. Restore quizzes and associated structures + // (course dependent) + function quiz_restore_mods($mod,$restore) { + + global $CFG; + + $status = true; + + return $status; + } + +?> diff --git a/backup/restore_execute.html b/backup/restore_execute.html index a89afcdcff..860134ef0b 100644 --- a/backup/restore_execute.html +++ b/backup/restore_execute.html @@ -145,6 +145,12 @@ } } + //Now create categories and questions as needed (STEP1) + if ($status and ($restore->mods[quiz]->restore)) { + echo "
  • Creating Categories and Questions
    "; + $status = restore_create_questions($restore,$xml_file); + } + //Now create user_files as needed if ($status and ($restore->user_files)) { echo "
  • Copying User Files
    "; diff --git a/backup/restorelib.php b/backup/restorelib.php index 6f12fd4ebf..c94703bc60 100644 --- a/backup/restorelib.php +++ b/backup/restorelib.php @@ -84,6 +84,16 @@ return $info; } + //This function read the xml file and store its data from the questions in + //backup_ids->info db (and category's id in $info) + function restore_read_xml_questions ($restore,$xml_file) { + + //We call the main read_xml function, with todo = QUESTIONS + $info = restore_read_xml ($xml_file,"QUESTIONS",$restore); + + return $info; + } + //This function read the xml file and store its data from the modules in //backup_ids->info function restore_read_xml_modules ($restore,$xml_file) { @@ -571,6 +581,45 @@ return $status; } + //This function creates all the categories and questions + //from xml (STEP1 of quiz restore) + function restore_create_questions($restore,$xml_file) { + + global $CFG, $db; + + $status = true; + //Check it exists + if (!file_exists($xml_file)) { + $status = false; + } + //Get info from xml + if ($status) { + //info will contain the old_id of every category + //in backup_ids->info will be the real info (serialized) + $info = restore_read_xml_questions($restore,$xml_file); + } + //Now, if we have anything in info, we have to restore that + //categories/questions + if ($info) { + if ($info !== true) { + //Iterate over each category + foreach ($info as $category) { + $catrestore = "quiz_restore_question_categories"; + if (function_exists($catrestore)) { + //print_object ($category); //Debug + $status = $catrestore($category,$restore); + } else { + //Something was wrong. Function should exist. + $status = false; + } + } + } + } else { + $status = false; + } + return $status; + } + //This function restores the userfiles from the temp (user_files) directory to the //dataroot/users directory function restore_user_files($restore) { @@ -717,7 +766,7 @@ } else { $status = false; } - return $status; + return $status; } //This function adjusts the instance field into course_modules. It's executed after @@ -845,6 +894,29 @@ // echo $this->level.str_repeat(" ",$this->level*2)."<".$tagName.">
    \n"; //Debug } + //This is the startTag handler we use where we are reading the questions zone (todo="QUESTIONS") + function startElementQuestions($parser, $tagName, $attrs) { + //Refresh properties + $this->level++; + $this->tree[$this->level] = $tagName; + +if ($tagName == "QUESTION_CATEGORY" && $this->tree[3] == "QUESTION_CATEGORIES") { +echo "

    QUESTION_CATEGORY: ".strftime ("%X",time()),"-"; +} + + //Output something to avoid browser timeouts... + backup_flush(); + + //Check if we are into QUESTION_CATEGORIES zone + //if ($this->tree[3] == "QUESTION_CATEGORIES") //Debug + // echo $this->level.str_repeat(" ",$this->level*2)."<".$tagName.">
    \n"; //Debug + + //If we are under a QUESTION_CATEGORY tag under a QUESTION_CATEGORIES zone, accumule it + if (($this->tree[4] == "QUESTION_CATEGORY") and ($this->tree[3] == "QUESTION_CATEGORIES")) { + $this->temp .= "<".$tagName.">"; + } + } + //This is the startTag handler we use where we are reading the modules zone (todo="MODULES") function startElementModules($parser, $tagName, $attrs) { //Refresh properties @@ -1329,6 +1401,53 @@ echo "

    MOD: ".strftime ("%X",time()),"-"; $this->content = ""; } + //This is the endTag handler we use where we are reading the modules zone (todo="QUESTIONS") + function endElementQuestions($parser, $tagName) { + //Check if we are into QUESTION_CATEGORIES zone + if ($this->tree[3] == "QUESTION_CATEGORIES") { + //if (trim($this->content)) //Debug + // echo "C".str_repeat(" ",($this->level+2)*2).$this->getContents()."
    \n"; //Debug + //echo $this->level.str_repeat(" ",$this->level*2)."</".$tagName.">
    \n"; //Debug + //Acumulate data to info (content + close tag) + //Reconvert: strip htmlchars again and trim to generate xml data + $this->temp .= htmlspecialchars(trim($this->content)).""; + //If we've finished a mod, xmlize it an save to db + if (($this->level == 4) and ($tagName == "QUESTION_CATEGORY")) { + //Prepend XML standard header to info gathered + $xml_data = "\n".$this->temp; + //Call to xmlize for this portion of xml data (one MOD) + echo "-XMLIZE: ".strftime ("%X",time()),"-"; + $data = xmlize($xml_data); + echo strftime ("%X",time())."

    "; + //traverse_xmlize($data); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + //Now, save data to db. We'll use it later + //Get id and modtype from data + $category_id = $data["QUESTION_CATEGORY"]["#"]["ID"]["0"]["#"]; + //Save to db + $status = backup_putid($this->preferences->backup_unique_code,"quiz_categories",$category_id, + null,$data); + //Create returning info + $ret_info->id = $category_id; + $this->info[] = $ret_info; + //Reset temp + unset($this->temp); + } + } + + //Stop parsing if todo = QUESTION_CATEGORIES and tagName = QUESTION_CATEGORY (en of the tag, of course) + //Speed up a lot (avoid parse all) + if ($tagName == "QUESTION_CATEGORIES" and $this->level == 3) { + $this->finished = true; + } + + //Clear things + $this->tree[$this->level] = ""; + $this->level--; + $this->content = ""; + } + //This is the endTag handler we use where we are reading the modules zone (todo="MODULES") function endElementModules($parser, $tagName) { //Check if we are into MODULES zone @@ -1423,6 +1542,9 @@ echo "

    MOD: ".strftime ("%X",time()),"-"; } else if ($todo == "USERS") { //Define handlers to that zone xml_set_element_handler($xml_parser, "startElementUsers", "endElementUsers"); + } else if ($todo == "QUESTIONS") { + //Define handlers to that zone + xml_set_element_handler($xml_parser, "startElementQuestions", "endElementQuestions"); } else if ($todo == "MODULES") { //Define handlers to that zone xml_set_element_handler($xml_parser, "startElementModules", "endElementModules");