function qformat_gift::readquestion in Quiz 6.6
Same name and namespace in other branches
- 6.5 includes/moodle/question/format/gift/format.php \qformat_gift::readquestion()
Given the data known to define a question in this format, this function converts it into a question object suitable for processing and insertion into Moodle.
If your format does not use blank lines to delimit questions (e.g. an XML format) you must override 'readquestions' too
Parameters
$lines mixed data that represents question:
Return value
object question object
Overrides qformat_default::readquestion
File
- includes/
moodle/ question/ format/ gift/ format.php, line 115
Class
- qformat_gift
- @package questionbank @subpackage importexport
Code
function readquestion($lines) {
// Given an array of lines known to define a question in this format, this function
// converts it into a question object suitable for processing and insertion into Moodle.
$question = $this
->defaultquestion();
$comment = NULL;
// define replaced by simple assignment, stop redefine notices
$gift_answerweight_regex = "^%\\-*([0-9]{1,2})\\.?([0-9]*)%";
// REMOVED COMMENTED LINES and IMPLODE
foreach ($lines as $key => $line) {
$line = trim($line);
if (substr($line, 0, 2) == "//") {
$lines[$key] = " ";
}
}
$text = trim(implode(" ", $lines));
if ($text == "") {
return false;
}
// Substitute escaped control characters with placeholders
$text = $this
->escapedchar_pre($text);
// Look for category modifier
if (ereg('^\\$CATEGORY:', $text)) {
// $newcategory = $matches[1];
$newcategory = trim(substr($text, 10));
// build fake question to contain category
$question->qtype = 'category';
$question->category = $newcategory;
return $question;
}
// QUESTION NAME parser
if (substr($text, 0, 2) == "::") {
$text = substr($text, 2);
$namefinish = strpos($text, "::");
if ($namefinish === false) {
$question->name = false;
// name will be assigned after processing question text below
}
else {
$questionname = substr($text, 0, $namefinish);
$question->name = addslashes(trim($this
->escapedchar_post($questionname)));
$text = trim(substr($text, $namefinish + 2));
// Remove name from text
}
}
else {
$question->name = false;
}
// FIND ANSWER section
// no answer means its a description
$answerstart = strpos($text, "{");
$answerfinish = strpos($text, "}");
$description = false;
if ($answerstart === false and $answerfinish === false) {
$description = true;
$answertext = '';
$answerlength = 0;
}
elseif (!($answerstart !== false and $answerfinish !== false)) {
$this
->error(get_string('braceerror', 'quiz'), $text);
return false;
}
else {
$answerlength = $answerfinish - $answerstart;
$answertext = trim(substr($text, $answerstart + 1, $answerlength - 1));
}
// Format QUESTION TEXT without answer, inserting "_____" as necessary
if ($description) {
$questiontext = $text;
}
elseif (substr($text, -1) == "}") {
// no blank line if answers follow question, outside of closing punctuation
$questiontext = substr_replace($text, "", $answerstart, $answerlength + 1);
}
else {
// inserts blank line for missing word format
$questiontext = substr_replace($text, "_____", $answerstart, $answerlength + 1);
}
// get questiontext format from questiontext
$oldquestiontext = $questiontext;
$questiontextformat = 0;
if (substr($questiontext, 0, 1) == '[') {
$questiontext = substr($questiontext, 1);
$rh_brace = strpos($questiontext, ']');
$qtformat = substr($questiontext, 0, $rh_brace);
$questiontext = substr($questiontext, $rh_brace + 1);
if (!($questiontextformat = text_format_name($qtformat))) {
$questiontext = $oldquestiontext;
}
}
$question->questiontextformat = $questiontextformat;
$question->questiontext = addslashes(trim($this
->escapedchar_post($questiontext)));
// set question name if not already set
if ($question->name === false) {
$question->name = $question->questiontext;
}
// ensure name is not longer than 250 characters
//$question->name = shorten_text( $question->name, 200 );
$question->name = substr($question->name, 0, 200);
$question->name = strip_tags(substr($question->name, 0, 250));
// determine QUESTION TYPE
$question->qtype = NULL;
// give plugins first try
// plugins must promise not to intercept standard qtypes
// MDL-12346, this could be called from lesson mod which has its own base class =(
if (method_exists($this, 'try_importing_using_qtypes') && ($try_question = $this
->try_importing_using_qtypes($lines, $question, $answertext))) {
return $try_question;
}
if ($description) {
$question->qtype = DESCRIPTION;
}
elseif ($answertext == '') {
$question->qtype = ESSAY;
}
elseif ($answertext[0] == "#") {
$question->qtype = NUMERICAL;
}
elseif (strpos($answertext, "~") !== false) {
// only Multiplechoice questions contain tilde ~
$question->qtype = MULTICHOICE;
}
elseif (strpos($answertext, "=") !== false && strpos($answertext, "->") !== false) {
// only Matching contains both = and ->
$question->qtype = MATCH;
}
else {
// either TRUEFALSE or SHORTANSWER
// TRUEFALSE question check
$truefalse_check = $answertext;
if (strpos($answertext, "#") > 0) {
// strip comments to check for TrueFalse question
$truefalse_check = trim(substr($answertext, 0, strpos($answertext, "#")));
}
$valid_tf_answers = array(
"T",
"TRUE",
"F",
"FALSE",
);
if (in_array($truefalse_check, $valid_tf_answers)) {
$question->qtype = TRUEFALSE;
}
else {
// Must be SHORTANSWER
$question->qtype = SHORTANSWER;
}
}
if (!isset($question->qtype)) {
$giftqtypenotset = get_string('giftqtypenotset', 'quiz');
$this
->error($giftqtypenotset, $text);
return false;
}
switch ($question->qtype) {
case DESCRIPTION:
$question->defaultgrade = 0;
$question->length = 0;
return $question;
break;
case ESSAY:
$question->feedback = '';
$question->fraction = 0;
return $question;
break;
case MULTICHOICE:
if (strpos($answertext, "=") === false) {
$question->single = 0;
// multiple answers are enabled if no single answer is 100% correct
}
else {
$question->single = 1;
// only one answer allowed (the default)
}
$answertext = str_replace("=", "~=", $answertext);
$answers = explode("~", $answertext);
if (isset($answers[0])) {
$answers[0] = trim($answers[0]);
}
if (empty($answers[0])) {
array_shift($answers);
}
$countanswers = count($answers);
if (!$this
->check_answer_count(2, $answers, $text)) {
return false;
break;
}
foreach ($answers as $key => $answer) {
$answer = trim($answer);
// determine answer weight
if ($answer[0] == "=") {
$answer_weight = 1;
$answer = substr($answer, 1);
}
elseif (ereg($gift_answerweight_regex, $answer)) {
// check for properly formatted answer weight
$answer_weight = $this
->answerweightparser($answer);
}
else {
//default, i.e., wrong anwer
$answer_weight = 0;
}
$question->fraction[$key] = $answer_weight;
$question->feedback[$key] = $this
->commentparser($answer);
// commentparser also removes comment from $answer
$question->answer[$key] = addslashes($this
->escapedchar_post($answer));
$question->correctfeedback = '';
$question->partiallycorrectfeedback = '';
$question->incorrectfeedback = '';
}
// end foreach answer
//$question->defaultgrade = 1;
//$question->image = ""; // No images with this format
return $question;
break;
case MATCH:
$answers = explode("=", $answertext);
if (isset($answers[0])) {
$answers[0] = trim($answers[0]);
}
if (empty($answers[0])) {
array_shift($answers);
}
if (!$this
->check_answer_count(2, $answers, $text)) {
return false;
break;
}
foreach ($answers as $key => $answer) {
$answer = trim($answer);
if (strpos($answer, "->") === false) {
$giftmatchingformat = get_string('giftmatchingformat', 'quiz');
$this
->error($giftmatchingformat, $answer);
return false;
break 2;
}
$marker = strpos($answer, "->");
$question->subquestions[$key] = addslashes(trim($this
->escapedchar_post(substr($answer, 0, $marker))));
$question->subanswers[$key] = addslashes(trim($this
->escapedchar_post(substr($answer, $marker + 2))));
}
// end foreach answer
return $question;
break;
case TRUEFALSE:
$answer = $answertext;
$comment = $this
->commentparser($answer);
// commentparser also removes comment from $answer
$feedback = $this
->split_truefalse_comment($comment);
if ($answer == "T" or $answer == "TRUE") {
$question->answer = 1;
$question->feedbacktrue = $feedback['right'];
$question->feedbackfalse = $feedback['wrong'];
}
else {
$question->answer = 0;
$question->feedbackfalse = $feedback['right'];
$question->feedbacktrue = $feedback['wrong'];
}
$question->penalty = 1;
$question->correctanswer = $question->answer;
return $question;
break;
case SHORTANSWER:
// SHORTANSWER Question
$answers = explode("=", $answertext);
if (isset($answers[0])) {
$answers[0] = trim($answers[0]);
}
if (empty($answers[0])) {
array_shift($answers);
}
if (!$this
->check_answer_count(1, $answers, $text)) {
return false;
break;
}
foreach ($answers as $key => $answer) {
$answer = trim($answer);
// Answer Weight
if (ereg($gift_answerweight_regex, $answer)) {
// check for properly formatted answer weight
$answer_weight = $this
->answerweightparser($answer);
}
else {
//default, i.e., full-credit anwer
$answer_weight = 1;
}
$question->fraction[$key] = $answer_weight;
$question->feedback[$key] = $this
->commentparser($answer);
//commentparser also removes comment from $answer
$question->answer[$key] = addslashes($this
->escapedchar_post($answer));
}
// end foreach
//$question->usecase = 0; // Ignore case
//$question->defaultgrade = 1;
//$question->image = ""; // No images with this format
return $question;
break;
case NUMERICAL:
// Note similarities to ShortAnswer
$answertext = substr($answertext, 1);
// remove leading "#"
// If there is feedback for a wrong answer, store it for now.
if (($pos = strpos($answertext, '~')) !== false) {
$wrongfeedback = substr($answertext, $pos);
$answertext = substr($answertext, 0, $pos);
}
else {
$wrongfeedback = '';
}
$answers = explode("=", $answertext);
if (isset($answers[0])) {
$answers[0] = trim($answers[0]);
}
if (empty($answers[0])) {
array_shift($answers);
}
if (count($answers) == 0) {
// invalid question
$giftnonumericalanswers = get_string('giftnonumericalanswers', 'quiz');
$this
->error($giftnonumericalanswers, $text);
return false;
break;
}
foreach ($answers as $key => $answer) {
$answer = trim($answer);
// Answer weight
if (ereg($gift_answerweight_regex, $answer)) {
// check for properly formatted answer weight
$answer_weight = $this
->answerweightparser($answer);
}
else {
//default, i.e., full-credit anwer
$answer_weight = 1;
}
$question->fraction[$key] = $answer_weight;
$question->feedback[$key] = $this
->commentparser($answer);
//commentparser also removes comment from $answer
//Calculate Answer and Min/Max values
if (strpos($answer, "..") > 0) {
// optional [min]..[max] format
$marker = strpos($answer, "..");
$max = trim(substr($answer, $marker + 2));
$min = trim(substr($answer, 0, $marker));
$ans = ($max + $min) / 2;
$tol = $max - $ans;
}
elseif (strpos($answer, ":") > 0) {
// standard [answer]:[errormargin] format
$marker = strpos($answer, ":");
$tol = trim(substr($answer, $marker + 1));
$ans = trim(substr($answer, 0, $marker));
}
else {
// only one valid answer (zero errormargin)
$tol = 0;
$ans = trim($answer);
}
if (!(is_numeric($ans) || ($ans = '*')) || !is_numeric($tol)) {
$errornotnumbers = get_string('errornotnumbers');
$this
->error($errornotnumbers, $text);
return false;
break;
}
// store results
$question->answer[$key] = $ans;
$question->tolerance[$key] = $tol;
}
// end foreach
if ($wrongfeedback) {
$key += 1;
$question->fraction[$key] = 0;
$question->feedback[$key] = $this
->commentparser($wrongfeedback);
$question->answer[$key] = '';
$question->tolerance[$key] = '';
}
return $question;
break;
default:
$giftnovalidquestion = get_string('giftnovalidquestion', 'quiz');
$this
->error($giftnovalidquestion, $text);
return false;
break;
}
// end switch ($question->qtype)
}