public function test_functions_with_wrong_num_args_caught() { $this->assert_nonempty_string(qtype_calculated_find_formula_errors('abs(-1, 1)')); $this->assert_nonempty_string(qtype_calculated_find_formula_errors('abs()')); $this->assert_nonempty_string(qtype_calculated_find_formula_errors('pi(1)')); $this->assert_nonempty_string(qtype_calculated_find_formula_errors('log()')); $this->assert_nonempty_string(qtype_calculated_find_formula_errors('log(64, 2, 3)')); $this->assert_nonempty_string(qtype_calculated_find_formula_errors('atan2(1.0)')); $this->assert_nonempty_string(qtype_calculated_find_formula_errors('atan2(1.0, 1.0, 2.0)')); $this->assert_nonempty_string(qtype_calculated_find_formula_errors('max(1.0)')); }
function validation($data, $files) { // echo code left for testing period // echo "<p>question <pre>";print_r($this->question);echo "</pre></p>"; // echo "<p>data <pre>";print_r($data);echo "</pre></p>"; $errors = parent::validation($data, $files); //verifying for errors in {=...} in question text; $qtext = ""; $qtextremaining = $data['questiontext']['text']; $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']); foreach ($possibledatasets as $name => $value) { $qtextremaining = str_replace('{' . $name . '}', '1', $qtextremaining); } // echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets); while (preg_match('~\\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) { $qtextsplits = explode($regs1[0], $qtextremaining, 2); $qtext = $qtext . $qtextsplits[0]; $qtextremaining = $qtextsplits[1]; if (!empty($regs1[1]) && ($formulaerrors = qtype_calculated_find_formula_errors($regs1[1]))) { if (!isset($errors['questiontext'])) { $errors['questiontext'] = $formulaerrors . ':' . $regs1[1]; } else { $errors['questiontext'] .= '<br/>' . $formulaerrors . ':' . $regs1[1]; } } } $answers = $data['answer']; $answercount = 0; $maxgrade = false; $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']); $mandatorydatasets = array(); foreach ($answers as $key => $answer) { $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer); } if (count($mandatorydatasets) == 0) { // $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent'); foreach ($answers as $key => $answer) { $errors['answer[' . $key . ']'] = get_string('atleastonewildcard', 'qtype_datasetdependent'); } } if ($data['multichoice'] == 1) { foreach ($answers as $key => $answer) { $trimmedanswer = trim($answer); if ($trimmedanswer != '' || $answercount == 0) { //verifying for errors in {=...} in answer text; $qanswer = ""; $qanswerremaining = $trimmedanswer; $possibledatasets = $this->qtypeobj->find_dataset_names($trimmedanswer); foreach ($possibledatasets as $name => $value) { $qanswerremaining = str_replace('{' . $name . '}', '1', $qanswerremaining); } // echo "numericalquestion qanswerremaining <pre>";print_r($possibledatasets); while (preg_match('~\\{=([^[:space:]}]*)}~', $qanswerremaining, $regs1)) { $qanswersplits = explode($regs1[0], $qanswerremaining, 2); $qanswer = $qanswer . $qanswersplits[0]; $qanswerremaining = $qanswersplits[1]; if (!empty($regs1[1]) && ($formulaerrors = qtype_calculated_find_formula_errors($regs1[1]))) { if (!isset($errors['answer[' . $key . ']'])) { $errors['answer[' . $key . ']'] = $formulaerrors . ':' . $regs1[1]; } else { $errors['answer[' . $key . ']'] .= '<br/>' . $formulaerrors . ':' . $regs1[1]; } } } } if ($trimmedanswer != '') { if ('2' == $data['correctanswerformat'][$key] && '0' == $data['correctanswerlength'][$key]) { $errors['correctanswerlength[' . $key . ']'] = get_string('zerosignificantfiguresnotallowed', 'quiz'); } if (!is_numeric($data['tolerance'][$key])) { $errors['tolerance[' . $key . ']'] = get_string('mustbenumeric', 'qtype_calculated'); } if ($data['fraction'][$key] == 1) { $maxgrade = true; } $answercount++; } //check grades $totalfraction = 0; $maxfraction = 0; if ($answer != '') { if ($data['fraction'][$key] > 0) { $totalfraction += $data['fraction'][$key]; } if ($data['fraction'][$key] > $maxfraction) { $maxfraction = $data['fraction'][$key]; } } } if ($answercount == 0) { $errors['answer[0]'] = get_string('notenoughanswers', 'qtype_multichoice', 2); $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2); } elseif ($answercount == 1) { $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2); } /// Perform sanity checks on fractional grades if ($data['single']) { if ($maxfraction > 0.999) { $maxfraction = $maxfraction * 100; $errors['fraction[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction); } } else { $totalfraction = round($totalfraction, 2); if ($totalfraction != 1) { $totalfraction = $totalfraction * 100; $errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction); } } if ($answercount == 0) { $errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated'); } if ($maxgrade == false) { $errors['fraction[0]'] = get_string('fractionsnomax', 'question'); } } return $errors; }
public function substitute_variables_and_eval($str, $dataset) { $formula = $this->substitute_variables($str, $dataset); if ($error = qtype_calculated_find_formula_errors($formula)) { return $error; } // Calculate the correct answer. if (empty($formula)) { $str = ''; } else { if ($formula === '*') { $str = '*'; } else { $str = null; eval('$str = ' . $formula . ';'); } } return $str; }
public function readquestions($lines) { $webctnumberregex = '[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)((e|E|\\*10\\*\\*)([+-]?[0-9]+|\\([+-]?[0-9]+\\)))?'; $questions = array(); $errors = array(); $warnings = array(); $webctoptions = array(); $ignorerestofquestion = false; $nlinecounter = 0; $nquestionstartline = 0; $bishtmltext = false; $lines[] = ":EOF:"; // For an easiest processing of the last line. // We don't call defaultquestion() here, it will be called later. foreach ($lines as $line) { $nlinecounter++; $line = textlib::convert($line, 'windows-1252', 'utf-8'); // Processing multiples lines strings. if (isset($questiontext) and is_string($questiontext)) { if (preg_match("~^:~", $line)) { $questiontext = $this->text_field(trim($questiontext)); $question->questiontext = $questiontext['text']; $question->questiontextformat = $questiontext['format']; if (isset($questiontext['itemid'])) { $question->questiontextitemid = $questiontext['itemid']; } unset($questiontext); } else { $questiontext .= str_replace('\\:', ':', $line); continue; } } if (isset($answertext) and is_string($answertext)) { if (preg_match("~^:~", $line)) { $answertext = trim($answertext); if ($question->qtype == 'multichoice' || $question->qtype == 'match') { $question->answer[$currentchoice] = $this->text_field($answertext); $question->subanswers[$currentchoice] = $question->answer[$currentchoice]; } else { $question->answer[$currentchoice] = $answertext; $question->subanswers[$currentchoice] = $answertext; } unset($answertext); } else { $answertext .= str_replace('\\:', ':', $line); continue; } } if (isset($responsetext) and is_string($responsetext)) { if (preg_match("~^:~", $line)) { $question->subquestions[$currentchoice] = trim($responsetext); unset($responsetext); } else { $responsetext .= str_replace('\\:', ':', $line); continue; } } if (isset($feedbacktext) and is_string($feedbacktext)) { if (preg_match("~^:~", $line)) { $question->feedback[$currentchoice] = $this->text_field(trim($feedbacktext)); unset($feedbacktext); } else { $feedbacktext .= str_replace('\\:', ':', $line); continue; } } if (isset($generalfeedbacktext) and is_string($generalfeedbacktext)) { if (preg_match("~^:~", $line)) { $question->tempgeneralfeedback = trim($generalfeedbacktext); unset($generalfeedbacktext); } else { $generalfeedbacktext .= str_replace('\\:', ':', $line); continue; } } if (isset($graderinfo) and is_string($graderinfo)) { if (preg_match("~^:~", $line)) { $question->graderinfo['text'] = trim($graderinfo); $question->graderinfo['format'] = FORMAT_HTML; unset($graderinfo); } else { $graderinfo .= str_replace('\\:', ':', $line); continue; } } $line = trim($line); if (preg_match("~^:(TYPE|EOF):~i", $line)) { // New Question or End of File. if (isset($question)) { // If previous question exists, complete, check and save it. // Setup default value of missing fields. if (!isset($question->name)) { $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question')); } if (!isset($question->defaultmark)) { $question->defaultmark = 1; } if (!isset($question->image)) { $question->image = ''; } // Perform sanity checks. $questionok = true; if (strlen($question->questiontext) == 0) { $warnings[] = get_string('missingquestion', 'qformat_webct', $nquestionstartline); $questionok = false; } if (count($question->answer) < 1) { // A question must have at least 1 answer. $errors[] = get_string('missinganswer', 'qformat_webct', $nquestionstartline); $questionok = false; } else { // Create empty feedback array. foreach ($question->answer as $key => $dataanswer) { if (!isset($question->feedback[$key])) { $question->feedback[$key]['text'] = ''; $question->feedback[$key]['format'] = FORMAT_HTML; } } // This tempgeneralfeedback allows the code to work with versions from 1.6 to 1.9. // When question->generalfeedback is undefined, the webct feedback is added to each answer feedback. if (isset($question->tempgeneralfeedback)) { if (isset($question->generalfeedback)) { $generalfeedback = $this->text_field($question->tempgeneralfeedback); $question->generalfeedback = $generalfeedback['text']; $question->generalfeedbackformat = $generalfeedback['format']; if (isset($generalfeedback['itemid'])) { $question->genralfeedbackitemid = $generalfeedback['itemid']; } } else { foreach ($question->answer as $key => $dataanswer) { if ($question->tempgeneralfeedback != '') { $question->feedback[$key]['text'] = $question->tempgeneralfeedback . '<br/>' . $question->feedback[$key]['text']; } } } unset($question->tempgeneralfeedback); } $maxfraction = -1; $totalfraction = 0; foreach ($question->fraction as $fraction) { if ($fraction > 0) { $totalfraction += $fraction; } if ($fraction > $maxfraction) { $maxfraction = $fraction; } } switch ($question->qtype) { case 'shortanswer': if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $errors[] = "'{$question->name}': " . get_string('wronggrade', 'qformat_webct', $nlinecounter) . ' ' . get_string('fractionsnomax', 'question', $maxfraction); $questionok = false; } break; case 'multichoice': $question = $this->add_blank_combined_feedback($question); if ($question->single) { if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $errors[] = "'{$question->name}': " . get_string('wronggrade', 'qformat_webct', $nlinecounter) . ' ' . get_string('fractionsnomax', 'question', $maxfraction); $questionok = false; } } else { $totalfraction = round($totalfraction, 2); if ($totalfraction != 1) { $totalfraction = $totalfraction * 100; $errors[] = "'{$question->name}': " . get_string('wronggrade', 'qformat_webct', $nlinecounter) . ' ' . get_string('fractionsaddwrong', 'question', $totalfraction); $questionok = false; } } break; case 'calculated': foreach ($question->answers as $answer) { if ($formulaerror = qtype_calculated_find_formula_errors($answer)) { $warnings[] = "'{$question->name}': " . $formulaerror; $questionok = false; } } foreach ($question->dataset as $dataset) { $dataset->itemcount = count($dataset->datasetitem); } $question->import_process = true; unset($question->answer); // Not used in calculated question. break; case 'match': // MDL-10680: // Switch subquestions and subanswers. $question = $this->add_blank_combined_feedback($question); foreach ($question->subquestions as $id => $subquestion) { $temp = $question->subquestions[$id]; $question->subquestions[$id] = $question->subanswers[$id]; $question->subanswers[$id] = $temp; } if (count($question->answer) < 3) { // Add a dummy missing question. $question->name = 'Dummy question added ' . $question->name; $question->answer[] = 'dummy'; $question->subanswers[] = 'dummy'; $question->subquestions[] = 'dummy'; $question->fraction[] = '0.0'; $question->feedback[] = ''; } break; default: // No problemo. } } if ($questionok) { $questions[] = $question; // Store it. unset($question); // And prepare a new one. $question = $this->defaultquestion(); } } $nquestionstartline = $nlinecounter; } // Processing Question Header. if (preg_match("~^:TYPE:MC:1(.*)~i", $line, $webctoptions)) { // Multiple Choice Question with only one good answer. $question = $this->defaultquestion(); $question->feedback = array(); $question->qtype = 'multichoice'; $question->single = 1; // Only one answer is allowed. $ignorerestofquestion = false; continue; } if (preg_match("~^:TYPE:MC:N(.*)~i", $line, $webctoptions)) { // Multiple Choice Question with several good answers. $question = $this->defaultquestion(); $question->feedback = array(); $question->qtype = 'multichoice'; $question->single = 0; // Many answers allowed. $ignorerestofquestion = false; continue; } if (preg_match("~^:TYPE:S~i", $line)) { // Short Answer Question. $question = $this->defaultquestion(); $question->feedback = array(); $question->qtype = 'shortanswer'; $question->usecase = 0; // Ignore case. $ignorerestofquestion = false; continue; } if (preg_match("~^:TYPE:C~i", $line)) { // Calculated Question. $question = $this->defaultquestion(); $question->qtype = 'calculated'; $question->answer = array(); // No problem as they go as :FORMULA: from webct. $question->units = array(); $question->dataset = array(); $question->fraction = array('1.0'); $question->feedback = array(); $currentchoice = -1; $ignorerestofquestion = false; continue; } if (preg_match("~^:TYPE:M~i", $line)) { // Match Question. $question = $this->defaultquestion(); $question->qtype = 'match'; $question->feedback = array(); $ignorerestofquestion = false; // Match question processing is not debugged. continue; } if (preg_match("~^:TYPE:P~i", $line)) { // Paragraph Question. $question = $this->defaultquestion(); $question->qtype = 'essay'; $question->responseformat = 'editor'; $question->responsefieldlines = 15; $question->attachments = 0; $question->graderinfo = array('text' => '', 'format' => FORMAT_HTML); $question->feedback = array(); $question->generalfeedback = ''; $question->generalfeedbackformat = FORMAT_HTML; $question->generalfeedbackfiles = array(); $question->responsetemplate = $this->text_field(''); $question->questiontextformat = FORMAT_HTML; $ignorerestofquestion = false; // To make us pass the end-of-question sanity checks. $question->answer = array('dummy'); $question->fraction = array('1.0'); continue; } if (preg_match("~^:TYPE:~i", $line)) { // Unknow question type. $warnings[] = get_string('unknowntype', 'qformat_webct', $nlinecounter); unset($question); $ignorerestofquestion = true; // Question Type not handled by Moodle. continue; } if ($ignorerestofquestion) { continue; } if (preg_match("~^:TITLE:(.*)~i", $line, $webctoptions)) { $name = trim($webctoptions[1]); $question->name = $this->clean_question_name($name); continue; } if (preg_match("~^:IMAGE:(.*)~i", $line, $webctoptions)) { $filename = trim($webctoptions[1]); if (preg_match("~^http://~i", $filename)) { $question->image = $filename; } continue; } // Need to put the parsing of calculated items here to avoid ambitiuosness: // if question isn't defined yet there is nothing to do here (avoid notices). if (!isset($question)) { continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match("~^:([[:lower:]].*|::.*)-(MIN|MAX|DEC|VAL([0-9]+))::?:?({$webctnumberregex})~", $line, $webctoptions)) { $datasetname = preg_replace('/^::/', '', $webctoptions[1]); $datasetvalue = qformat_webct_convert_formula($webctoptions[4]); switch ($webctoptions[2]) { case 'MIN': $question->dataset[$datasetname]->min = $datasetvalue; break; case 'MAX': $question->dataset[$datasetname]->max = $datasetvalue; break; case 'DEC': $datasetvalue = floor($datasetvalue); // Int only! $question->dataset[$datasetname]->length = max(0, $datasetvalue); break; default: // The VAL case. $question->dataset[$datasetname]->datasetitem[$webctoptions[3]] = new stdClass(); $question->dataset[$datasetname]->datasetitem[$webctoptions[3]]->itemnumber = $webctoptions[3]; $question->dataset[$datasetname]->datasetitem[$webctoptions[3]]->value = $datasetvalue; break; } continue; } $bishtmltext = preg_match("~:H\$~i", $line); // True if next lines are coded in HTML. if (preg_match("~^:QUESTION~i", $line)) { $questiontext = ''; // Start gathering next lines. continue; } if (preg_match("~^:ANSWER([0-9]+):([^:]+):([0-9\\.\\-]+):(.*)~i", $line, $webctoptions)) { // Shortanswer. $currentchoice = $webctoptions[1]; $answertext = $webctoptions[2]; // Start gathering next lines. $question->fraction[$currentchoice] = $webctoptions[3] / 100; continue; } if (preg_match("~^:ANSWER([0-9]+):([0-9\\.\\-]+)~i", $line, $webctoptions)) { $answertext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; $question->fraction[$currentchoice] = $webctoptions[2] / 100; continue; } if (preg_match('~^:ANSWER:~i', $line)) { // Essay. $graderinfo = ''; // Start gathering next lines. continue; } if (preg_match('~^:FORMULA:(.*)~i', $line, $webctoptions)) { // Answer for a calculated question. ++$currentchoice; $question->answer[$currentchoice] = qformat_webct_convert_formula($webctoptions[1]); // Default settings. $question->fraction[$currentchoice] = 1.0; $question->tolerance[$currentchoice] = 0.0; $question->tolerancetype[$currentchoice] = 2; // Nominal (units in webct). $question->feedback[$currentchoice]['text'] = ''; $question->feedback[$currentchoice]['format'] = FORMAT_HTML; $question->correctanswerlength[$currentchoice] = 4; $datasetnames = question_bank::get_qtype('calculated')->find_dataset_names($webctoptions[1]); foreach ($datasetnames as $datasetname) { $question->dataset[$datasetname] = new stdClass(); $question->dataset[$datasetname]->datasetitem = array(); $question->dataset[$datasetname]->name = $datasetname; $question->dataset[$datasetname]->distribution = 'uniform'; $question->dataset[$datasetname]->status = 'private'; } continue; } if (preg_match("~^:L([0-9]+)~i", $line, $webctoptions)) { $answertext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; $question->fraction[$currentchoice] = 1; continue; } if (preg_match("~^:R([0-9]+)~i", $line, $webctoptions)) { $responsetext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; continue; } if (preg_match("~^:REASON([0-9]+):?~i", $line, $webctoptions)) { $feedbacktext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; continue; } if (preg_match("~^:FEEDBACK([0-9]+):?~i", $line, $webctoptions)) { $generalfeedbacktext = ''; // Start gathering next lines. $currentchoice = $webctoptions[1]; continue; } if (preg_match('~^:FEEDBACK:(.*)~i', $line, $webctoptions)) { $generalfeedbacktext = ''; // Start gathering next lines. continue; } if (preg_match('~^:LAYOUT:(.*)~i', $line, $webctoptions)) { // Ignore since layout in question_multichoice is no more used in Moodle. // $webctoptions[1] contains either vertical or horizontal. continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match('~^:ANS-DEC:([1-9][0-9]*)~i', $line, $webctoptions)) { // We can but hope that this always appear before the ANSTYPE property. $question->correctanswerlength[$currentchoice] = $webctoptions[1]; continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match("~^:TOL:({$webctnumberregex})~i", $line, $webctoptions)) { // We can but hope that this always appear before the TOL property. $question->tolerance[$currentchoice] = qformat_webct_convert_formula($webctoptions[1]); continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match('~^:TOLTYPE:percent~i', $line)) { // Percentage case is handled as relative in Moodle. $question->tolerance[$currentchoice] /= 100; $question->tolerancetype[$currentchoice] = 1; // Relative. continue; } if (preg_match('~^:UNITS:(.+)~i', $line, $webctoptions) and $webctunits = trim($webctoptions[1])) { // This is a guess - I really do not know how different webct units are separated... $webctunits = explode(':', $webctunits); $unitrec->multiplier = 1.0; // Webct does not seem to support this. foreach ($webctunits as $webctunit) { $unitrec->unit = trim($webctunit); $question->units[] = $unitrec; } continue; } if (!empty($question->units) && preg_match('~^:UNITREQ:(.*)~i', $line, $webctoptions) && !$webctoptions[1]) { // There are units but units are not required so add the no unit alternative. // We can but hope that the UNITS property always appear before this property. $unitrec->unit = ''; $unitrec->multiplier = 1.0; $question->units[] = $unitrec; continue; } if (!empty($question->units) && preg_match('~^:UNITCASE:~i', $line)) { // This could be important but I was not able to figure out how // it works so I ignore it for now. continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match('~^:ANSTYPE:dec~i', $line)) { $question->correctanswerformat[$currentchoice] = '1'; continue; } if (isset($question->qtype) && 'calculated' == $question->qtype && preg_match('~^:ANSTYPE:sig~i', $line)) { $question->correctanswerformat[$currentchoice] = '2'; continue; } } if (count($errors) > 0) { echo '<p>' . get_string('errorsdetected', 'qformat_webct', count($errors)) . '</p><ul>'; foreach ($errors as $error) { echo "<li>{$error}</li>"; } echo '</ul>'; unset($questions); // No questions imported. } if (count($warnings) > 0) { echo '<p>' . get_string('warningsdetected', 'qformat_webct', count($warnings)) . '</p><ul>'; foreach ($warnings as $warning) { echo "<li>{$warning}</li>"; } echo '</ul>'; } return $questions; }
function substitute_variables($str, $dataset) { $formula = parent::substitute_variables($str, $dataset); if ($error = qtype_calculated_find_formula_errors($formula)) { return $error; } /// Calculate the correct answer if (empty($formula)) { $str = ''; } else { if ($formula === '*') { $str = '*'; } else { eval('$str = ' . $formula . ';'); } } return $str; }
protected function valid_answer_message($answer) { if (!$answer) { return get_string('mustenteraformulaorstar', 'qtype_numerical'); } else { return qtype_calculated_find_formula_errors($answer); } }
public function validation($data, $files) { $errors = parent::validation($data, $files); // Verifying for errors in {=...} in question text. $qtext = ''; $qtextremaining = $data['questiontext']['text']; $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']); foreach ($possibledatasets as $name => $value) { $qtextremaining = str_replace('{' . $name . '}', '1', $qtextremaining); } while (preg_match('~\\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) { $qtextsplits = explode($regs1[0], $qtextremaining, 2); $qtext = $qtext . $qtextsplits[0]; $qtextremaining = $qtextsplits[1]; if (!empty($regs1[1]) && ($formulaerrors = qtype_calculated_find_formula_errors($regs1[1]))) { if (!isset($errors['questiontext'])) { $errors['questiontext'] = $formulaerrors . ':' . $regs1[1]; } else { $errors['questiontext'] .= '<br/>' . $formulaerrors . ':' . $regs1[1]; } } } $answers = $data['answer']; $answercount = 0; $maxgrade = false; $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']); $mandatorydatasets = array(); foreach ($answers as $key => $answer) { $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer); } if (count($mandatorydatasets) == 0) { foreach ($answers as $key => $answer) { $errors['answeroptions[' . $key . ']'] = get_string('atleastonewildcard', 'qtype_calculated'); } } $totalfraction = 0; $maxfraction = -1; foreach ($answers as $key => $answer) { $trimmedanswer = trim($answer); $fraction = (double) $data['fraction'][$key]; if (empty($trimmedanswer) && $trimmedanswer != '0' && empty($fraction)) { continue; } if (empty($trimmedanswer)) { $errors['answeroptions[' . $key . ']'] = get_string('errgradesetanswerblank', 'qtype_multichoice'); } if ($trimmedanswer != '' || $answercount == 0) { // Verifying for errors in {=...} in answer text. $qanswer = ''; $qanswerremaining = $trimmedanswer; $possibledatasets = $this->qtypeobj->find_dataset_names($trimmedanswer); foreach ($possibledatasets as $name => $value) { $qanswerremaining = str_replace('{' . $name . '}', '1', $qanswerremaining); } while (preg_match('~\\{=([^[:space:]}]*)}~', $qanswerremaining, $regs1)) { $qanswersplits = explode($regs1[0], $qanswerremaining, 2); $qanswer = $qanswer . $qanswersplits[0]; $qanswerremaining = $qanswersplits[1]; if (!empty($regs1[1]) && ($formulaerrors = qtype_calculated_find_formula_errors($regs1[1]))) { if (!isset($errors['answeroptions[' . $key . ']'])) { $errors['answeroptions[' . $key . ']'] = $formulaerrors . ':' . $regs1[1]; } else { $errors['answeroptions[' . $key . ']'] .= '<br/>' . $formulaerrors . ':' . $regs1[1]; } } } } if ($trimmedanswer != '') { if ('2' == $data['correctanswerformat'][$key] && '0' == $data['correctanswerlength'][$key]) { $errors['correctanswerlength[' . $key . ']'] = get_string('zerosignificantfiguresnotallowed', 'qtype_calculated'); } if (!is_numeric($data['tolerance'][$key])) { $errors['tolerance[' . $key . ']'] = get_string('xmustbenumeric', 'qtype_numerical', get_string('acceptederror', 'qtype_numerical')); } if ($data['fraction'][$key] > 0) { $totalfraction += $data['fraction'][$key]; } if ($data['fraction'][$key] > $maxfraction) { $maxfraction = $data['fraction'][$key]; } $answercount++; } } if ($answercount == 0) { $errors['answeroptions[0]'] = get_string('notenoughanswers', 'qtype_multichoice', 2); $errors['answeroptions[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2); } else { if ($answercount == 1) { $errors['answeroptions[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2); } } // Perform sanity checks on fractional grades. if ($data['single'] == 1) { if ($maxfraction != 1) { $errors['answeroptions[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction * 100); } } else { $totalfraction = round($totalfraction, 2); if ($totalfraction != 1) { $totalfraction = $totalfraction * 100; $errors['answeroptions[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction); } } return $errors; }
function readquestions($lines) { global $QTYPES; // $qtypecalculated = new qformat_webct_modified_calculated_qtype(); $webctnumberregex = '[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)((e|E|\\*10\\*\\*)([+-]?[0-9]+|\\([+-]?[0-9]+\\)))?'; $questions = array(); $errors = array(); $warnings = array(); $webct_options = array(); $ignore_rest_of_question = FALSE; $nLineCounter = 0; $nQuestionStartLine = 0; $bIsHTMLText = FALSE; $lines[] = ":EOF:"; // for an easiest processing of the last line // $question = $this->defaultquestion(); foreach ($lines as $line) { $nLineCounter++; $line = iconv("Windows-1252", "UTF-8", $line); // Processing multiples lines strings if (isset($questiontext) and is_string($questiontext)) { if (preg_match("~^:~", $line)) { $question->questiontext = trim($questiontext); unset($questiontext); } else { $questiontext .= str_replace('\\:', ':', $line); continue; } } if (isset($answertext) and is_string($answertext)) { if (preg_match("~^:~", $line)) { $answertext = trim($answertext); $question->answer[$currentchoice] = $answertext; $question->subanswers[$currentchoice] = $answertext; unset($answertext); } else { $answertext .= str_replace('\\:', ':', $line); continue; } } if (isset($responsetext) and is_string($responsetext)) { if (preg_match("~^:~", $line)) { $question->subquestions[$currentchoice] = trim($responsetext); unset($responsetext); } else { $responsetext .= str_replace('\\:', ':', $line); continue; } } if (isset($feedbacktext) and is_string($feedbacktext)) { if (preg_match("~^:~", $line)) { $question->feedback[$currentchoice] = trim($feedbacktext); unset($feedbacktext); } else { $feedbacktext .= str_replace('\\:', ':', $line); continue; } } if (isset($generalfeedbacktext) and is_string($generalfeedbacktext)) { if (preg_match("~^:~", $line)) { $question->tempgeneralfeedback = trim($generalfeedbacktext); unset($generalfeedbacktext); } else { $generalfeedbacktext .= str_replace('\\:', ':', $line); continue; } } $line = trim($line); if (preg_match("~^:(TYPE|EOF):~i", $line)) { // New Question or End of File if (isset($question)) { // if previous question exists, complete, check and save it // Setup default value of missing fields if (!isset($question->name)) { $question->name = $question->questiontext; } if (strlen($question->name) > 255) { $question->name = substr($question->name, 0, 250) . "..."; $warnings[] = get_string("questionnametoolong", "quiz", $nQuestionStartLine); } if (!isset($question->defaultgrade)) { $question->defaultgrade = 1; } if (!isset($question->image)) { $question->image = ""; } // Perform sanity checks $QuestionOK = TRUE; if (strlen($question->questiontext) == 0) { $warnings[] = get_string("missingquestion", "quiz", $nQuestionStartLine); $QuestionOK = FALSE; } if (sizeof($question->answer) < 1) { // a question must have at least 1 answer $errors[] = get_string("missinganswer", "quiz", $nQuestionStartLine); $QuestionOK = FALSE; } else { // Create empty feedback array foreach ($question->answer as $key => $dataanswer) { if (!isset($question->feedback[$key])) { $question->feedback[$key] = ''; } } // this tempgeneralfeedback allows the code to work with versions from 1.6 to 1.9 // when question->generalfeedback is undefined, the webct feedback is added to each answer feedback if (isset($question->tempgeneralfeedback)) { if (isset($question->generalfeedback)) { $question->generalfeedback = $question->tempgeneralfeedback; } else { foreach ($question->answer as $key => $dataanswer) { if ($question->tempgeneralfeedback != '') { $question->feedback[$key] = $question->tempgeneralfeedback . '<br/>' . $question->feedback[$key]; } } } unset($question->tempgeneralfeedback); } $maxfraction = -1; $totalfraction = 0; foreach ($question->fraction as $fraction) { if ($fraction > 0) { $totalfraction += $fraction; } if ($fraction > $maxfraction) { $maxfraction = $fraction; } } switch ($question->qtype) { case SHORTANSWER: if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $errors[] = "'{$question->name}': " . get_string("wronggrade", "quiz", $nLineCounter) . ' ' . get_string("fractionsnomax", "quiz", $maxfraction); $QuestionOK = FALSE; } break; case MULTICHOICE: if ($question->single) { if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $errors[] = "'{$question->name}': " . get_string("wronggrade", "quiz", $nLineCounter) . ' ' . get_string("fractionsnomax", "quiz", $maxfraction); $QuestionOK = FALSE; } } else { $totalfraction = round($totalfraction, 2); if ($totalfraction != 1) { $totalfraction = $totalfraction * 100; $errors[] = "'{$question->name}': " . get_string("wronggrade", "quiz", $nLineCounter) . ' ' . get_string("fractionsaddwrong", "quiz", $totalfraction); $QuestionOK = FALSE; } } break; case CALCULATED: foreach ($question->answers as $answer) { if ($formulaerror = qtype_calculated_find_formula_errors($answer)) { //$QTYPES['calculated']-> $warnings[] = "'{$question->name}': " . $formulaerror; $QuestionOK = FALSE; } } foreach ($question->dataset as $dataset) { $dataset->itemcount = count($dataset->datasetitem); } $question->import_process = TRUE; unset($question->answer); //not used in calculated question break; case MATCH: // MDL-10680: // switch subquestions and subanswers foreach ($question->subquestions as $id => $subquestion) { $temp = $question->subquestions[$id]; $question->subquestions[$id] = $question->subanswers[$id]; $question->subanswers[$id] = $temp; } if (count($question->answer) < 3) { // add a dummy missing question $question->name = 'Dummy question added ' . $question->name; $question->answer[] = 'dummy'; $question->subanswers[] = 'dummy'; $question->subquestions[] = 'dummy'; $question->fraction[] = '0.0'; $question->feedback[] = ''; } break; default: // No problemo } } if ($QuestionOK) { // echo "<pre>"; print_r ($question); $questions[] = $question; // store it unset($question); // and prepare a new one $question = $this->defaultquestion(); } } $nQuestionStartLine = $nLineCounter; } // Processing Question Header if (preg_match("~^:TYPE:MC:1(.*)~i", $line, $webct_options)) { // Multiple Choice Question with only one good answer $question = $this->defaultquestion(); $question->feedback = array(); $question->qtype = MULTICHOICE; $question->single = 1; // Only one answer is allowed $ignore_rest_of_question = FALSE; continue; } if (preg_match("~^:TYPE:MC:N(.*)~i", $line, $webct_options)) { // Multiple Choice Question with several good answers $question = $this->defaultquestion(); $question->feedback = array(); $question->qtype = MULTICHOICE; $question->single = 0; // Many answers allowed $ignore_rest_of_question = FALSE; continue; } if (preg_match("~^:TYPE:S~i", $line)) { // Short Answer Question $question = $this->defaultquestion(); $question->feedback = array(); $question->qtype = SHORTANSWER; $question->usecase = 0; // Ignore case $ignore_rest_of_question = FALSE; continue; } if (preg_match("~^:TYPE:C~i", $line)) { // Calculated Question /* $warnings[] = get_string("calculatedquestion", "quiz", $nLineCounter); unset($question); $ignore_rest_of_question = TRUE; // Question Type not handled by Moodle */ $question = $this->defaultquestion(); $question->qtype = CALCULATED; $question->answers = array(); // No problem as they go as :FORMULA: from webct $question->units = array(); $question->dataset = array(); // To make us pass the end-of-question sanity checks $question->answer = array('dummy'); $question->fraction = array('1.0'); $question->feedback = array(); $currentchoice = -1; $ignore_rest_of_question = FALSE; continue; } if (preg_match("~^:TYPE:M~i", $line)) { // Match Question $question = $this->defaultquestion(); $question->qtype = MATCH; $question->feedback = array(); $ignore_rest_of_question = FALSE; // match question processing is not debugged continue; } if (preg_match("~^:TYPE:P~i", $line)) { // Paragraph Question $warnings[] = get_string("paragraphquestion", "quiz", $nLineCounter); unset($question); $ignore_rest_of_question = TRUE; // Question Type not handled by Moodle continue; } if (preg_match("~^:TYPE:~i", $line)) { // Unknow Question $warnings[] = get_string("unknowntype", "quiz", $nLineCounter); unset($question); $ignore_rest_of_question = TRUE; // Question Type not handled by Moodle continue; } if ($ignore_rest_of_question) { continue; } if (preg_match("~^:TITLE:(.*)~i", $line, $webct_options)) { $name = trim($webct_options[1]); if (strlen($name) > 255) { $name = substr($name, 0, 250) . "..."; $warnings[] = get_string("questionnametoolong", "quiz", $nLineCounter); } $question->name = $name; continue; } if (preg_match("~^:IMAGE:(.*)~i", $line, $webct_options)) { $filename = trim($webct_options[1]); if (preg_match("~^http://~i", $filename)) { $question->image = $filename; } continue; } // Need to put the parsing of calculated items here to avoid ambitiuosness: // if question isn't defined yet there is nothing to do here (avoid notices) if (!isset($question)) { continue; } if (isset($question->qtype) && CALCULATED == $question->qtype && preg_match("~^:([[:lower:]].*|::.*)-(MIN|MAX|DEC|VAL([0-9]+))::?:?({$webctnumberregex})~", $line, $webct_options)) { $datasetname = preg_replace('/^::/', '', $webct_options[1]); $datasetvalue = qformat_webct_convert_formula($webct_options[4]); switch ($webct_options[2]) { case 'MIN': $question->dataset[$datasetname]->min = $datasetvalue; break; case 'MAX': $question->dataset[$datasetname]->max = $datasetvalue; break; case 'DEC': $datasetvalue = floor($datasetvalue); // int only! $question->dataset[$datasetname]->length = max(0, $datasetvalue); break; default: // The VAL case: $question->dataset[$datasetname]->datasetitem[$webct_options[3]] = new stdClass(); $question->dataset[$datasetname]->datasetitem[$webct_options[3]]->itemnumber = $webct_options[3]; $question->dataset[$datasetname]->datasetitem[$webct_options[3]]->value = $datasetvalue; break; } continue; } $bIsHTMLText = preg_match("~:H\$~i", $line); // True if next lines are coded in HTML if (preg_match("~^:QUESTION~i", $line)) { $questiontext = ""; // Start gathering next lines continue; } if (preg_match("~^:ANSWER([0-9]+):([^:]+):([0-9\\.\\-]+):(.*)~i", $line, $webct_options)) { /// SHORTANSWER $currentchoice = $webct_options[1]; $answertext = $webct_options[2]; // Start gathering next lines $question->fraction[$currentchoice] = $webct_options[3] / 100; continue; } if (preg_match("~^:ANSWER([0-9]+):([0-9\\.\\-]+)~i", $line, $webct_options)) { $answertext = ""; // Start gathering next lines $currentchoice = $webct_options[1]; $question->fraction[$currentchoice] = $webct_options[2] / 100; continue; } if (preg_match('~^:FORMULA:(.*)~i', $line, $webct_options)) { // Answer for a CALCULATED question ++$currentchoice; $question->answers[$currentchoice] = qformat_webct_convert_formula($webct_options[1]); // Default settings: $question->fraction[$currentchoice] = 1.0; $question->tolerance[$currentchoice] = 0.0; $question->tolerancetype[$currentchoice] = 2; // nominal (units in webct) $question->feedback[$currentchoice] = ''; $question->correctanswerlength[$currentchoice] = 4; $datasetnames = $QTYPES[CALCULATED]->find_dataset_names($webct_options[1]); foreach ($datasetnames as $datasetname) { $question->dataset[$datasetname] = new stdClass(); $question->dataset[$datasetname]->datasetitem = array(); $question->dataset[$datasetname]->name = $datasetname; $question->dataset[$datasetname]->distribution = 'uniform'; $question->dataset[$datasetname]->status = 'private'; } continue; } if (preg_match("~^:L([0-9]+)~i", $line, $webct_options)) { $answertext = ""; // Start gathering next lines $currentchoice = $webct_options[1]; $question->fraction[$currentchoice] = 1; continue; } if (preg_match("~^:R([0-9]+)~i", $line, $webct_options)) { $responsetext = ""; // Start gathering next lines $currentchoice = $webct_options[1]; continue; } if (preg_match("~^:REASON([0-9]+):?~i", $line, $webct_options)) { $feedbacktext = ""; // Start gathering next lines $currentchoice = $webct_options[1]; continue; } if (preg_match("~^:FEEDBACK([0-9]+):?~i", $line, $webct_options)) { $generalfeedbacktext = ""; // Start gathering next lines $currentchoice = $webct_options[1]; continue; } if (preg_match('~^:FEEDBACK:(.*)~i', $line, $webct_options)) { $generalfeedbacktext = ""; // Start gathering next lines continue; } if (preg_match('~^:LAYOUT:(.*)~i', $line, $webct_options)) { // ignore since layout in question_multichoice is no more used in moodle // $webct_options[1] contains either vertical or horizontal ; continue; } if (isset($question->qtype) && CALCULATED == $question->qtype && preg_match('~^:ANS-DEC:([1-9][0-9]*)~i', $line, $webct_options)) { // We can but hope that this always appear before the ANSTYPE property $question->correctanswerlength[$currentchoice] = $webct_options[1]; continue; } if (isset($question->qtype) && CALCULATED == $question->qtype && preg_match("~^:TOL:({$webctnumberregex})~i", $line, $webct_options)) { // We can but hope that this always appear before the TOL property $question->tolerance[$currentchoice] = qformat_webct_convert_formula($webct_options[1]); continue; } if (isset($question->qtype) && CALCULATED == $question->qtype && preg_match('~^:TOLTYPE:percent~i', $line)) { // Percentage case is handled as relative in Moodle: $question->tolerance[$currentchoice] /= 100; $question->tolerancetype[$currentchoice] = 1; // Relative continue; } if (preg_match('~^:UNITS:(.+)~i', $line, $webct_options) and $webctunits = trim($webct_options[1])) { // This is a guess - I really do not know how different webct units are separated... $webctunits = explode(':', $webctunits); $unitrec->multiplier = 1.0; // Webct does not seem to support this foreach ($webctunits as $webctunit) { $unitrec->unit = trim($webctunit); $question->units[] = $unitrec; } continue; } if (!empty($question->units) && preg_match('~^:UNITREQ:(.*)~i', $line, $webct_options) && !$webct_options[1]) { // There are units but units are not required so add the no unit alternative // We can but hope that the UNITS property always appear before this property $unitrec->unit = ''; $unitrec->multiplier = 1.0; $question->units[] = $unitrec; continue; } if (!empty($question->units) && preg_match('~^:UNITCASE:~i', $line)) { // This could be important but I was not able to figure out how // it works so I ignore it for now continue; } if (isset($question->qtype) && CALCULATED == $question->qtype && preg_match('~^:ANSTYPE:dec~i', $line)) { $question->correctanswerformat[$currentchoice] = '1'; continue; } if (isset($question->qtype) && CALCULATED == $question->qtype && preg_match('~^:ANSTYPE:sig~i', $line)) { $question->correctanswerformat[$currentchoice] = '2'; continue; } } if (sizeof($errors) > 0) { echo "<p>" . get_string("errorsdetected", "quiz", sizeof($errors)) . "</p><ul>"; foreach ($errors as $error) { echo "<li>{$error}</li>"; } echo "</ul>"; unset($questions); // no questions imported } if (sizeof($warnings) > 0) { echo "<p>" . get_string("warningsdetected", "quiz", sizeof($warnings)) . "</p><ul>"; foreach ($warnings as $warning) { echo "<li>{$warning}</li>"; } echo "</ul>"; } return $questions; }
public function comment_on_datasetitems($qtypeobj, $questionid, $questiontext, $answers, $data, $number) { global $DB; $comment = new stdClass(); $comment->stranswers = array(); $comment->outsidelimit = false; $comment->answers = array(); $answers = fullclone($answers); $errors = ''; $delimiter = ': '; foreach ($answers as $key => $answer) { $answer->answer = $this->substitute_variables($answer->answer, $data); //evaluate the equations i.e {=5+4) $qtext = ''; $qtextremaining = $answer->answer; while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) { $qtextsplits = explode($regs1[0], $qtextremaining, 2); $qtext =$qtext.$qtextsplits[0]; $qtextremaining = $qtextsplits[1]; if (empty($regs1[1])) { $str = ''; } else { if ($formulaerrors = qtype_calculated_find_formula_errors($regs1[1])) { $str=$formulaerrors; } else { eval('$str = '.$regs1[1].';'); } } $qtext = $qtext.$str; } $answer->answer = $qtext.$qtextremaining; $comment->stranswers[$key] = $answer->answer; } return fullclone($comment); }
function validation($data, $files) { $errors = parent::validation($data, $files); //verifying for errors in {=...} in question text; $qtext = ""; $qtextremaining = $data['questiontext']; $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']); foreach ($possibledatasets as $name => $value) { $qtextremaining = str_replace('{' . $name . '}', '1', $qtextremaining); } while (preg_match('~\\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) { $qtextsplits = explode($regs1[0], $qtextremaining, 2); $qtext = $qtext . $qtextsplits[0]; $qtextremaining = $qtextsplits[1]; if (!empty($regs1[1]) && ($formulaerrors = qtype_calculated_find_formula_errors($regs1[1]))) { if (!isset($errors['questiontext'])) { $errors['questiontext'] = $formulaerrors . ':' . $regs1[1]; } else { $errors['questiontext'] .= '<br/>' . $formulaerrors . ':' . $regs1[1]; } } } $answers = $data['answer']; $answercount = 0; $maxgrade = false; $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']); $mandatorydatasets = array(); foreach ($answers as $key => $answer) { $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer); } if (count($mandatorydatasets) == 0) { foreach ($answers as $key => $answer) { $errors['answer[' . $key . ']'] = get_string('atleastonewildcard', 'qtype_datasetdependent'); } } foreach ($answers as $key => $answer) { //check no of choices // the * for everykind of answer not actually implemented $trimmedanswer = trim($answer); if ($trimmedanswer != '' || $answercount == 0) { $eqerror = qtype_calculated_find_formula_errors($trimmedanswer); if (FALSE !== $eqerror) { $errors['answer[' . $key . ']'] = $eqerror; } } if ($trimmedanswer != '') { if ('2' == $data['correctanswerformat'][$key] && '0' == $data['correctanswerlength'][$key]) { $errors['correctanswerlength[' . $key . ']'] = get_string('zerosignificantfiguresnotallowed', 'quiz'); } if (!is_numeric($data['tolerance'][$key])) { $errors['tolerance[' . $key . ']'] = get_string('mustbenumeric', 'qtype_calculated'); } if ($data['fraction'][$key] == 1) { $maxgrade = true; } $answercount++; } //check grades //TODO how should grade checking work here?? /*if ($answer != '') { if ($data['fraction'][$key] > 0) { $totalfraction += $data['fraction'][$key]; } if ($data['fraction'][$key] > $maxfraction) { $maxfraction = $data['fraction'][$key]; } }*/ } //grade checking : /// Perform sanity checks on fractional grades /*if ( ) { if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $errors['fraction[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction); } } else { $totalfraction = round($totalfraction,2); if ($totalfraction != 1) { $totalfraction = $totalfraction * 100; $errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction); } }*/ $units = $data['unit']; if (count($units)) { foreach ($units as $key => $unit) { if (is_numeric($unit)) { $errors['unit[' . $key . ']'] = get_string('mustnotbenumeric', 'qtype_calculated'); } $trimmedunit = trim($unit); $trimmedmultiplier = trim($data['multiplier'][$key]); if (!empty($trimmedunit)) { if (empty($trimmedmultiplier)) { $errors['multiplier[' . $key . ']'] = get_string('youmustenteramultiplierhere', 'qtype_calculated'); } if (!is_numeric($trimmedmultiplier)) { $errors['multiplier[' . $key . ']'] = get_string('mustbenumeric', 'qtype_calculated'); } } } } if ($answercount == 0) { $errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated'); } if ($maxgrade == false) { $errors['fraction[0]'] = get_string('fractionsnomax', 'question'); } if (isset($data['backtoquiz']) && $this->noofitems == 0) { $errors['warning'] = get_string('warning', 'mnet'); } if ($this->outsidelimit) { // if(!isset($errors['warning'])) $errors['warning']=' '; $errors['outsidelimits'] = get_string('oneanswertrueansweroutsidelimits', 'qtype_calculated'); } /*Here we use the already done the error analysis so that * we could force all wild cards values display if there is an error in values. * as using a , in a number */ $numbers = $data['number']; foreach ($numbers as $key => $number) { if (!is_numeric($number)) { if (stristr($number, ',')) { $errors['number[' . $key . ']'] = get_string('notvalidnumber', 'qtype_datasetdependent'); } else { $errors['number[' . $key . ']'] = get_string('notvalidnumber', 'qtype_datasetdependent'); } } else { if (stristr($number, 'x')) { $errors['number[' . $key . ']'] = get_string('notvalidnumber', 'qtype_datasetdependent'); } else { if (is_nan($number)) { $errors['number[' . $key . ']'] = get_string('notvalidnumber', 'qtype_datasetdependent'); } } } } if ($this->noofitems == 0) { $errors['warning'] = get_string('warning', 'mnet'); } return $errors; }
protected function definition() { global $PAGE; $labelsharedwildcard = get_string("sharedwildcard", "qtype_calculated"); $mform = $this->_form; $mform->setDisableShortforms(); $strquestionlabel = $this->qtypeobj->comment_header($this->question); if ($this->maxnumber != -1) { $this->noofitems = $this->maxnumber; } else { $this->noofitems = 0; } $label = get_string("sharedwildcards", "qtype_calculated"); $html2 = $this->qtypeobj->print_dataset_definitions_category_shared($this->question, $this->datasetdefs); $mform->addElement('static', 'listcategory', $label, $html2); // ...----------------------------------------------------------------------. $mform->addElement('submit', 'updatedatasets', get_string('updatedatasetparam', 'qtype_calculated')); $mform->registerNoSubmitButton('updatedatasets'); $mform->addElement('header', 'additemhdr', get_string('itemtoadd', 'qtype_calculated')); $idx = 1; $data = array(); $j = $this->noofitems * count($this->datasetdefs) + 1; foreach ($this->datasetdefs as $defkey => $datasetdef) { if ($datasetdef->category |= 0) { $name = get_string('sharedwildcard', 'qtype_calculated', $datasetdef->name); } else { $name = get_string('wildcard', 'qtype_calculated', $datasetdef->name); } $mform->addElement('text', "number[{$j}]", $name); $mform->setType("number[{$j}]", PARAM_RAW); // This parameter will be validated in validation(). $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j); $idx++; $mform->addElement('hidden', "definition[{$j}]"); $mform->setType("definition[{$j}]", PARAM_RAW); $mform->addElement('hidden', "itemid[{$j}]"); $mform->setType("itemid[{$j}]", PARAM_RAW); $mform->addElement('static', "divider[{$j}]", '', '<hr />'); $mform->setType("divider[{$j}]", PARAM_RAW); $j++; } $mform->addElement('header', 'updateanswershdr', get_string('answerstoleranceparam', 'qtype_calculated')); $mform->addElement('submit', 'updateanswers', get_string('updatetolerancesparam', 'qtype_calculated')); $mform->setAdvanced('updateanswers', true); $mform->registerNoSubmitButton('updateanswers'); $answers = fullclone($this->question->options->answers); $key1 = 1; foreach ($answers as $key => $answer) { $ans = shorten_text($answer->answer, 17, true); if ($ans === '*') { $mform->addElement('static', 'answercomment[' . ($this->noofitems + $key1) . ']', $ans); $mform->addElement('hidden', 'tolerance[' . $key . ']', ''); $mform->setType('tolerance[' . $key . ']', PARAM_RAW); $mform->setAdvanced('tolerance[' . $key . ']', true); $mform->addElement('hidden', 'tolerancetype[' . $key . ']', ''); $mform->setType('tolerancetype[' . $key . ']', PARAM_RAW); $mform->setAdvanced('tolerancetype[' . $key . ']', true); $mform->addElement('hidden', 'correctanswerlength[' . $key . ']', ''); $mform->setType('correctanswerlength[' . $key . ']', PARAM_RAW); $mform->setAdvanced('correctanswerlength[' . $key . ']', true); $mform->addElement('hidden', 'correctanswerformat[' . $key . ']', ''); $mform->setType('correctanswerformat[' . $key . ']', PARAM_RAW); $mform->setAdvanced('correctanswerformat[' . $key . ']', true); } else { if ($ans !== '') { $mform->addElement('static', 'answercomment[' . ($this->noofitems + $key1) . ']', $ans); $mform->addElement('text', 'tolerance[' . $key . ']', get_string('tolerance', 'qtype_calculated')); $mform->setType('tolerance[' . $key . ']', PARAM_RAW); $mform->setAdvanced('tolerance[' . $key . ']', true); $mform->addElement('select', 'tolerancetype[' . $key . ']', get_string('tolerancetype', 'qtype_numerical'), $this->qtypeobj->tolerance_types()); $mform->setAdvanced('tolerancetype[' . $key . ']', true); $mform->addElement('select', 'correctanswerlength[' . $key . ']', get_string('correctanswershows', 'qtype_calculated'), range(0, 9)); $mform->setAdvanced('correctanswerlength[' . $key . ']', true); $answerlengthformats = array('1' => get_string('decimalformat', 'qtype_numerical'), '2' => get_string('significantfiguresformat', 'qtype_calculated')); $mform->addElement('select', 'correctanswerformat[' . $key . ']', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats); $mform->setAdvanced('correctanswerformat[' . $key . ']', true); $mform->addElement('static', 'dividertolerance', '', '<hr />'); $mform->setAdvanced('dividertolerance', true); } } $key1++; } $addremoveoptions = array(); $addremoveoptions['1'] = '1'; for ($i = 10; $i <= 100; $i += 10) { $addremoveoptions["{$i}"] = "{$i}"; } $showoptions = array(); $showoptions['1'] = '1'; $showoptions['2'] = '2'; $showoptions['5'] = '5'; for ($i = 10; $i <= 100; $i += 10) { $showoptions["{$i}"] = "{$i}"; } $mform->addElement('header', 'addhdr', get_string('add', 'moodle')); $mform->closeHeaderBefore('addhdr'); if ($this->qtypeobj->supports_dataset_item_generation()) { $radiogrp = array(); $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]', null, get_string('reuseifpossible', 'qtype_calculated'), 0); $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]', null, get_string('forceregenerationshared', 'qtype_calculated'), 1); $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]', null, get_string('forceregenerationall', 'qtype_calculated'), 2); $mform->addGroup($radiogrp, 'forceregenerationgrp', get_string('nextitemtoadd', 'qtype_calculated'), "<br/>", false); } $mform->addElement('submit', 'getnextbutton', get_string('getnextnow', 'qtype_calculated')); $mform->addElement('static', "dividera", '', '<hr />'); $addgrp = array(); $addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('add', 'moodle')); $addgrp[] =& $mform->createElement('select', "selectadd", get_string('additem', 'qtype_calculated'), $addremoveoptions); $addgrp[] =& $mform->createElement('static', "stat", "Items", get_string('newsetwildcardvalues', 'qtype_calculatedsimple')); $mform->addGroup($addgrp, 'addgrp', get_string('additem', 'qtype_calculated'), ' ', false); $mform->addElement('static', "divideradd", '', ''); if ($this->noofitems > 0) { $mform->addElement('header', 'deleteitemhdr', get_string('delete', 'moodle')); $deletegrp = array(); $deletegrp[] = $mform->createElement('submit', 'deletebutton', get_string('delete', 'moodle')); $deletegrp[] = $mform->createElement('select', 'selectdelete', get_string('deleteitem', 'qtype_calculated') . "1", $addremoveoptions); $deletegrp[] = $mform->createElement('static', "stat", "Items", get_string('setwildcardvalues', 'qtype_calculatedsimple')); $mform->addGroup($deletegrp, 'deletegrp', '', ' ', false); } else { $mform->addElement('static', 'warning', '', '<span class="error">' . get_string('youmustaddatleastoneitem', 'qtype_calculated') . '</span>'); } $addgrp1 = array(); $addgrp1[] = $mform->createElement('submit', 'showbutton', get_string('showitems', 'qtype_calculated')); $addgrp1[] = $mform->createElement('select', "selectshow", '', $showoptions); $addgrp1[] = $mform->createElement('static', "stat", '', get_string('setwildcardvalues', 'qtype_calculated')); $mform->addGroup($addgrp1, 'addgrp1', '', ' ', false); $mform->registerNoSubmitButton('showbutton'); $mform->closeHeaderBefore('addgrp1'); // ...----------------------------------------------------------------------. $j = $this->noofitems * count($this->datasetdefs); $k = optional_param('selectshow', 1, PARAM_INT); for ($i = $this->noofitems; $i >= 1; $i--) { if ($k > 0) { $mform->addElement('header', 'setnoheader' . $i, "<b>" . get_string('setno', 'qtype_calculated', $i) . "</b> "); } foreach ($this->datasetdefs as $defkey => $datasetdef) { if ($k > 0) { if ($datasetdef->category == 0) { $mform->addElement('text', "number[{$j}]", get_string('wildcard', 'qtype_calculated', $datasetdef->name)); } else { $mform->addElement('text', "number[{$j}]", get_string('sharedwildcard', 'qtype_calculated', $datasetdef->name)); } } else { $mform->addElement('hidden', "number[{$j}]", ''); } $mform->setType("number[{$j}]", PARAM_RAW); // This parameter will be validated in validation(). $mform->addElement('hidden', "itemid[{$j}]"); $mform->setType("itemid[{$j}]", PARAM_INT); $mform->addElement('hidden', "definition[{$j}]"); $mform->setType("definition[{$j}]", PARAM_NOTAGS); $data[$datasetdef->name] = $datasetdef->items[$i]->value; $j--; } if ('' != $strquestionlabel && $k > 0) { // ... $this->outsidelimit || !empty($this->numbererrors ). $repeated[] = $mform->addElement('static', "answercomment[{$i}]", $strquestionlabel); // Decode equations in question text. $qtext = $this->qtypeobj->substitute_variables($this->question->questiontext, $data); $textequations = $this->qtypeobj->find_math_equations($qtext); if ($textequations != '' && count($textequations) > 0) { $mform->addElement('static', "divider1[{$j}]", '', 'Formulas {=..} in question text'); foreach ($textequations as $key => $equation) { if ($formulaerrors = qtype_calculated_find_formula_errors($equation)) { $str = $formulaerrors; } else { eval('$str = ' . $equation . ';'); } $equation = shorten_text($equation, 17, true); $mform->addElement('static', "textequation", "{={$equation}}", "=" . $str); } } } $k--; } $mform->addElement('static', 'outsidelimit', '', ''); // Submit buttons. if ($this->noofitems > 0) { $buttonarray = array(); $buttonarray[] = $mform->createElement('submit', 'savechanges', get_string('savechanges')); $previewlink = $PAGE->get_renderer('core_question')->question_preview_link($this->question->id, $this->categorycontext, true); $buttonarray[] = $mform->createElement('static', 'previewlink', '', $previewlink); $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false); $mform->closeHeaderBefore('buttonar'); } $this->add_hidden_fields(); $mform->addElement('hidden', 'category'); $mform->setType('category', PARAM_SEQUENCE); $mform->addElement('hidden', 'wizard', 'datasetitems'); $mform->setType('wizard', PARAM_ALPHA); }
protected function definition() { $labelsharedwildcard = get_string("sharedwildcard", "qtype_calculated"); $mform =& $this->_form; $strquestionlabel = $this->qtypeobj->comment_header($this->question); if ($this->maxnumber != -1 ) { $this->noofitems = $this->maxnumber; } else { $this->noofitems = 0; } $label = get_string("sharedwildcards", "qtype_calculated"); $html2 = $this->qtypeobj->print_dataset_definitions_category_shared( $this->question, $this->datasetdefs); $mform->addElement('static', 'listcategory', $label, $html2); //---------------------------------------------------------------------- $mform->addElement('submit', 'updatedatasets', get_string('updatedatasetparam', 'qtype_calculated')); $mform->registerNoSubmitButton('updatedatasets'); $mform->addElement('header', 'additemhdr', get_string('itemtoadd', 'qtype_calculated')); $idx = 1; $data = array(); $j = (($this->noofitems) * count($this->datasetdefs))+1; foreach ($this->datasetdefs as $defkey => $datasetdef) { if ($datasetdef->category |= 0 ) { $name = get_string('sharedwildcard', 'qtype_calculated', $datasetdef->name); } else { $name = get_string('wildcard', 'qtype_calculated', $datasetdef->name); } $mform->addElement('text', "number[$j]", $name); $mform->setType("number[$j]", PARAM_NUMBER); $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j); $idx++; $mform->addElement('hidden', "definition[$j]"); $mform->setType("definition[$j]", PARAM_RAW); $mform->addElement('hidden', "itemid[$j]"); $mform->setType("itemid[$j]", PARAM_RAW); $mform->addElement('static', "divider[$j]", '', '<hr />'); $mform->setType("divider[$j]", PARAM_RAW); $j++; } $mform->addElement('header', 'updateanswershdr', get_string('answerstoleranceparam', 'qtype_calculated')); $mform->addElement('submit', 'updateanswers', get_string('updatetolerancesparam', 'qtype_calculated')); $mform->setAdvanced('updateanswers', true); $mform->registerNoSubmitButton('updateanswers'); $answers = fullclone($this->question->options->answers); $key1 =1; foreach ($answers as $key => $answer) { if ('' === $answer->answer) { // Do nothing. } else if ('*' === $answer->answer) { $mform->addElement('static', 'answercomment[' . ($this->noofitems+$key1) . ']', $answer->answer); $mform->addElement('hidden', 'tolerance['.$key.']', ''); $mform->setType('tolerance['.$key.']', PARAM_RAW); $mform->setAdvanced('tolerance['.$key.']', true); $mform->addElement('hidden', 'tolerancetype['.$key.']', ''); $mform->setType('tolerancetype['.$key.']', PARAM_RAW); $mform->setAdvanced('tolerancetype['.$key.']', true); $mform->addElement('hidden', 'correctanswerlength['.$key.']', ''); $mform->setType('correctanswerlength['.$key.']', PARAM_RAW); $mform->setAdvanced('correctanswerlength['.$key.']', true); $mform->addElement('hidden', 'correctanswerformat['.$key.']', ''); $mform->setType('correctanswerformat['.$key.']', PARAM_RAW); $mform->setAdvanced('correctanswerformat['.$key.']', true); } else { $mform->addElement('static', 'answercomment[' . ($this->noofitems+$key1) . ']', $answer->answer); $mform->addElement('text', 'tolerance['.$key.']', get_string('tolerance', 'qtype_calculated')); $mform->setAdvanced('tolerance['.$key.']', true); $mform->addElement('select', 'tolerancetype['.$key.']', get_string('tolerancetype', 'qtype_numerical'), $this->qtypeobj->tolerance_types()); $mform->setAdvanced('tolerancetype['.$key.']', true); $mform->addElement('select', 'correctanswerlength['.$key.']', get_string('correctanswershows', 'qtype_calculated'), range(0, 9)); $mform->setAdvanced('correctanswerlength['.$key.']', true); $answerlengthformats = array( '1' => get_string('decimalformat', 'qtype_numerical'), '2' => get_string('significantfiguresformat', 'qtype_calculated') ); $mform->addElement('select', 'correctanswerformat['.$key.']', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats); $mform->setAdvanced('correctanswerformat['.$key.']', true); $mform->addElement('static', 'dividertolerance', '', '<hr />'); $mform->setAdvanced('dividertolerance', true); } $key1++; } $addremoveoptions = array(); $addremoveoptions['1']='1'; for ($i=10; $i<=100; $i+=10) { $addremoveoptions["$i"]="$i"; } $showoptions = Array(); $showoptions['1']='1'; $showoptions['2']='2'; $showoptions['5']='5'; for ($i=10; $i<=100; $i+=10) { $showoptions["$i"]="$i"; } $mform->addElement('header', 'additemhdr', get_string('add', 'moodle')); $mform->closeHeaderBefore('additemhdr'); if ($this->qtypeobj->supports_dataset_item_generation()) { $radiogrp = array(); $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]', null, get_string('reuseifpossible', 'qtype_calculated'), 0); $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]', null, get_string('forceregenerationshared', 'qtype_calculated'), 1); $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]', null, get_string('forceregenerationall', 'qtype_calculated'), 2); $mform->addGroup($radiogrp, 'forceregenerationgrp', get_string('nextitemtoadd', 'qtype_calculated'), "<br/>", false); } $mform->addElement('submit', 'getnextbutton', get_string('getnextnow', 'qtype_calculated')); $mform->addElement('static', "dividera", '', '<hr />'); $addgrp = array(); $addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('add', 'moodle')); $addgrp[] =& $mform->createElement('select', "selectadd", get_string('additem', 'qtype_calculated'), $addremoveoptions); $addgrp[] = & $mform->createElement('static', "stat", "Items", get_string('newsetwildcardvalues', 'qtype_calculatedsimple')); $mform->addGroup($addgrp, 'addgrp', get_string('additem', 'qtype_calculated'), ' ', false); $mform->addElement('static', "divideradd", '', ''); if ($this->noofitems > 0) { $mform->addElement('header', 'additemhdr', get_string('delete', 'moodle')); $deletegrp = array(); $deletegrp[] = $mform->createElement('submit', 'deletebutton', get_string('delete', 'moodle')); $deletegrp[] = $mform->createElement('select', 'selectdelete', get_string('deleteitem', 'qtype_calculated')."1", $addremoveoptions); $deletegrp[] = $mform->createElement('static', "stat", "Items", get_string('setwildcardvalues', 'qtype_calculatedsimple')); $mform->addGroup($deletegrp, 'deletegrp', '', ' ', false); } else { $mform->addElement('static', 'warning', '', '<span class="error">' . get_string('youmustaddatleastoneitem', 'qtype_calculated').'</span>'); } $addgrp1 = array(); $addgrp1[] = $mform->createElement('submit', 'showbutton', get_string('showitems', 'qtype_calculated')); $addgrp1[] = $mform->createElement('select', "selectshow", '' , $showoptions); $addgrp1[] = $mform->createElement('static', "stat", '', get_string('setwildcardvalues', 'qtype_calculated')); $mform->addGroup($addgrp1, 'addgrp1', '', ' ', false); $mform->registerNoSubmitButton('showbutton'); $mform->closeHeaderBefore('addgrp1'); //---------------------------------------------------------------------- $j = $this->noofitems * count($this->datasetdefs); $k = 1; if ("" != optional_param('selectshow', '', PARAM_INT)) { $k = optional_param('selectshow', '', PARAM_INT); } for ($i = $this->noofitems; $i >= 1; $i--) { if ($k > 0) { $mform->addElement('header', '', "<b>" . get_string('setno', 'qtype_calculated', $i)."</b> "); } foreach ($this->datasetdefs as $defkey => $datasetdef) { if ($k > 0) { if ($datasetdef->category == 0 ) { $mform->addElement('text', "number[$j]", get_string('wildcard', 'qtype_calculated', $datasetdef->name)); } else { $mform->addElement('text', "number[$j]", get_string( 'sharedwildcard', 'qtype_calculated', $datasetdef->name)); } } else { $mform->addElement('hidden', "number[$j]" , ''); } $mform->setType("number[$j]", PARAM_NUMBER); $mform->addElement('hidden', "itemid[$j]"); $mform->setType("itemid[$j]", PARAM_INT); $mform->addElement('hidden', "definition[$j]"); $mform->setType("definition[$j]", PARAM_NOTAGS); $data[$datasetdef->name] =$datasetdef->items[$i]->value; $j--; } if ('' != $strquestionlabel && ($k > 0 )) { //|| $this->outsidelimit || !empty($this->numbererrors ) $repeated[] = $mform->addElement('static', "answercomment[$i]", $strquestionlabel); // decode equations in question text $qtext = $this->qtypeobj->substitute_variables( $this->question->questiontext, $data); $textequations = $this->qtypeobj->find_math_equations($qtext); if ($textequations != '' && count($textequations) > 0 ) { $mform->addElement('static', "divider1[$j]", '', 'Formulas {=..} in question text'); foreach ($textequations as $key => $equation) { if ($formulaerrors = qtype_calculated_find_formula_errors($equation)) { $str=$formulaerrors; } else { eval('$str = '.$equation.';'); } $mform->addElement('static', "textequation", "{=$equation}", "=".$str); } } } $k--; } $mform->addElement('static', 'outsidelimit', '', ''); //---------------------------------------------------------------------- // Non standard name for button element needed so not using add_action_buttons if (!($this->noofitems==0) ) { $mform->addElement('submit', 'savechanges', get_string('savechanges')); $mform->closeHeaderBefore('savechanges'); } //hidden elements $mform->addElement('hidden', 'id'); $mform->setType('id', PARAM_INT); $mform->addElement('hidden', 'courseid'); $mform->setType('courseid', PARAM_INT); $mform->setDefault('courseid', 0); $mform->addElement('hidden', 'category'); $mform->setType('category', PARAM_RAW); $mform->setDefault('category', array('contexts' => array($this->categorycontext))); $mform->addElement('hidden', 'cmid'); $mform->setType('cmid', PARAM_INT); $mform->setDefault('cmid', 0); $mform->addElement('hidden', 'wizard', 'datasetitems'); $mform->setType('wizard', PARAM_ALPHA); $mform->addElement('hidden', 'returnurl'); $mform->setType('returnurl', PARAM_LOCALURL); $mform->setDefault('returnurl', 0); }
/** * Evaluate an expression using the variable values. * @param string $expression the expression. A PHP expression with placeholders * like {a} for where the variables need to go. * @return float the computed result. */ public function calculate($expression) { // Make sure no malicious code is present in the expression. Refer MDL-46148 for details. if ($error = qtype_calculated_find_formula_errors($expression)) { throw new moodle_exception('illegalformulasyntax', 'qtype_calculated', '', $error); } return $this->calculate_raw($this->substitute_values_for_eval($expression)); }
function validation($data) { $errors = array(); //verifying for errors in {=...} in question text; $qtext = ""; $qtextremaining = $data['questiontext']; $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']); foreach ($possibledatasets as $name => $value) { $qtextremaining = str_replace('{' . $name . '}', '1', $qtextremaining); } // echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets); while (ereg('\\{=([^[:space:]}]*)}', $qtextremaining, $regs1)) { $qtextsplits = explode($regs1[0], $qtextremaining, 2); $qtext = $qtext . $qtextsplits[0]; $qtextremaining = $qtextsplits[1]; if (!empty($regs1[1]) && ($formulaerrors = qtype_calculated_find_formula_errors($regs1[1]))) { if (!isset($errors['questiontext'])) { $errors['questiontext'] = $formulaerrors . ':' . $regs1[1]; } else { $errors['questiontext'] .= '<br/>' . $formulaerrors . ':' . $regs1[1]; } } } $answers = $data['answers']; $answercount = 0; $maxgrade = false; $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']); $mandatorydatasets = array(); foreach ($answers as $key => $answer) { $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer); } if (count($mandatorydatasets) == 0) { // $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent'); foreach ($answers as $key => $answer) { $errors['answers[' . $key . ']'] = get_string('atleastonewildcard', 'qtype_datasetdependent'); } } foreach ($answers as $key => $answer) { //check no of choices // the * for everykind of answer not actually implemented $trimmedanswer = trim($answer); if ($trimmedanswer != '' || $answercount == 0) { $eqerror = qtype_calculated_find_formula_errors($trimmedanswer); if (FALSE !== $eqerror) { $errors['answers[' . $key . ']'] = $eqerror; } } if ($trimmedanswer != '') { if ('2' == $data['correctanswerformat'][$key] && '0' == $data['correctanswerlength'][$key]) { $errors['correctanswerlength[' . $key . ']'] = get_string('zerosignificantfiguresnotallowed', 'quiz'); } if (!is_numeric($data['tolerance'][$key])) { $errors['tolerance[' . $key . ']'] = get_string('mustbenumeric', 'qtype_calculated'); } if ($data['fraction'][$key] == 1) { $maxgrade = true; } $answercount++; } //check grades //TODO how should grade checking work here?? /*if ($answer != '') { if ($data['fraction'][$key] > 0) { $totalfraction += $data['fraction'][$key]; } if ($data['fraction'][$key] > $maxfraction) { $maxfraction = $data['fraction'][$key]; } }*/ } //grade checking : /// Perform sanity checks on fractional grades /*if ( ) { if ($maxfraction != 1) { $maxfraction = $maxfraction * 100; $errors['fraction[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction); } } else { $totalfraction = round($totalfraction,2); if ($totalfraction != 1) { $totalfraction = $totalfraction * 100; $errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction); } }*/ $units = $data['unit']; if (count($units)) { foreach ($units as $key => $unit) { if (is_numeric($unit)) { $errors['unit[' . $key . ']'] = get_string('mustnotbenumeric', 'qtype_calculated'); } $trimmedunit = trim($unit); $trimmedmultiplier = trim($data['multiplier'][$key]); if (!empty($trimmedunit)) { if (empty($trimmedmultiplier)) { $errors['multiplier[' . $key . ']'] = get_string('youmustenteramultiplierhere', 'qtype_calculated'); } if (!is_numeric($trimmedmultiplier)) { $errors['multiplier[' . $key . ']'] = get_string('mustbenumeric', 'qtype_calculated'); } } } } if ($answercount == 0) { $errors['answers[0]'] = get_string('atleastoneanswer', 'qtype_calculated'); } if ($maxgrade == false) { $errors['fraction[0]'] = get_string('fractionsnomax', 'question'); } return $errors; }
function comment_on_datasetitems($qtypeobj, $questionid, $questiontext, $answers, $data, $number) { //multichoice_ global $DB; $comment = new stdClass(); $comment->stranswers = array(); $comment->outsidelimit = false; $comment->answers = array(); /// Find a default unit: /* if (!empty($questionid) && $unit = $DB->get_record('question_numerical_units', array('question'=> $questionid, 'multiplier' => 1.0))) { $unit = $unit->unit; } else { $unit = ''; }*/ $answers = fullclone($answers); $strmin = get_string('min', 'quiz'); $strmax = get_string('max', 'quiz'); $errors = ''; $delimiter = ': '; foreach ($answers as $key => $answer) { $answer->answer = $this->substitute_variables($answer->answer, $data); //evaluate the equations i.e {=5+4) $qtext = ""; $qtextremaining = $answer->answer; while (preg_match('~\\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) { $qtextsplits = explode($regs1[0], $qtextremaining, 2); $qtext = $qtext . $qtextsplits[0]; $qtextremaining = $qtextsplits[1]; if (empty($regs1[1])) { $str = ''; } else { if ($formulaerrors = qtype_calculated_find_formula_errors($regs1[1])) { $str = $formulaerrors; } else { eval('$str = ' . $regs1[1] . ';'); } } $qtext = $qtext . $str; } $answer->answer = $qtext . $qtextremaining; $comment->stranswers[$key] = $answer->answer; /* $formula = $this->substitute_variables($answer->answer,$data); $formattedanswer = qtype_calculated_calculate_answer( $answer->answer, $data, $answer->tolerance, $answer->tolerancetype, $answer->correctanswerlength, $answer->correctanswerformat, $unit); if ( $formula === '*'){ $answer->min = ' '; $formattedanswer->answer = $answer->answer ; }else { eval('$answer->answer = '.$formula.';') ; $virtualqtype->get_tolerance_interval($answer); } if ($answer->min === '') { // This should mean that something is wrong $comment->stranswers[$key] = " $formattedanswer->answer".'<br/><br/>'; } else if ($formula === '*'){ $comment->stranswers[$key] = $formula.' = '.get_string('anyvalue','qtype_calculated').'<br/><br/><br/>'; }else{ $comment->stranswers[$key]= $formula.' = '.$formattedanswer->answer.'<br/>' ; $comment->stranswers[$key] .= $strmin. $delimiter.$answer->min.'---'; $comment->stranswers[$key] .= $strmax.$delimiter.$answer->max; $comment->stranswers[$key] .='<br/>'; $correcttrue->correct = $formattedanswer->answer ; $correcttrue->true = $answer->answer ; if ($formattedanswer->answer < $answer->min || $formattedanswer->answer > $answer->max){ $comment->outsidelimit = true ; $comment->answers[$key] = $key; $comment->stranswers[$key] .=get_string('trueansweroutsidelimits','qtype_calculated',$correcttrue);//<span class="error">ERROR True answer '..' outside limits</span>'; }else { $comment->stranswers[$key] .=get_string('trueanswerinsidelimits','qtype_calculated',$correcttrue);//' True answer :'.$calculated->trueanswer.' inside limits'; } $comment->stranswers[$key] .=''; }*/ } return fullclone($comment); }