From 9fd687e0d2e6d8f300e884e6a53a65b07c8c1039 Mon Sep 17 00:00:00 2001 From: stronk7 Date: Fri, 6 Aug 2004 23:43:19 +0000 Subject: [PATCH] Now CALCULATED questions are in backup & restore. It was difficult to understand but easy to implement :-) Some mechanisms has been added to avoid to duplicate quiz_dataset_definitions (confirmed from Henrik). Please, test, test, test, test.... --- mod/quiz/backuplib.php | 138 ++++++++++++++++++++++--- mod/quiz/restorelib.php | 220 +++++++++++++++++++++++++++++++++++++--- 2 files changed, 330 insertions(+), 28 deletions(-) diff --git a/mod/quiz/backuplib.php b/mod/quiz/backuplib.php index 92afbea150..46e7bc1b70 100644 --- a/mod/quiz/backuplib.php +++ b/mod/quiz/backuplib.php @@ -10,19 +10,25 @@ // (CL,pk->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_attempts quiz_grades quiz_question_grades | ----quiz_question_datasets---- . + // (UL,pk->id, fk->quiz) (UL,pk->id,fk->quiz) (CL,pk->id,fk->quiz) | | (CL,pk->id,fk->question, | . + // | | | | fk->dataset_definition) | . + // | | | | | . + // | | | | | . + // | | | | | . + // quiz_responses | quiz_questions quiz_dataset_definitions + // (UL,pk->id, fk->attempt)----------------------------------------------------(CL,pk->id,fk->category,files) (CL,pk->id,fk->category) + // | | + // | | + // | | + // | quiz_dataset_items + // | (CL,pk->id,fk->definition) + // | + // | + // | // -------------------------------------------------------------------------------------------------------------- // | | | | | | | // | | | | | | | @@ -68,8 +74,12 @@ // - quiz_randomsamatch // - quiz_match // - quiz_match_sub + // - quiz_calculated // - quiz_answers // - quiz_numerical_units + // - quiz_question_datasets + // - quiz_dataset_definitions + // - quiz_dataset_items // 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 backup quizzes has been selected !! // It's invoked with quiz_backup_question_categories. (course independent). @@ -168,6 +178,8 @@ $status = quiz_backup_numerical($bf,$preferences,$question->id); } else if ($question->qtype == "9") { $status = quiz_backup_multianswer($bf,$preferences,$question->id); + } else if ($question->qtype == "10") { + $status = quiz_backup_calculated($bf,$preferences,$question->id); } //End question $status =fwrite ($bf,end_tag("QUESTION",5,true)); @@ -388,8 +400,42 @@ return $status; } + //This function backups the data in a calculated question (qtype=10) and its + //asociated data + function quiz_backup_calculated($bf,$preferences,$question,$level=6,$include_answers=true) { + + global $CFG; + + $status = true; + + $calculateds = get_records("quiz_calculated","question",$question,"id"); + //If there are calculated-s + if ($calculateds) { + //Iterate over each calculateds + foreach ($calculateds as $calculated) { + $status =fwrite ($bf,start_tag("CALCULATED",$level,true)); + //Print calculated contents + fwrite ($bf,full_tag("ANSWER",$level+1,false,$calculated->answer)); + fwrite ($bf,full_tag("TOLERANCE",$level+1,false,$calculated->tolerance)); + fwrite ($bf,full_tag("TOLERANCETYPE",$level+1,false,$calculated->tolerancetype)); + fwrite ($bf,full_tag("CORRECTANSWERLENGTH",$level+1,false,$calculated->correctanswerlength)); + //Now backup numerical_units + $status = quiz_backup_numerical_units($bf,$preferences,$question,7); + //Now backup required dataset definitions and items... + $status = quiz_backup_datasets($bf,$preferences,$question,7); + //End calculated data + $status =fwrite ($bf,end_tag("CALCULATED",$level,true)); + } + //Now print quiz_answers + if ($include_answers) { + $status = quiz_backup_answers($bf,$preferences,$question); + } + } + return $status; + } + //This function backups the answers data in some question types - //(truefalse, shortanswer,multichoice,numerical) + //(truefalse, shortanswer,multichoice,numerical,calculated) function quiz_backup_answers($bf,$preferences,$question) { global $CFG; @@ -442,6 +488,70 @@ } + //This function backups dataset_definitions (via question_datasets) from different question types + function quiz_backup_datasets($bf,$preferences,$question,$level=7) { + + global $CFG; + + $status = true; + + //First, we get the used datasets for this question + $question_datasets = get_records("quiz_question_datasets","question",$question,"id"); + //If there are question_datasets + if ($question_datasets) { + $status =fwrite ($bf,start_tag("DATASET_DEFINITIONS",$level,true)); + //Iterate over each question_dataset + foreach ($question_datasets as $question_dataset) { + $def = NULL; + //Get dataset_definition + if ($def = get_record("quiz_dataset_definitions","id",$question_dataset->datasetdefinition)) {; + $status =fwrite ($bf,start_tag("DATASET_DEFINITION",$level+1,true)); + //Print question_dataset contents + fwrite ($bf,full_tag("CATEGORY",$level+2,false,$def->category)); + fwrite ($bf,full_tag("NAME",$level+2,false,$def->name)); + fwrite ($bf,full_tag("TYPE",$level+2,false,$def->type)); + fwrite ($bf,full_tag("OPTIONS",$level+2,false,$def->options)); + fwrite ($bf,full_tag("ITEMCOUNT",$level+2,false,$def->itemcount)); + //Now backup dataset_entries + $status = quiz_backup_dataset_items($bf,$preferences,$def->id,$level+2); + //End dataset definition + $status =fwrite ($bf,end_tag("DATASET_DEFINITION",$level+1,true)); + } + } + $status =fwrite ($bf,end_tag("DATASET_DEFINITIONS",$level,true)); + } + + return $status; + + } + + //This function backups datases_items from dataset_definitions + function quiz_backup_dataset_items($bf,$preferences,$datasetdefinition,$level=9) { + + global $CFG; + + $status = true; + + //First, we get the datasets_items for this dataset_definition + $dataset_items = get_records("quiz_dataset_items","definition",$datasetdefinition,"id"); + //If there are dataset_items + if ($dataset_items) { + $status =fwrite ($bf,start_tag("DATASET_ITEMS",$level,true)); + //Iterate over each dataset_item + foreach ($dataset_items as $dataset_item) { + $status =fwrite ($bf,start_tag("DATASET_ITEM",$level+1,true)); + //Print question_dataset contents + fwrite ($bf,full_tag("NUMBER",$level+2,false,$dataset_item->number)); + fwrite ($bf,full_tag("VALUE",$level+2,false,$dataset_item->value)); + //End dataset definition + $status =fwrite ($bf,end_tag("DATASET_ITEM",$level+1,true)); + } + $status =fwrite ($bf,end_tag("DATASET_ITEMS",$level,true)); + } + + return $status; + + } //STEP 2. Backup quizzes and associated structures // (course dependent) diff --git a/mod/quiz/restorelib.php b/mod/quiz/restorelib.php index 8128b70e25..2d3542d75d 100644 --- a/mod/quiz/restorelib.php +++ b/mod/quiz/restorelib.php @@ -2,7 +2,7 @@ //This php script contains all the stuff to backup/restore //quiz mods - //To see, put your terminal to 132cc + //To see, put your terminal to 160cc //This is the "graphical" structure of the quiz mod: // @@ -10,16 +10,22 @@ // (CL,pk->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_attempts quiz_grades quiz_question_grades | ----quiz_question_datasets---- . + // (UL,pk->id, fk->quiz) (UL,pk->id,fk->quiz) (CL,pk->id,fk->quiz) | | (CL,pk->id,fk->question, | . + // | | | | fk->dataset_definition) | . + // | | | | | . + // | | | | | . + // | | | | | . + // quiz_responses | quiz_questions quiz_dataset_definitions + // (UL,pk->id, fk->attempt)----------------------------------------------------(CL,pk->id,fk->category,files) (CL,pk->id,fk->category) + // | | + // | | + // | | + // | quiz_dataset_items + // | (CL,pk->id,fk->definition) // | // | // | @@ -66,8 +72,12 @@ // - quiz_randomsamatch // - quiz_match // - quiz_match_sub + // - quiz_calculated // - quiz_answers // - quiz_numerical_units + // - quiz_question_datasets + // - quiz_dataset_definitions + // - quiz_dataset_items // 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). @@ -378,6 +388,8 @@ $status = quiz_restore_numerical($oldid,$newid,$que_info,$restore); } else if ($question->qtype == "9") { $status = quiz_restore_multianswer($oldid,$newid,$que_info,$restore); + } else if ($question->qtype == "10") { + $status = quiz_restore_calculated($oldid,$newid,$que_info,$restore); } } else { //We are NOT creating the question, but we need to know every quiz_answers @@ -405,6 +417,8 @@ //Numerical question. Nothing to remap } else if ($question->qtype == "9") { $status = quiz_restore_map_multianswer($oldid,$newid,$que_info,$restore); + } else if ($question->qtype == "10") { + //Calculated question. Nothing to remap } } } @@ -972,6 +986,63 @@ return $status; } + function quiz_restore_calculated ($old_question_id,$new_question_id,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the calculated-s array + $calculateds = $info['#']['CALCULATED']; + + //Iterate over calculateds + for($i = 0; $i < sizeof($calculateds); $i++) { + $cal_info = $calculateds[$i]; + //traverse_xmlize($cal_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //Now, build the QUIZ_CALCULATED record structure + $calculated->question = $new_question_id; + $calculated->answer = backup_todb($cal_info['#']['ANSWER']['0']['#']); + $calculated->tolerance = backup_todb($cal_info['#']['TOLERANCE']['0']['#']); + $calculated->tolerancetype = backup_todb($cal_info['#']['TOLERANCETYPE']['0']['#']); + $calculated->correctanswerlength = backup_todb($cal_info['#']['CORRECTANSWERLENGTH']['0']['#']); + + ////We have to recode the answer field + $answer = backup_getid($restore->backup_unique_code,"quiz_answers",$calculated->answer); + if ($answer) { + $calculated->answer = $answer->new_id; + } + + //The structure is equal to the db, so insert the quiz_calculated + $newid = insert_record ("quiz_calculated",$calculated); + + //Do some output + if (($i+1) % 50 == 0) { + echo "."; + if (($i+1) % 1000 == 0) { + echo "
"; + } + backup_flush(300); + } + + //Now restore numerical_units + $status = quiz_restore_numerical_units ($old_question_id,$new_question_id,$cal_info,$restore); + + //Now restore dataset_definitions + if ($status && $newid) { + $status = quiz_restore_dataset_definitions ($old_question_id,$new_question_id,$cal_info,$restore); + } + + if (!$newid) { + $status = false; + } + } + + return $status; + } + function quiz_restore_multianswer ($old_question_id,$new_question_id,$info,$restore) { global $CFG; @@ -1067,9 +1138,9 @@ //Iterate over numerical_units for($i = 0; $i < sizeof($numerical_units); $i++) { $nu_info = $numerical_units[$i]; - traverse_xmlize($nu_info); //Debug - print_object ($GLOBALS['traverse_array']); //Debug - $GLOBALS['traverse_array']=""; //Debug + //traverse_xmlize($nu_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug //Now, build the QUIZ_NUMERICAL_UNITS record structure $numerical_unit->question = $new_question_id; @@ -1087,6 +1158,124 @@ return $status; } + function quiz_restore_dataset_definitions ($old_question_id,$new_question_id,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the dataset_definitions array + $dataset_definitions = $info['#']['DATASET_DEFINITIONS']['0']['#']['DATASET_DEFINITION']; + + //Iterate over dataset_definitions + for($i = 0; $i < sizeof($dataset_definitions); $i++) { + $dd_info = $dataset_definitions[$i]; + //traverse_xmlize($dd_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //Now, build the QUIZ_DATASET_DEFINITION record structure + $dataset_definition->category = backup_todb($dd_info['#']['CATEGORY']['0']['#']); + $dataset_definition->name = backup_todb($dd_info['#']['NAME']['0']['#']); + $dataset_definition->type = backup_todb($dd_info['#']['TYPE']['0']['#']); + $dataset_definition->options = backup_todb($dd_info['#']['OPTIONS']['0']['#']); + $dataset_definition->itemcount = backup_todb($dd_info['#']['ITEMCOUNT']['0']['#']); + + //We have to recode the category field (only if the category != 0) + if ($dataset_definition->category != 0) { + $category = backup_getid($restore->backup_unique_code,"quiz_categories",$dataset_definition->category); + if ($category) { + $dataset_definition->category = $category->new_id; + } + } + + //Now, we hace to decide when to create the new records or reuse an existing one + $create_definition = false; + + //If the dataset_definition->category = 0, it's a individual question dataset_definition, so we'll create it + if ($dataset_definition->category == 0) { + $create_definition = true; + } else { + //The category isn't 0, so it's a category question dataset_definition, we have to see if it exists + //Look for a definition with the same category, name and type + if ($definitionrec = get_record_sql("SELECT d.* + FROM {$CFG->prefix}quiz_dataset_definitions d + WHERE d.category = '$dataset_definition->category' AND + d.name = '$dataset_definition->name' AND + d.type = '$dataset_definition->type'")) { + //Such dataset_definition exist. Now we must check if it has enough itemcount + if ($definitionrec->itemcount < $dataset_definition->itemcount) { + //We haven't enough itemcount, so we have to create the definition as an individual question one. + $dataset_definition->category = 0; + $create_definition = true; + } else { + //We have enough itemcount, so we'll reuse the existing definition + $create_definition = false; + $newid = $definitionrec->id; + } + } else { + //Such dataset_definition doesn't exist. We'll create it. + $create_definition = true; + } + } + + //If we've to create the definition, do it + if ($create_definition) { + //The structure is equal to the db, so insert the quiz_dataset_definitions + $newid = insert_record ("quiz_dataset_definitions",$dataset_definition); + if ($newid) { + //Restore quiz_dataset_items + $status = quiz_restore_dataset_items($newid,$dd_info,$restore); + } + } + + //Now, we must have a definition (created o reused). Its id is in newid. Create the quiz_question_datasets record + //to join the question and the dataset_definition + if ($newid) { + $question_dataset->question = $new_question_id; + $question_dataset->datasetdefinition = $newid; + $newid = insert_record ("quiz_question_datasets",$question_dataset); + } + + if (!$newid) { + $status = false; + } + } + + return $status; + } + + function quiz_restore_dataset_items ($definitionid,$info,$restore) { + + global $CFG; + + $status = true; + + //Get the items array + $dataset_items = $info['#']['DATASET_ITEMS']['0']['#']['DATASET_ITEM']; + + //Iterate over dataset_items + for($i = 0; $i < sizeof($dataset_items); $i++) { + $di_info = $dataset_items[$i]; + //traverse_xmlize($di_info); //Debug + //print_object ($GLOBALS['traverse_array']); //Debug + //$GLOBALS['traverse_array']=""; //Debug + + //Now, build the QUIZ_DATASET_ITEMS record structure + $dataset_item->definition = $definitionid; + $dataset_item->number = backup_todb($di_info['#']['NUMBER']['0']['#']); + $dataset_item->value = backup_todb($di_info['#']['VALUE']['0']['#']); + + //The structure is equal to the db, so insert the quiz_dataset_items + $newid = insert_record ("quiz_dataset_items",$dataset_item); + + if (!$newid) { + $status = false; + } + } + + return $status; + } //STEP 2. Restore quizzes and associated structures // (course dependent) @@ -1492,6 +1681,9 @@ } $response->answer = $answer_field; break; + case 10: //CALCULATED QTYPE + //Nothing to do. The response is a text. + break; default: //UNMATCHED QTYPE. //This is an error (unimplemented qtype) $status = false; -- 2.39.5