get_string("gradehighest", "quiz"), GRADEAVERAGE => get_string("gradeaverage", "quiz"), ATTEMPTFIRST => get_string("attemptfirst", "quiz"), ATTEMPTLAST => get_string("attemptlast", "quiz")); define("SHORTANSWER", "1"); define("TRUEFALSE", "2"); define("MULTICHOICE", "3"); define("RANDOM", "4"); define("MATCH", "5"); define("RANDOMSAMATCH", "6"); $QUIZ_QUESTION_TYPE = array ( MULTICHOICE => get_string("multichoice", "quiz"), TRUEFALSE => get_string("truefalse", "quiz"), SHORTANSWER => get_string("shortanswer", "quiz"), MATCH => get_string("match", "quiz"), RANDOM => get_string("random", "quiz"), RANDOMSAMATCH => get_string("randomsamatch", "quiz") ); $QUIZ_FILE_FORMAT = array ( "custom" => get_string("custom", "quiz"), "missingword" => get_string("missingword", "quiz"), "blackboard" => get_string("blackboard", "quiz"), "aon" => "AON" ); define("QUIZ_PICTURE_DEFAULT_HEIGHT", "200"); define("QUIZ_MAX_NUMBER_ANSWERS", "8"); /// FUNCTIONS /////////////////////////////////////////////////////////////////// function quiz_add_instance($quiz) { /// Given an object containing all the necessary data, /// (defined by the form in mod.html) this function /// will create a new instance and return the id number /// of the new instance. $quiz->created = time(); $quiz->timemodified = time(); $quiz->timeopen = make_timestamp($quiz->openyear, $quiz->openmonth, $quiz->openday, $quiz->openhour, $quiz->openminute, 0); $quiz->timeclose = make_timestamp($quiz->closeyear, $quiz->closemonth, $quiz->closeday, $quiz->closehour, $quiz->closeminute, 0); if (!$quiz->id = insert_record("quiz", $quiz)) { return false; // some error occurred } // The grades for every question in this quiz are stored in an array if ($quiz->grades) { foreach ($quiz->grades as $question => $grade) { if ($question and $grade) { unset($questiongrade); $questiongrade->quiz = $quiz->id; $questiongrade->question = $question; $questiongrade->grade = $grade; if (!insert_record("quiz_question_grades", $questiongrade)) { return false; } } } } return $quiz->id; } function quiz_update_instance($quiz) { /// Given an object containing all the necessary data, /// (defined by the form in mod.html) this function /// will update an existing instance with new data. $quiz->timemodified = time(); $quiz->timeopen = make_timestamp($quiz->openyear, $quiz->openmonth, $quiz->openday, $quiz->openhour, $quiz->openminute, 0); $quiz->timeclose = make_timestamp($quiz->closeyear, $quiz->closemonth, $quiz->closeday, $quiz->closehour, $quiz->closeminute, 0); $quiz->id = $quiz->instance; if (!update_record("quiz", $quiz)) { return false; // some error occurred } // The grades for every question in this quiz are stored in an array // Insert or update records as appropriate $existing = get_records("quiz_question_grades", "quiz", $quiz->id, "", "question,grade,id"); if ($quiz->grades) { foreach ($quiz->grades as $question => $grade) { if ($question and $grade) { unset($questiongrade); $questiongrade->quiz = $quiz->id; $questiongrade->question = $question; $questiongrade->grade = $grade; if (isset($existing[$question])) { if ($existing[$question]->grade != $grade) { $questiongrade->id = $existing[$question]->id; if (!update_record("quiz_question_grades", $questiongrade)) { return false; } } } else { if (!insert_record("quiz_question_grades", $questiongrade)) { return false; } } } } } return true; } function quiz_delete_instance($id) { /// Given an ID of an instance of this module, /// this function will permanently delete the instance /// and any data that depends on it. if (! $quiz = get_record("quiz", "id", "$id")) { return false; } $result = true; if ($attempts = get_record("quiz_attempts", "quiz", "$quiz->id")) { foreach ($attempts as $attempt) { if (! delete_records("quiz_responses", "attempt", "$attempt->id")) { $result = false; } } } if (! delete_records("quiz_attempts", "quiz", "$quiz->id")) { $result = false; } if (! delete_records("quiz_grades", "quiz", "$quiz->id")) { $result = false; } if (! delete_records("quiz_question_grades", "quiz", "$quiz->id")) { $result = false; } if (! delete_records("quiz", "id", "$quiz->id")) { $result = false; } return $result; } function quiz_user_outline($course, $user, $mod, $quiz) { /// Return a small object with summary information about what a /// user has done with a given particular instance of this module /// Used for user activity reports. /// $return->time = the time they did it /// $return->info = a short text description if ($grade = get_record("quiz_grades", "userid", $user->id, "quiz", $quiz->id)) { if ($grade->grade) { $result->info = get_string("grade").": $grade->grade"; } $result->time = $grade->timemodified; return $result; } return NULL; return $return; } function quiz_user_complete($course, $user, $mod, $quiz) { /// Print a detailed representation of what a user has done with /// a given particular instance of this module, for user activity reports. return true; } function quiz_cron () { /// Function to be run periodically according to the moodle cron /// This function searches for things that need to be done, such /// as sending out mail, toggling flags etc ... global $CFG; return true; } function quiz_grades($quizid) { /// Must return an array of grades, indexed by user, and a max grade. $return->grades = get_records_menu("quiz_grades", "quiz", $quizid, "", "userid,grade"); $return->maxgrade = get_field("quiz", "grade", "id", "$quizid"); return $return; } /// SQL FUNCTIONS //////////////////////////////////////////////////////////////////// function quiz_move_questions($category1, $category2) { global $CFG; return execute_sql("UPDATE {$CFG->prefix}quiz_questions SET category = '$category2' WHERE category = '$category1'", false); } function quiz_get_question_grades($quizid, $questionlist) { global $CFG; return get_records_sql("SELECT question,grade FROM {$CFG->prefix}quiz_question_grades WHERE quiz = '$quizid' AND question IN ($questionlist)"); } function quiz_get_random_categories($questionlist) { /// Given an array of questions, this function looks for random /// questions among them and returns a list of categories with /// an associated count of random questions for each. global $CFG; return get_records_sql_menu("SELECT category,count(*) FROM {$CFG->prefix}quiz_questions WHERE id IN ($questionlist) AND qtype = '".RANDOM."' GROUP BY category "); } function quiz_get_grade_records($quiz) { /// Gets all info required to display the table of quiz results /// for report.php global $CFG; return get_records_sql("SELECT qg.*, u.firstname, u.lastname, u.picture FROM {$CFG->prefix}quiz_grades qg, {$CFG->prefix}user u WHERE qg.quiz = '$quiz->id' AND qg.userid = u.id"); } function quiz_get_answers($question) { // Given a question, returns the correct answers for a given question global $CFG; switch ($question->qtype) { case SHORTANSWER: // Could be multiple answers return get_records_sql("SELECT a.*, sa.usecase FROM {$CFG->prefix}quiz_shortanswer sa, {$CFG->prefix}quiz_answers a WHERE sa.question = '$question->id' AND sa.question = a.question "); break; case TRUEFALSE: // Should be always two answers return get_records("quiz_answers", "question", $question->id); break; case MULTICHOICE: // Should be multiple answers return get_records_sql("SELECT a.*, mc.single FROM {$CFG->prefix}quiz_multichoice mc, {$CFG->prefix}quiz_answers a WHERE mc.question = '$question->id' AND mc.question = a.question "); break; case MATCH: return get_records("quiz_match_sub", "question", $question->id); break; case RANDOMSAMATCH: // Could be any of many answers, return them all return get_records_sql("SELECT a.* FROM {$CFG->prefix}quiz_questions q, {$CFG->prefix}quiz_answers a WHERE q.category = '$question->category' AND q.qtype = ".SHORTANSWER." AND q.id = a.question "); break; default: return false; } } function quiz_get_attempt_responses($attempt, $quiz) { // Given an attempt object, this function gets all the // stored responses and returns them in a format suitable // for regrading using quiz_grade_attempt_results() global $CFG; if (!$responses = get_records_sql("SELECT q.id, q.qtype, q.category, q.questiontext, r.answer FROM {$CFG->prefix}quiz_responses r, {$CFG->prefix}quiz_questions q WHERE r.attempt = '$attempt->id' AND q.id = r.question")) { notify("Could not find any responses for that attempt!"); return false; } foreach ($responses as $key => $response) { if ($response->qtype == RANDOM) { $responses[$key]->random = $response->answer; $responses[$key]->answer = explode(",",$responses[$response->answer]->answer); $responses[$response->answer]->delete = true; } else { $responses[$key]->answer = explode(",",$response->answer); } } foreach ($responses as $key => $response) { if (!empty($response->delete)) { unset($responses[$key]); } } return $responses; } ////////////////////////////////////////////////////////////////////////////////////// /// Any other quiz functions go here. Each of them must have a name that /// starts with quiz_ function quiz_print_comment($text) { global $THEME; echo "".text_to_html($text, true, false).""; } function quiz_print_correctanswer($text) { global $THEME; echo "
$text
"; } function quiz_print_question_icon($question, $editlink=true) { // Prints a question icon global $QUIZ_QUESTION_TYPE; if ($editlink) { echo "id\" TITLE=\"".$QUIZ_QUESTION_TYPE[$question->qtype]."\">"; } switch ($question->qtype) { case SHORTANSWER: echo "";
echo " $number "; if ($feedback or $response) { echo "$strmarks: $actualgrade/$grade "; } else { echo "$grade $strmarks "; } print_spacer(1,100); echo " | ";
if (empty($realquestion)) {
$realquestion->id = $question->id;
} else { // Add a marker to connect this question to the actual random parent
echo "id}rq$question->id\" value=\"x\">\n";
}
switch ($question->qtype) {
case SHORTANSWER:
if (!$options = get_record("quiz_shortanswer", "question", $question->id)) {
notify("Error: Missing question options!");
}
echo text_to_html($question->questiontext);
if ($question->image) {
print_file_picture($question->image, $courseid, QUIZ_PICTURE_DEFAULT_HEIGHT);
}
if ($response) {
$value = "VALUE=\"$response[0]\"";
} else {
$value = "";
}
echo " $stranswer: id SIZE=20 $value> "; if ($feedback) { quiz_print_comment("$feedback[0] "); } if ($correct) { $correctanswers = implode(", ", $correct); quiz_print_correctanswer($correctanswers); } break; case TRUEFALSE: if (!$options = get_record("quiz_truefalse", "question", $question->id)) { notify("Error: Missing question options!"); } if (!$true = get_record("quiz_answers", "id", $options->trueanswer)) { notify("Error: Missing question answers!"); } if (!$false = get_record("quiz_answers", "id", $options->falseanswer)) { notify("Error: Missing question answers!"); } if (!$true->answer) { $true->answer = get_string("true", "quiz"); } if (!$false->answer) { $false->answer = get_string("false", "quiz"); } echo text_to_html($question->questiontext); if ($question->image) { print_file_picture($question->image, $courseid, QUIZ_PICTURE_DEFAULT_HEIGHT); } $truechecked = ""; $falsechecked = ""; if (!empty($response[$true->id])) { $truechecked = "CHECKED"; $feedbackid = $true->id; } else if (!empty($response[$false->id])) { $falsechecked = "CHECKED"; $feedbackid = $false->id; } $truecorrect = ""; $falsecorrect = ""; if ($correct) { if (!empty($correct[$true->id])) { $truecorrect = "CLASS=highlight"; } if (!empty($correct[$false->id])) { $falsecorrect = "CLASS=highlight"; } } echo "
"; if ($feedback) { quiz_print_comment(" $feedback[$feedbackid] "); } break; case MULTICHOICE: if (!$options = get_record("quiz_multichoice", "question", $question->id)) { notify("Error: Missing question options!"); } if (!$answers = get_records_list("quiz_answers", "id", $options->answers)) { notify("Error: Missing question answers!"); } echo text_to_html($question->questiontext); if ($question->image) { print_file_picture($question->image, $courseid, QUIZ_PICTURE_DEFAULT_HEIGHT); } echo "
Random questions should not be printed this way! "; break; default: notify("Error: Unknown question type!"); } echo " |
"; echo ""; echo " | "; echo ""; echo " |
"; print_string("noquestions", "quiz"); echo "
"; return; } $order = explode(",", $questionlist); if (!$questions = get_records_list("quiz_questions", "id", $questionlist)) { echo ""; print_string("noquestions", "quiz"); echo "
"; return; } $strorder = get_string("order"); $strquestionname = get_string("questionname", "quiz"); $strgrade = get_string("grade"); $strdelete = get_string("delete"); $stredit = get_string("edit"); $strmoveup = get_string("moveup"); $strmovedown = get_string("movedown"); $strsavegrades = get_string("savegrades", "quiz"); $strtype = get_string("type", "quiz"); for ($i=10; $i>=0; $i--) { $gradesmenu[$i] = $i; } $count = 0; $sumgrade = 0; $total = count($order); echo ""; return $sumgrade; } function quiz_print_cat_question_list($categoryid) { // Prints a form to choose categories global $THEME, $QUIZ_QUESTION_TYPE; $strcategory = get_string("category", "quiz"); $strquestion = get_string("question", "quiz"); $straddquestions = get_string("addquestions", "quiz"); $strimportquestions = get_string("importquestions", "quiz"); $strnoquestions = get_string("noquestions", "quiz"); $strselect = get_string("select", "quiz"); $strselectall = get_string("selectall", "quiz"); $strcreatenewquestion = get_string("createnewquestion", "quiz"); $strquestionname = get_string("questionname", "quiz"); $strdelete = get_string("delete"); $stredit = get_string("edit"); $straddselectedtoquiz = get_string("addselectedtoquiz", "quiz"); $strtype = get_string("type", "quiz"); $strcreatemultiple = get_string("createmultiple", "quiz"); if (!$categoryid) { echo ""; print_string("selectcategoryabove", "quiz"); echo "
"; return; } if (!$category = get_record("quiz_categories", "id", "$categoryid")) { notify("Category not found!"); return; } echo "$straddquestions: | "; echo ""; echo ""; echo ""; echo ""; echo " |
"; print_string("noquestions", "quiz"); echo "
"; return; } $canedit = isteacher($category->course); echo ""; } function quiz_start_attempt($quizid, $userid, $numattempt) { $attempt->quiz = $quizid; $attempt->userid = $userid; $attempt->attempt = $numattempt; $attempt->timestart = time(); $attempt->timefinish = 0; $attempt->timemodified = time(); return insert_record("quiz_attempts", $attempt); } function quiz_get_user_attempt_unfinished($quizid, $userid) { // Returns an object containing an unfinished attempt (if there is one) return get_record("quiz_attempts", "quiz", $quizid, "userid", $userid, "timefinish", 0); } function quiz_get_user_attempts($quizid, $userid) { // Returns a list of all attempts by a user return get_records_select("quiz_attempts", "quiz = '$quizid' AND userid = '$userid' AND timefinish > 0", "attempt ASC"); } function quiz_get_user_attempts_string($quiz, $attempts, $bestgrade) { /// Returns a simple little comma-separated list of all attempts, /// with each grade linked to the feedback report and with the best grade highlighted $bestgrade = format_float($bestgrade); foreach ($attempts as $attempt) { $attemptgrade = format_float(($attempt->sumgrades / $quiz->sumgrades) * $quiz->grade); if ($attemptgrade == $bestgrade) { $userattempts[] = "id&attempt=$attempt->id\">$attemptgrade"; } else { $userattempts[] = "id&attempt=$attempt->id\">$attemptgrade"; } } return implode(",", $userattempts); } function quiz_get_best_grade($quizid, $userid) { /// Get the best current grade for a particular user in a quiz if (!$grade = get_record("quiz_grades", "quiz", $quizid, "userid", $userid)) { return 0; } return (round($grade->grade,0)); } function quiz_save_best_grade($quiz, $userid) { /// Calculates the best grade out of all attempts at a quiz for a user, /// and then saves that grade in the quiz_grades table. if (!$attempts = quiz_get_user_attempts($quiz->id, $userid)) { notify("Could not find any user attempts"); return false; } $bestgrade = quiz_calculate_best_grade($quiz, $attempts); $bestgrade = (($bestgrade / $quiz->sumgrades) * $quiz->grade); if ($grade = get_record("quiz_grades", "quiz", $quiz->id, "userid", $userid)) { $grade->grade = round($bestgrade, 2); $grade->timemodified = time(); if (!update_record("quiz_grades", $grade)) { notify("Could not update best grade"); return false; } } else { $grade->quiz = $quiz->id; $grade->userid = $userid; $grade->grade = round($bestgrade, 2); $grade->timemodified = time(); if (!insert_record("quiz_grades", $grade)) { notify("Could not insert new best grade"); return false; } } return true; } function quiz_calculate_best_grade($quiz, $attempts) { /// Calculate the best grade for a quiz given a number of attempts by a particular user. switch ($quiz->grademethod) { case ATTEMPTFIRST: foreach ($attempts as $attempt) { return $attempt->sumgrades; } break; case ATTEMPTLAST: foreach ($attempts as $attempt) { $final = $attempt->sumgrades; } return $final; case GRADEAVERAGE: $sum = 0; $count = 0; foreach ($attempts as $attempt) { $sum += $attempt->sumgrades; $count++; } return (float)$sum/$count; default: case GRADEHIGHEST: $max = 0; foreach ($attempts as $attempt) { if ($attempt->sumgrades > $max) { $max = $attempt->sumgrades; } } return $max; } } function quiz_save_attempt($quiz, $questions, $result, $attemptnum) { /// Given a quiz, a list of attempted questions and a total grade /// this function saves EVERYTHING so it can be reconstructed later /// if necessary. global $USER; // First find the attempt in the database (start of attempt) if (!$attempt = quiz_get_user_attempt_unfinished($quiz->id, $USER->id)) { notify("Trying to save an attempt that was not started!"); return false; } if ($attempt->attempt != $attemptnum) { // Double check. notify("Number of this attempt is different to the unfinished one!"); return false; } // Now let's complete this record and save it $attempt->sumgrades = $result->sumgrades; $attempt->timefinish = time(); $attempt->timemodified = time(); if (! update_record("quiz_attempts", $attempt)) { notify("Error while saving attempt"); return false; } // Now let's save all the questions for this attempt foreach ($questions as $question) { $response->attempt = $attempt->id; $response->question = $question->id; $response->grade = $result->grades[$question->id]; if (!empty($question->random)) { // First save the response of the random question // the answer is the id of the REAL response $response->answer = $question->random; if (!insert_record("quiz_responses", $response)) { notify("Error while saving response"); return false; } $response->question = $question->random; } if (!empty($question->answer)) { $response->answer = implode(",",$question->answer); } else { $response->answer = ""; } if (!insert_record("quiz_responses", $response)) { notify("Error while saving response"); return false; } } return true; } function quiz_grade_attempt_results($quiz, $questions) { /// Given a list of questions (including answers for each one) /// this function does all the hard work of calculating the /// grades for each question, as well as a total grade for /// for the whole quiz. It returns everything in a structure /// that looks like: /// $result->sumgrades (sum of all grades for all questions) /// $result->percentage (Percentage of grades that were correct) /// $result->grade (final grade result for the whole quiz) /// $result->grades[] (array of grades, indexed by question id) /// $result->response[] (array of response arrays, indexed by question id) /// $result->feedback[] (array of feedback arrays, indexed by question id) /// $result->correct[] (array of feedback arrays, indexed by question id) if (!$questions) { error("No questions!"); } if (!$grades = get_records_menu("quiz_question_grades", "quiz", $quiz->id, "", "question,grade")) { error("No grades defined for these quiz questions!"); } $result->sumgrades = 0; foreach ($questions as $question) { if (!empty($question->random)) { // This question has been randomly chosen $randomquestion = $question; // Save it for later if (!$question = get_record("quiz_questions", "id", $question->random)) { error("Could not find the real question behind this random question!"); } if (isset($randomquestion->answer)) { $question->answer = $randomquestion->answer; } else { $question->answer = ""; } $question->grade = $grades[$randomquestion->id]; } else { $question->grade = $grades[$question->id]; } if (!$answers = quiz_get_answers($question)) { error("No answers defined for question id $question->id!"); } $grade = 0; // default $correct = array(); $feedback = array(); $response = array(); switch ($question->qtype) { case SHORTANSWER: if ($question->answer) { $question->answer = trim(stripslashes($question->answer[0])); } else { $question->answer = ""; } $response[0] = $question->answer; $bestshortanswer = 0; foreach($answers as $answer) { // There might be multiple right answers if ($answer->fraction > $bestshortanswer) { $correct[$answer->id] = $answer->answer; $bestshortanswer = $answer->fraction; } if (!$answer->usecase) { // Don't compare case $answer->answer = strtolower($answer->answer); $question->answer = strtolower($question->answer); } if ($question->answer == $answer->answer) { $feedback[0] = $answer->feedback; $grade = (float)$answer->fraction * $question->grade; } } break; case TRUEFALSE: if ($question->answer) { $question->answer = $question->answer[0]; } else { $question->answer = NULL; } foreach($answers as $answer) { // There should be two answers (true and false) $feedback[$answer->id] = $answer->feedback; if ($answer->fraction > 0) { $correct[$answer->id] = true; } if ($question->answer == $answer->id) { $grade = (float)$answer->fraction * $question->grade; $response[$answer->id] = true; } } break; case MULTICHOICE: foreach($answers as $answer) { // There will be multiple answers, perhaps more than one is right $feedback[$answer->id] = $answer->feedback; if ($answer->fraction > 0) { $correct[$answer->id] = true; } if (!empty($question->answer)) { foreach ($question->answer as $questionanswer) { if ($questionanswer == $answer->id) { $response[$answer->id] = true; if ($answer->single) { $grade = (float)$answer->fraction * $question->grade; continue; } else { $grade += (float)$answer->fraction * $question->grade; } } } } } break; case MATCH: $matchcount = $totalcount = 0; foreach ($question->answer as $questionanswer) { // Each answer is "subquestionid-answerid" $totalcount++; $qarr = explode('-', $questionanswer); // Extract subquestion/answer. $subquestionid = $qarr[0]; $subanswerid = $qarr[1]; if ($subquestionid and $subanswerid and (($subquestionid == $subanswerid) or ($answers[$subquestionid]->answertext == $answers[$subanswerid]->answertext))) { // Either the ids match exactly, or the answertexts match exactly // (in case two subquestions had the same answer) $matchcount++; $correct[$subquestionid] = true; } else { $correct[$subquestionid] = false; } $response[$subquestionid] = $subanswerid; } $grade = $question->grade * $matchcount / $totalcount; break; case RANDOMSAMATCH: $bestanswer = array(); foreach ($answers as $answer) { // Loop through them all looking for correct answers if (empty($bestanswer[$answer->question])) { $bestanswer[$answer->question] = 0; $correct[$answer->question] = ""; } if ($answer->fraction > $bestanswer[$answer->question]) { $bestanswer[$answer->question] = $answer->fraction; $correct[$answer->question] = $answer->answer; } } $answerfraction = 1.0 / (float) count($question->answer); foreach ($question->answer as $questionanswer) { // For each random answered question $rqarr = explode('-', $questionanswer); // Extract question/answer. $rquestion = $rqarr[0]; $ranswer = $rqarr[1]; $response[$rquestion] = $questionanswer; if (isset($answers[$ranswer])) { // If the answer exists in the list $answer = $answers[$ranswer]; $feedback[$rquestion] = $answer->feedback; if ($answer->question == $rquestion) { // Check that this answer matches the question $grade += (float)$answer->fraction * $question->grade * $answerfraction; } } } break; } if (!empty($randomquestion)) { // This question has been randomly chosen $question = $randomquestion; // Restore the question->id unset($randomquestion); } if ($grade < 0.0) { // No negative grades $grade = 0.0; } $result->grades[$question->id] = round($grade, 2); $result->sumgrades += $grade; $result->feedback[$question->id] = $feedback; $result->response[$question->id] = $response; $result->correct[$question->id] = $correct; } $fraction = (float)($result->sumgrades / $quiz->sumgrades); $result->percentage = format_float($fraction * 100.0); $result->grade = format_float($fraction * $quiz->grade); $result->sumgrades = round($result->sumgrades, 2); return $result; } function quiz_save_question_options($question) { /// Given some question info and some data about the the answers /// this function parses, organises and saves the question /// It is used by question.php when saving new data from a /// form, and also by import.php when importing questions /// /// If this is an update, and old answers already exist, then /// these are overwritten using an update(). To do this, it /// it is assumed that the IDs in quiz_answers are in the same /// sort order as the new answers being saved. This should always /// be true, but it's something to keep in mind if fiddling with /// question.php /// /// Returns $result->error or $result->notice switch ($question->qtype) { case SHORTANSWER: if (!$oldanswers = get_records("quiz_answers", "question", $question->id, "id ASC")) { $oldanswers = array(); } $answers = array(); $maxfraction = -1; // Insert all the new answers foreach ($question->answer as $key => $dataanswer) { if ($dataanswer != "") { if ($oldanswer = array_shift($oldanswers)) { // Existing answer, so reuse it $answer = $oldanswer; $answer->answer = $dataanswer; $answer->fraction = $question->fraction[$key]; $answer->feedback = $question->feedback[$key]; if (!update_record("quiz_answers", $answer)) { $result->error = "Could not update quiz answer! (id=$answer->id)"; return $result; } } else { // This is a completely new answer unset($answer); $answer->answer = $dataanswer; $answer->question = $question->id; $answer->fraction = $question->fraction[$key]; $answer->feedback = $question->feedback[$key]; if (!$answer->id = insert_record("quiz_answers", $answer)) { $result->error = "Could not insert quiz answer!"; return $result; } } $answers[] = $answer->id; if ($question->fraction[$key] > $maxfraction) { $maxfraction = $question->fraction[$key]; } } } if ($options = get_record("quiz_shortanswer", "question", $question->id)) { $options->answers = implode(",",$answers); $options->usecase = $question->usecase; if (!update_record("quiz_shortanswer", $options)) { $result->error = "Could not update quiz shortanswer options! (id=$options->id)"; return $result; } } else { unset($options); $options->question = $question->id; $options->answers = implode(",",$answers); $options->usecase = $question->usecase; if (!insert_record("quiz_shortanswer", $options)) { $result->error = "Could not insert quiz shortanswer options!"; return $result; } } /// Perform sanity checks on fractional grades if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); return $result; } break; case TRUEFALSE: if (!$oldanswers = get_records("quiz_answers", "question", $question->id, "id ASC")) { $oldanswers = array(); } if ($true = array_shift($oldanswers)) { // Existing answer, so reuse it $true->fraction = $question->answer; $true->feedback = $question->feedbacktrue; if (!update_record("quiz_answers", $true)) { $result->error = "Could not update quiz answer \"true\")!"; return $result; } } else { unset($true); $true->answer = get_string("true", "quiz"); $true->question = $question->id; $true->fraction = $question->answer; $true->feedback = $question->feedbacktrue; if (!$true->id = insert_record("quiz_answers", $true)) { $result->error = "Could not insert quiz answer \"true\")!"; return $result; } } if ($false = array_shift($oldanswers)) { // Existing answer, so reuse it $false->fraction = 1 - (int)$question->answer; $false->feedback = $question->feedbackfalse; if (!update_record("quiz_answers", $false)) { $result->error = "Could not insert quiz answer \"false\")!"; return $result; } } else { unset($false); $false->answer = get_string("false", "quiz"); $false->question = $question->id; $false->fraction = 1 - (int)$question->answer; $false->feedback = $question->feedbackfalse; if (!$false->id = insert_record("quiz_answers", $false)) { $result->error = "Could not insert quiz answer \"false\")!"; return $result; } } if ($options = get_record("quiz_truefalse", "question", $question->id)) { // No need to do anything, since the answer IDs won't have changed // But we'll do it anyway, just for robustness $options->trueanswer = $true->id; $options->falseanswer = $false->id; if (!update_record("quiz_truefalse", $options)) { $result->error = "Could not update quiz truefalse options! (id=$options->id)"; return $result; } } else { unset($options); $options->question = $question->id; $options->trueanswer = $true->id; $options->falseanswer = $false->id; if (!insert_record("quiz_truefalse", $options)) { $result->error = "Could not insert quiz truefalse options!"; return $result; } } break; case MULTICHOICE: if (!$oldanswers = get_records("quiz_answers", "question", $question->id, "id ASC")) { $oldanswers = array(); } $totalfraction = 0; $maxfraction = -1; $answers = array(); // Insert all the new answers foreach ($question->answer as $key => $dataanswer) { if ($dataanswer != "") { if ($answer = array_shift($oldanswers)) { // Existing answer, so reuse it $answer->answer = $dataanswer; $answer->fraction = $question->fraction[$key]; $answer->feedback = $question->feedback[$key]; if (!update_record("quiz_answers", $answer)) { $result->error = "Could not update quiz answer! (id=$answer->id)"; return $result; } } else { unset($answer); $answer->answer = $dataanswer; $answer->question = $question->id; $answer->fraction = $question->fraction[$key]; $answer->feedback = $question->feedback[$key]; if (!$answer->id = insert_record("quiz_answers", $answer)) { $result->error = "Could not insert quiz answer! "; return $result; } } $answers[] = $answer->id; if ($question->fraction[$key] > 0) { // Sanity checks $totalfraction += $question->fraction[$key]; } if ($question->fraction[$key] > $maxfraction) { $maxfraction = $question->fraction[$key]; } } } if ($options = get_record("quiz_multichoice", "question", $question->id)) { $options->answers = implode(",",$answers); $options->single = $question->single; if (!update_record("quiz_multichoice", $options)) { $result->error = "Could not update quiz multichoice options! (id=$options->id)"; return $result; } } else { unset($options); $options->question = $question->id; $options->answers = implode(",",$answers); $options->single = $question->single; if (!insert_record("quiz_multichoice", $options)) { $result->error = "Could not insert quiz multichoice options!"; return $result; } } /// Perform sanity checks on fractional grades if ($options->single) { if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $result->notice = get_string("fractionsnomax", "quiz", $maxfraction); return $result; } } else { $totalfraction = round($totalfraction,2); if ($totalfraction != 1) { $totalfraction = $totalfraction * 100; $result->notice = get_string("fractionsaddwrong", "quiz", $totalfraction); return $result; } } break; case MATCH: if (!$oldsubquestions = get_records("quiz_match_sub", "question", $question->id, "id ASC")) { $oldsubquestions = array(); } $subquestions = array(); // Insert all the new question+answer pairs foreach ($question->subquestions as $key => $questiontext) { $answertext = $question->subanswers[$key]; if (!empty($questiontext) and !empty($answertext)) { if ($subquestion = array_shift($oldsubquestions)) { // Existing answer, so reuse it $subquestion->questiontext = $questiontext; $subquestion->answertext = $answertext; if (!update_record("quiz_match_sub", $subquestion)) { $result->error = "Could not insert quiz match subquestion! (id=$subquestion->id)"; return $result; } } else { unset($subquestion); $subquestion->question = $question->id; $subquestion->questiontext = $questiontext; $subquestion->answertext = $answertext; if (!$subquestion->id = insert_record("quiz_match_sub", $subquestion)) { $result->error = "Could not insert quiz match subquestion!"; return $result; } } $subquestions[] = $subquestion->id; } } if (count($subquestions) < 3) { $result->notice = get_string("notenoughsubquestions", "quiz"); return $result; } if ($options = get_record("quiz_match", "question", $question->id)) { $options->subquestions = implode(",",$subquestions); if (!update_record("quiz_match", $options)) { $result->error = "Could not update quiz match options! (id=$options->id)"; return $result; } } else { unset($options); $options->question = $question->id; $options->subquestions = implode(",",$subquestions); if (!insert_record("quiz_match", $options)) { $result->error = "Could not insert quiz match options!"; return $result; } } break; case RANDOMSAMATCH: $options->question = $question->id; $options->choose = $question->choose; if ($existing = get_record("quiz_randomsamatch", "question", $options->question)) { $options->id = $existing->id; if (!update_record("quiz_randomsamatch", $options)) { $result->error = "Could not update quiz randomsamatch options!"; return $result; } } else { if (!insert_record("quiz_randomsamatch", $options)) { $result->error = "Could not insert quiz randomsamatch options!"; return $result; } } break; case RANDOM: break; default: $result->error = "Unsupported question type ($question->qtype)!"; return $result; break; } return true; } ?>