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;
 }
示例#3
0
 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;
 }
示例#4
0
 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;
 }
示例#8
0
 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;
 }
示例#9
0
    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>&nbsp;&nbsp;");
         }
         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);
 }
示例#12
0
    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>&nbsp;&nbsp;");
            }
            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);
    }
示例#13
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;
 }
示例#15
0
 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);
 }