Skip to content
Fetching contributors…
Cannot retrieve contributors at this time
1843 lines (1561 sloc) 69.2 KB
<?PHP // $Id$
/// Library of function for module quiz
/// CONSTANTS ///////////////////////////////////////////////////////////////////
define("GRADEHIGHEST", "1");
define("GRADEAVERAGE", "2");
define("ATTEMPTFIRST", "3");
define("ATTEMPTLAST", "4");
$QUIZ_GRADE_METHOD = array ( GRADEHIGHEST => 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"),
"webct" => get_string("webct", "quiz"),
"qti" => get_string("qti", "quiz"),
"missingword" => get_string("missingword", "quiz") );
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, 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 "<SPAN CLASS=feedbacktext>".text_to_html($text, true, false)."</SPAN>";
}
function quiz_print_correctanswer($text) {
global $THEME;
echo "<P ALIGN=RIGHT><SPAN CLASS=highlight>$text</SPAN></P>";
}
function quiz_print_question_icon($question, $editlink=true) {
// Prints a question icon
global $QUIZ_QUESTION_TYPE;
if ($editlink) {
echo "<A HREF=\"question.php?id=$question->id\" TITLE=\"".$QUIZ_QUESTION_TYPE[$question->qtype]."\">";
}
switch ($question->qtype) {
case SHORTANSWER:
echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/sa.gif\">";
break;
case TRUEFALSE:
echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/tf.gif\">";
break;
case MULTICHOICE:
echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/mc.gif\">";
break;
case RANDOM:
echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/rs.gif\">";
break;
case MATCH:
echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/ma.gif\">";
break;
case RANDOMSAMATCH:
echo "<IMG BORDER=0 HEIGHT=16 WIDTH=16 SRC=\"pix/rm.gif\">";
break;
}
if ($editlink) {
echo "</A>\n";
}
}
function quiz_print_question($number, $question, $grade, $courseid,
$feedback=NULL, $response=NULL, $actualgrade=NULL, $correct=NULL,
$realquestion=NULL, $shuffleanswers=false) {
/// Prints a quiz question, any format
/// $question is provided as an object
if (empty($actualgrade)) {
$actualgrade = 0;
}
$stranswer = get_string("answer", "quiz");
$strmarks = get_string("marks", "quiz");
echo "<TABLE WIDTH=100% CELLSPACING=10><TR><TD NOWRAP WIDTH=100 VALIGN=top>";
echo "<P ALIGN=CENTER><B>$number</B></P>";
if ($feedback or $response) {
echo "<P ALIGN=CENTER><FONT SIZE=1>$strmarks: $actualgrade/$grade</FONT></P>";
} else {
echo "<P ALIGN=CENTER><FONT SIZE=1>$grade $strmarks</FONT></P>";
}
print_spacer(1,100);
echo "</TD><TD VALIGN=TOP>";
if (empty($realquestion)) {
$realquestion->id = $question->id;
} else { // Add a marker to connect this question to the actual random parent
echo "<input type=\"hidden\" name=\"q{$realquestion->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 "<P ALIGN=RIGHT>$stranswer: <INPUT TYPE=TEXT NAME=q$realquestion->id SIZE=20 $value></P>";
if ($feedback) {
quiz_print_comment("<P ALIGN=right>$feedback[0]</P>");
}
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 "<TABLE ALIGN=right cellpadding=5><TR><TD align=right>$stranswer:&nbsp;&nbsp;";
echo "<TD $truecorrect>";
echo "<INPUT $truechecked TYPE=RADIO NAME=\"q$realquestion->id\" VALUE=\"$true->id\">$true->answer";
echo "</TD><TD $falsecorrect>";
echo "<INPUT $falsechecked TYPE=RADIO NAME=\"q$realquestion->id\" VALUE=\"$false->id\">$false->answer";
echo "</TD></TR></TABLE><BR CLEAR=ALL>";
if ($feedback) {
quiz_print_comment("<P ALIGN=right>$feedback[$feedbackid]</P>");
}
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 "<TABLE ALIGN=right>";
echo "<TR><TD valign=top>$stranswer:&nbsp;&nbsp;</TD><TD>";
echo "<TABLE>";
$answerids = explode(",", $options->answers);
if ($shuffleanswers) {
$answerids = swapshuffle($answerids);
}
foreach ($answerids as $key => $answerid) {
$answer = $answers[$answerid];
$qnumchar = chr(ord('a') + $key);
if (empty($feedback) or empty($response[$answerid])) {
$checked = "";
} else {
$checked = "CHECKED";
}
echo "<TR><TD valign=top>";
if ($options->single) {
echo "<INPUT $checked TYPE=RADIO NAME=q$realquestion->id VALUE=\"$answer->id\">";
} else {
echo "<INPUT $checked TYPE=CHECKBOX NAME=q$realquestion->id"."a$answer->id VALUE=\"$answer->id\">";
}
echo "</TD>";
if (empty($feedback) or empty($correct[$answer->id])) {
echo "<TD valign=top>$qnumchar. $answer->answer</TD>";
} else {
echo "<TD valign=top CLASS=highlight>$qnumchar. $answer->answer</TD>";
}
if (!empty($feedback)) {
echo "<TD valign=top>&nbsp;";
if (!empty($response[$answerid])) {
quiz_print_comment($feedback[$answerid]);
}
echo "</TD>";
}
echo "</TR>";
}
echo "</TABLE>";
echo "</TABLE>";
break;
case MATCH:
if (!$options = get_record("quiz_match", "question", $question->id)) {
notify("Error: Missing question options!");
}
if (!$subquestions = get_records_list("quiz_match_sub", "id", $options->subquestions)) {
notify("Error: Missing subquestions for this question!");
}
if (!empty($question->questiontext)) {
echo text_to_html($question->questiontext);
}
if (!empty($question->image)) {
print_file_picture($question->image, $courseid, QUIZ_PICTURE_DEFAULT_HEIGHT);
}
if ($shuffleanswers) {
$subquestions = draw_rand_array($subquestions, count($subquestions));
}
foreach ($subquestions as $subquestion) {
$answers[$subquestion->id] = $subquestion->answertext;
}
$answers = draw_rand_array($answers, count($answers));
echo "<table border=0 cellpadding=10 align=right>";
foreach ($subquestions as $key => $subquestion) {
echo "<tr><td align=left valign=top>";
echo $subquestion->questiontext;
echo "</td>";
if (empty($response)) {
echo "<td align=right valign=top>";
choose_from_menu($answers, "q$realquestion->id"."r$subquestion->id");
} else {
if (empty($response[$key])) {
echo "<td align=right valign=top>";
choose_from_menu($answers, "q$realquestion->id"."r$subquestion->id");
} else {
if ($response[$key] == $correct[$key]) {
echo "<td align=right valign=top class=highlight>";
choose_from_menu($answers, "q$realquestion->id"."r$subquestion->id", $response[$key]);
} else {
echo "<td align=right valign=top>";
choose_from_menu($answers, "q$realquestion->id"."r$subquestion->id", $response[$key]);
}
}
if (!empty($feedback[$key])) {
quiz_print_comment($feedback[$key]);
}
}
echo "</td></tr>";
}
echo "</table>";
break;
case RANDOMSAMATCH:
if (!$options = get_record("quiz_randomsamatch", "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);
}
/// First, get all the questions available
$allquestions = get_records_select("quiz_questions",
"category = $question->category AND qtype = ".SHORTANSWER);
if (count($allquestions) < $options->choose) {
notify("Error: could not find enough Short Answer questions in the database!");
notify("Found ".count($allquestions).", need $options->choose.");
break;
}
if (empty($response)) { // Randomly pick the questions
if (!$randomquestions = draw_rand_array($allquestions, $options->choose)) {
notify("Error choosing $options->choose random questions");
break;
}
} else { // Use existing questions
$randomquestions = array();
foreach ($response as $key => $rrr) {
$rrr = explode("-", $rrr);
$randomquestions[$key] = $allquestions[$key];
$responseanswer[$key] = $rrr[1];
}
}
/// For each selected, find the best matching answers
foreach ($randomquestions as $randomquestion) {
$shortanswerquestion = get_record("quiz_shortanswer", "question", $randomquestion->id);
$questionanswers = get_records_list("quiz_answers", "id", $shortanswerquestion->answers);
$bestfraction = 0;
$bestanswer = NULL;
foreach ($questionanswers as $questionanswer) {
if ($questionanswer->fraction > $bestfraction) {
$bestanswer = $questionanswer;
}
}
if (empty($bestanswer)) {
notify("Error: Could not find the best answer for question: ".$randomquestions->name);
break;
}
$randomanswers[$bestanswer->id] = trim($bestanswer->answer);
}
if (!$randomanswers = draw_rand_array($randomanswers, $options->choose)) { // Mix them up
notify("Error randomising answers!");
break;
}
echo "<table border=0 cellpadding=10>";
foreach ($randomquestions as $key => $randomquestion) {
echo "<tr><td align=left valign=top>";
echo $randomquestion->questiontext;
echo "</td>";
echo "<td align=right valign=top>";
if (empty($response)) {
choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id");
} else {
if (!empty($correct[$key])) {
if ($randomanswers[$responseanswer[$key]] == $correct[$key]) {
echo "<span=highlight>";
choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id", $responseanswer[$key]);
echo "</span><br \>";
} else {
choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id", $responseanswer[$key]);
quiz_print_correctanswer($correct[$key]);
}
} else {
choose_from_menu($randomanswers, "q$realquestion->id"."r$randomquestion->id", $responseanswer[$key]);
}
if (!empty($feedback[$key])) {
quiz_print_comment($feedback[$key]);
}
}
echo "</td></tr>";
}
echo "</table>";
break;
case RANDOM:
echo "<P>Random questions should not be printed this way!</P>";
break;
default:
notify("Error: Unknown question type!");
}
echo "</TD></TR></TABLE>";
}
function quiz_print_quiz_questions($quiz, $results=NULL, $questions=NULL, $shuffleorder=NULL) {
// Prints a whole quiz on one page.
/// Get the questions
if (!$questions) {
if (empty($quiz->questions)) {
notify("No questions have been defined!");
return false;
}
if (!$questions = get_records_list("quiz_questions", "id", $quiz->questions, "")) {
notify("Error when reading questions from the database!");
return false;
}
if (!empty($quiz->shufflequestions)) { // Mix everything up
$questions = swapshuffle_assoc($questions);
}
}
if ($shuffleorder) { // Order has been defined, so reorder questions
$oldquestions = $questions;
$questions = array();
foreach ($shuffleorder as $key) {
$questions[] = $oldquestions[$key]; // This loses the index key, but doesn't matter
}
}
if (!$grades = get_records_list("quiz_question_grades", "question", $quiz->questions, "", "question,grade")) {
notify("No grades were found for these questions!");
return false;
}
/// Examine the set of questions for random questions, and retrieve them
if (empty($results)) { // Choose some new random questions
if ($randomcats = quiz_get_random_categories($quiz->questions)) {
foreach ($randomcats as $randomcat => $randomdraw) {
/// Get the appropriate amount of random questions from this category
if (!$catquestions[$randomcat] = quiz_choose_random_questions($randomcat, $randomdraw)) {
notify(get_string("toomanyrandom", "quiz", $randomcat));
return false;
}
}
}
} else { // Get the previously chosen questions
$chosen = array();
foreach ($questions as $question) {
if (isset($question->random)) {
$chosen[] = $question->random;
}
}
if ($chosen) {
$chosenlist = implode(",", $chosen);
if (!$chosen = get_records_list("quiz_questions", "id", $chosenlist, "")) {
notify("Error when reading questions from the database!");
return false;
}
}
}
$strconfirmattempt = addslashes(get_string("readytosend", "quiz"));
echo "<FORM METHOD=POST ACTION=attempt.php onsubmit=\"return confirm('$strconfirmattempt');\">";
echo "<INPUT TYPE=hidden NAME=q VALUE=\"$quiz->id\">";
$count = 0;
$questionorder = array();
foreach ($questions as $question) {
$count++;
$questionorder[] = $question->id;
$feedback = NULL;
$response = NULL;
$actualgrades = NULL;
$correct = NULL;
$randomquestion = NULL;
if (empty($results)) {
if ($question->qtype == RANDOM ) { // Set up random questions
$randomquestion = $question;
$question = array_pop($catquestions[$randomquestion->category]);
$grades[$question->id]->grade = $grades[$randomquestion->id]->grade;
}
} else {
if (!empty($results->feedback[$question->id])) {
$feedback = $results->feedback[$question->id];
}
if (!empty($results->response[$question->id])) {
$response = $results->response[$question->id];
}
if (!empty($results->grades[$question->id])) {
$actualgrades = $results->grades[$question->id];
}
if ($quiz->correctanswers) {
if (!empty($results->correct[$question->id])) {
$correct = $results->correct[$question->id];
}
}
if (!empty($question->random)) {
$randomquestion = $question;
$question = $chosen[$question->random];
$grades[$question->id]->grade = $grades[$randomquestion->id]->grade;
}
}
print_simple_box_start("CENTER", "90%");
quiz_print_question($count, $question, $grades[$question->id]->grade, $quiz->course,
$feedback, $response, $actualgrades, $correct,
$randomquestion, $quiz->shuffleanswers);
print_simple_box_end();
echo "<br \>";
}
if (empty($results)) {
if (!empty($quiz->shufflequestions)) { // Things have been mixed up, so pass the question order
$shuffleorder = implode(',', $questionorder);
echo "<input type=hidden name=shuffleorder value=\"$shuffleorder\">\n";
}
echo "<center><input type=submit value=\"".get_string("savemyanswers", "quiz")."\"></center>";
}
echo "</form>";
return true;
}
function quiz_get_default_category($courseid) {
/// Returns the current category
if ($categories = get_records("quiz_categories", "course", $courseid, "id")) {
foreach ($categories as $category) {
return $category; // Return the first one (lowest id)
}
}
// Otherwise, we need to make one
$category->name = get_string("default", "quiz");
$category->info = get_string("defaultinfo", "quiz");
$category->course = $courseid;
$category->publish = 0;
if (!$category->id = insert_record("quiz_categories", $category)) {
notify("Error creating a default category!");
return false;
}
return $category;
}
function quiz_get_category_menu($courseid, $published=false) {
/// Returns the list of categories
$publish = "";
if ($published) {
$publish = "OR publish = '1'";
}
return get_records_select_menu("quiz_categories", "course='$courseid' $publish", "name ASC", "id,name");
}
function quiz_print_category_form($course, $current) {
// Prints a form to choose categories
if (!$categories = get_records_select("quiz_categories", "course='$course->id' OR publish = '1'", "name ASC")) {
if (!$category = quiz_get_default_category($course->id)) {
notify("Error creating a default category!");
return false;
}
$categories[$category->id] = $category;
}
foreach ($categories as $key => $category) {
if ($category->publish) {
if ($catcourse = get_record("course", "id", $category->course)) {
$category->name .= " ($catcourse->shortname)";
}
}
$catmenu[$category->id] = $category->name;
}
$strcategory = get_string("category", "quiz");
$strshow = get_string("show", "quiz");
$streditcats = get_string("editcategories", "quiz");
echo "<TABLE width=\"100%\"><TR><TD NOWRAP>";
echo "<FORM METHOD=POST ACTION=edit.php>";
echo "<B>$strcategory:</B>&nbsp;";
choose_from_menu($catmenu, "cat", "$current");
echo "<INPUT TYPE=submit VALUE=\"$strshow\">";
echo "</FORM>";
echo "</TD><TD align=right>";
echo "<FORM METHOD=GET ACTION=category.php>";
echo "<INPUT TYPE=hidden NAME=id VALUE=\"$course->id\">";
echo "<INPUT TYPE=submit VALUE=\"$streditcats\">";
echo "</FORM>";
echo "</TD></TR></TABLE>";
}
function quiz_choose_random_questions($category, $draws) {
/// Given a question category and a number of draws, this function
/// creates a random subset of that size - returned as an array of questions
if (!$pool = get_records_select_menu("quiz_questions",
"category = '$category' AND qtype <> ".RANDOM, "", "id,qtype")) {
return false;
}
$countpool = count($pool);
if ($countpool == $draws) {
$chosen = $pool;
} else if ($countpool < $draws) {
return false;
} else {
$chosen = draw_rand_array($pool, $draws);
}
$chosenlist = implode(",", array_keys($chosen));
return get_records_list("quiz_questions", "id", $chosenlist);
}
function quiz_get_all_question_grades($questionlist, $quizid) {
// Given a list of question IDs, finds grades or invents them to
// create an array of matching grades
if (empty($questionlist)) {
return array();
}
$questions = quiz_get_question_grades($quizid, $questionlist);
$list = explode(",", $questionlist);
$grades = array();
foreach ($list as $qid) {
if (isset($questions[$qid])) {
$grades[$qid] = $questions[$qid]->grade;
} else {
$grades[$qid] = 1;
}
}
return $grades;
}
function quiz_print_question_list($questionlist, $grades) {
// Prints a list of quiz questions in a small layout form with knobs
// $questionlist is comma-separated list
// $grades is an array of corresponding grades
global $THEME;
if (!$questionlist) {
echo "<P align=center>";
print_string("noquestions", "quiz");
echo "</P>";
return;
}
$order = explode(",", $questionlist);
if (!$questions = get_records_list("quiz_questions", "id", $questionlist)) {
echo "<P align=center>";
print_string("noquestions", "quiz");
echo "</P>";
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 "<FORM METHOD=post ACTION=edit.php>";
echo "<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=2 WIDTH=\"100%\">";
echo "<TR><TH WIDTH=\"*\" COLSPAN=3 NOWRAP>$strorder</TH><TH align=left WIDTH=\"100%\" NOWRAP>$strquestionname</TH><TH width=\"*\" NOWRAP>$strtype</TH><TH WIDTH=\"*\" NOWRAP>$strgrade</TH><TH WIDTH=\"*\" NOWRAP>$stredit</TH></TR>";
foreach ($order as $qnum) {
if (empty($questions[$qnum])) {
continue;
}
$count++;
echo "<TR BGCOLOR=\"$THEME->cellcontent\">";
echo "<TD>$count</TD>";
echo "<TD>";
if ($count != 1) {
echo "<A TITLE=\"$strmoveup\" HREF=\"edit.php?up=$qnum\"><IMG
SRC=\"../../pix/t/up.gif\" BORDER=0></A>";
}
echo "</TD>";
echo "<TD>";
if ($count != $total) {
echo "<A TITLE=\"$strmovedown\" HREF=\"edit.php?down=$qnum\"><IMG
SRC=\"../../pix/t/down.gif\" BORDER=0></A>";
}
echo "</TD>";
echo "<TD>".$questions[$qnum]->name."</TD>";
echo "<TD ALIGN=CENTER>";
quiz_print_question_icon($questions[$qnum]);
echo "</TD>";
echo "<TD>";
choose_from_menu($gradesmenu, "q$qnum", (string)$grades[$qnum], "");
echo "<TD>";
echo "<A TITLE=\"$strdelete\" HREF=\"edit.php?delete=$qnum\"><IMG
SRC=\"../../pix/t/delete.gif\" BORDER=0></A>&nbsp;";
echo "<A TITLE=\"$stredit\" HREF=\"question.php?id=$qnum\"><IMG
SRC=\"../../pix/t/edit.gif\" BORDER=0></A>";
echo "</TD>";
$sumgrade += $grades[$qnum];
}
echo "<TR><TD COLSPAN=5 ALIGN=right>";
echo "<INPUT TYPE=submit VALUE=\"$strsavegrades:\">";
echo "<INPUT TYPE=hidden NAME=setgrades VALUE=\"save\">";
echo "<TD ALIGN=LEFT BGCOLOR=\"$THEME->cellcontent\">";
echo "<B>$sumgrade</B>";
echo "</TD><TD></TD></TR>";
echo "</TABLE>";
echo "</FORM>";
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 "<P align=center>";
print_string("selectcategoryabove", "quiz");
echo "</P>";
return;
}
if (!$category = get_record("quiz_categories", "id", "$categoryid")) {
notify("Category not found!");
return;
}
echo "<CENTER>";
echo text_to_html($category->info);
echo "<TABLE><TR>";
echo "<TD valign=top><B>$straddquestions:</B></TD>";
echo "<TD valign=top align=right>";
echo "<FORM METHOD=GET ACTION=question.php>";
choose_from_menu($QUIZ_QUESTION_TYPE, "qtype", "", "");
echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">";
echo "<INPUT TYPE=submit VALUE=\"$strcreatenewquestion\">";
helpbutton("questiontypes", $strcreatenewquestion, "quiz");
echo "</FORM>";
echo "<FORM METHOD=GET ACTION=import.php>";
echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">";
echo "<INPUT TYPE=submit VALUE=\"$strimportquestions\">";
helpbutton("import", $strimportquestions, "quiz");
echo "</FORM>";
echo "<FORM METHOD=GET ACTION=multiple.php>";
echo "<INPUT TYPE=hidden NAME=category VALUE=\"$category->id\">";
echo "<INPUT TYPE=submit VALUE=\"$strcreatemultiple\">";
helpbutton("createmultiple", $strcreatemultiple, "quiz");
echo "</FORM>";
echo "</TR></TABLE>";
echo "</CENTER>";
if (!$questions = get_records("quiz_questions", "category", $category->id, "qtype ASC")) {
echo "<P align=center>";
print_string("noquestions", "quiz");
echo "</P>";
return;
}
$canedit = isteacher($category->course);
echo "<FORM METHOD=post ACTION=edit.php>";
echo "<TABLE BORDER=0 CELLPADDING=5 CELLSPACING=2 WIDTH=\"100%\">";
echo "<TR><TH width=\"*\" NOWRAP>$strselect</TH><TH width=\"100%\" align=left NOWRAP>$strquestionname</TH><TH WIDTH=\"*\" NOWRAP>$strtype</TH>";
if ($canedit) {
echo "<TH width=\"*\" NOWRAP>$stredit</TH>";
}
echo "</TR>";
foreach ($questions as $question) {
echo "<TR BGCOLOR=\"$THEME->cellcontent\">";
echo "<TD ALIGN=CENTER>";
echo "<INPUT TYPE=CHECKBOX NAME=q$question->id VALUE=\"1\">";
echo "</TD>";
echo "<TD>".$question->name."</TD>";
echo "<TD ALIGN=CENTER>";
quiz_print_question_icon($question);
echo "</TD>";
if ($canedit) {
echo "<TD>";
echo "<A TITLE=\"$strdelete\" HREF=\"question.php?id=$question->id&delete=$question->id\"><IMG
SRC=\"../../pix/t/delete.gif\" BORDER=0></A>&nbsp;";
echo "<A TITLE=\"$stredit\" HREF=\"question.php?id=$question->id\"><IMG
SRC=\"../../pix/t/edit.gif\" BORDER=0></A>";
echo "</TD></TR>";
}
echo "</TR>";
}
echo "<TR><TD COLSPAN=3>";
echo "<INPUT TYPE=submit NAME=add VALUE=\"<< $straddselectedtoquiz\">";
//echo "<INPUT TYPE=submit NAME=delete VALUE=\"XX Delete selected\">";
echo "<INPUT type=button onclick=\"checkall()\" value=\"$strselectall\">";
echo "</TD></TR>";
echo "</TABLE>";
echo "</FORM>";
}
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[] = "<SPAN CLASS=highlight><A HREF=\"report.php?q=$quiz->id&attempt=$attempt->id\">$attemptgrade</A></SPAN>";
} else {
$userattempts[] = "<A HREF=\"report.php?q=$quiz->id&attempt=$attempt->id\">$attemptgrade</A>";
}
}
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;
}
?>
Jump to Line
Something went wrong with that request. Please try again.