MDL-27410 qtype_calculated fix basic question editing and preview.

At least, after these changes, I was able to create a calculated question through the Moodle UI and then preview it. I am sure more testing and fixing is needed to make sure everything works.
This commit is contained in:
Tim Hunt
2011-05-18 21:15:25 +01:00
parent 1da4060f65
commit 18f9b2d2cf
8 changed files with 129 additions and 337 deletions
@@ -56,7 +56,7 @@ class question_dataset_dependent_definitions_form extends moodleform {
public function __construct($submiturl, $question) {
global $DB;
$this->question = $question;
$this->qtypeobj = $QTYPES[$this->question->qtype];
$this->qtypeobj = question_bank::get_qtype($this->question->qtype);
// Validate the question category.
if (!$category = $DB->get_record('question_categories',
array('id' => $question->category))) {
@@ -70,7 +70,7 @@ class question_dataset_dependent_items_form extends moodleform {
global $SESSION, $CFG, $DB;
$this->regenerate = $regenerate;
$this->question = $question;
$this->qtypeobj =& $QTYPES[$this->question->qtype];
$this->qtypeobj = question_bank::get_qtype($this->question->qtype);
// Validate the question category.
if (!$category = $DB->get_record('question_categories',
array('id' => $question->category))) {
@@ -192,7 +192,7 @@ class question_dataset_dependent_items_form extends moodleform {
$answerlengthformats = array(
'1' => get_string('decimalformat', 'qtype_numerical'),
'2' => get_string('significantfiguresformat', 'quiz')
'2' => get_string('significantfiguresformat', 'qtype_calculated')
);
$mform->addElement('select', 'correctanswerformat['.$key.']',
get_string('correctanswershowsformat', 'qtype_calculated'),
@@ -26,6 +26,8 @@
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/question/type/numerical/edit_numerical_form.php');
/**
* Calculated question type editing form definition.
@@ -33,7 +35,7 @@ defined('MOODLE_INTERNAL') || die();
* @copyright 2007 Jamie Pratt [email protected]
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class qtype_calculated_edit_form extends question_edit_form {
class qtype_calculated_edit_form extends qtype_numerical_edit_form {
/**
* Handle to the question type for this question.
*
@@ -50,7 +52,6 @@ class qtype_calculated_edit_form extends question_edit_form {
$formeditable = true) {
global $CFG, $DB;
$this->question = $question;
$this->qtypeobj = $QTYPES[$this->question->qtype];
if ('1' == optional_param('reload', '', PARAM_INT)) {
$this->reload = true;
} else {
@@ -101,7 +102,7 @@ class qtype_calculated_edit_form extends question_edit_form {
$answerlengthformats = array(
'1' => get_string('decimalformat', 'qtype_numerical'),
'2' => get_string('significantfiguresformat', 'quiz')
'2' => get_string('significantfiguresformat', 'qtype_calculated')
);
$addrepeated[] = $mform->createElement('select', 'correctanswerformat',
get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
@@ -115,8 +116,8 @@ class qtype_calculated_edit_form extends question_edit_form {
*
* @param MoodleQuickForm $mform the form being built.
*/
protected function definition_inner(&$mform) {
$this->qtypeobj = $QTYPES[$this->qtype()];
protected function definition_inner($mform) {
$this->qtypeobj = question_bank::get_qtype($this->qtype());
$label = get_string('sharedwildcards', 'qtype_calculated');
$mform->addElement('hidden', 'initialcategory', 1);
$mform->addElement('hidden', 'reload', 1);
@@ -152,8 +153,8 @@ class qtype_calculated_edit_form extends question_edit_form {
$repeated = array();
$QTYPES['numerical']->add_units_options($mform, $this);
$QTYPES['numerical']->add_units_elements($mform, $this);
$this->add_unit_options($mform, $this);
$this->add_unit_fields($mform, $this);
//hidden elements
$mform->addElement('hidden', 'synchronize', '');
@@ -163,8 +164,6 @@ class qtype_calculated_edit_form extends question_edit_form {
}
public function data_preprocessing($question) {
global $QTYPES;
$default_values = array();
if (isset($question->options)) {
$answers = $question->options->answers;
@@ -194,8 +193,6 @@ class qtype_calculated_edit_form extends question_edit_form {
}
}
$default_values['synchronize'] = $question->options->synchronize;
// set unit data, prepare files in instruction area
$QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
}
if (isset($question->options->single)) {
$default_values['single'] = $question->options->single;
@@ -225,6 +222,9 @@ class qtype_calculated_edit_form extends question_edit_form {
$this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2;
$question = (object)((array)$question + $default_values);
$question = $this->data_preprocessing_units($question);
$question = $this->data_preprocessing_unit_options($question);
return $question;
}
@@ -234,7 +234,6 @@ class qtype_calculated_edit_form extends question_edit_form {
public function validation($data, $files) {
$errors = parent::validation($data, $files);
// verifying for errors in {=...} in question text;
$qtext = "";
$qtextremaining = $data['questiontext']['text'];
@@ -255,57 +254,46 @@ class qtype_calculated_edit_form extends question_edit_form {
}
}
}
$errors = parent::validation($data, $files);
// Check that the answers use datasets.
$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) {
if (empty($mandatorydatasets)) {
foreach ($answers as $key => $answer) {
$errors['answer['.$key.']'] =
get_string('atleastonewildcard', 'qtype_datasetdependent');
}
}
// regular calculated
// Validate the answer format.
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]) {
if (trim($answer)) {
if ($data['correctanswerformat'][$key] == 2 &&
$data['correctanswerlength'][$key] == '0') {
$errors['correctanswerlength['.$key.']'] =
get_string('zerosignificantfiguresnotallowed', 'qtype_calculated');
}
if (!is_numeric($data['tolerance'][$key])) {
$errors['tolerance['.$key.']'] =
get_string('mustbenumeric', 'qtype_calculated');
}
if ($data['fraction'][$key] == 1) {
$maxgrade = true;
}
$answercount++;
}
}
$QTYPES['numerical']->validate_numerical_options($data, $errors);
if ($answercount == 0) {
$errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
}
if ($maxgrade == false) {
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
}
return $errors;
}
function is_valid_answer($answer, $data) {
return !qtype_calculated_find_formula_errors($answer);
}
function valid_answer_message($answer) {
if (!$answer) {
return get_string('mustenteraformulaorstar', 'qtype_numerical');
} else {
return qtype_calculated_find_formula_errors($answer);
}
}
}
@@ -30,6 +30,7 @@ $string['addmoreunitblanks'] = 'Blanks for {$a} more units';
$string['addsets'] = 'Add set(s)';
$string['answerhdr'] = 'Answer';
$string['answerstoleranceparam'] = 'Answers tolerance parameters';
$string['anyvalue'] = 'Any value';
$string['atleastoneanswer'] = 'You need to provide at least one answer.';
$string['atleastonerealdataset']='There should be at least one real dataset in question text';
$string['atleastonewildcard']='There should be at least one wild card in answer formula or question text';
@@ -43,6 +44,7 @@ $string['calculated_link'] = 'question/type/calculated';
$string['calculatedsummary'] = 'Calculated questions are like numerical questions but with the numbers used selected randomly from a set when the quiz is taken.';
$string['choosedatasetproperties'] = 'Choose wildcards dataset properties';
$string['choosedatasetproperties_help'] = 'A dataset is a set of values inserted in place of a wildcard. You can create a private dataset for a specific question, or a shared dataset that can be used for other calculated questions within the category.';
$string['correctanswerformula'] = 'Correct answer formula';
$string['correctanswershows'] = 'Correct answer shows';
$string['correctanswershowsformat'] = 'Format';
$string['correctfeedback'] = 'For any correct response';
@@ -86,11 +88,14 @@ $string['loguniform'] = 'Loguniform';
$string['loguniformbit'] = 'digits, from a loguniform distribution';
$string['makecopynextpage'] = 'Next page (new question)';
$string['mandatoryhdr'] = 'Mandatory wild cards present in answers';
$string['max'] = 'Max';
$string['min'] = 'Min';
$string['minmax'] = 'Range of Values';
$string['missingformula'] = 'Missing formula';
$string['missingname'] = 'Missing question name';
$string['missingquestiontext'] = 'Missing question text';
$string['mustbenumeric'] = 'You must enter a number here.';
$string['mustenteraformulaorstar'] = 'You must enter a formula or \'*\'.';
$string['mustnotbenumeric'] = 'This can\'t be a number.';
$string['newcategory1'] = 'will use a new shared dataset';
$string['newcategory2'] = 'a file from a new set of files that may also be used by other questions in this category';
+4 -3
View File
@@ -61,7 +61,7 @@ class qtype_calculated_question extends qtype_numerical_question {
public function apply_attempt_state(question_attempt_step $step) {
$values = array();
foreach ($step->get_qt_datavalues() as $name => $value) {
foreach ($step->get_qt_data() as $name => $value) {
if (substr($name, 0, 5) === '_var_') {
$values[substr($name, 5)] = $value;
}
@@ -81,7 +81,6 @@ class qtype_calculated_question extends qtype_numerical_question {
protected function calculate_all_expressions() {
$this->questiontext = $this->vs->replace_expressions_in_text($this->questiontext);
$this->generalfeedback = $this->vs->replace_expressions_in_text($this->generalfeedback);
// TODO etc.
foreach ($this->answers as $ans) {
if ($ans->answer && $ans->answer !== '*') {
@@ -142,7 +141,9 @@ class qtype_calculated_dataset_loader {
* @return array name => value;
*/
protected function load_values($itemnumber) {
return $DB->get_records_sql('
global $DB;
return $DB->get_records_sql_menu('
SELECT qdd.name, qdi.value
FROM {question_dataset_items} qdi
JOIN {question_dataset_definitions} qdd ON qdd.id = qdi.definition
+40 -273
View File
@@ -26,6 +26,8 @@
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/question/type/numerical/question.php');
/**
* The calculated question type.
@@ -44,7 +46,6 @@ class qtype_calculated extends question_type {
// Used by the function custom_generator_tools:
public $calcgenerateidhasbeenadded = false;
public $virtualqtype = false;
public $wizardpagesnumber = 3;
public function requires_qtypes() {
@@ -79,9 +80,9 @@ class qtype_calculated extends question_type {
return false;
}
if ($this->get_virtual_qtype() == $QTYPES['numerical']) {
$QTYPES['numerical']->get_numerical_units($question);
$QTYPES['numerical']->get_numerical_options($question);
if ($this->get_virtual_qtype()->name() == 'numerical') {
$this->get_virtual_qtype()->get_numerical_units($question);
$this->get_virtual_qtype()->get_numerical_options($question);
}
if (isset($question->export_process)&&$question->export_process) {
@@ -180,12 +181,14 @@ class qtype_calculated extends question_type {
// Save the units.
$virtualqtype = $this->get_virtual_qtype();
$result = $virtualqtype->save_numerical_units($question);
$result = $virtualqtype->save_units($question);
if (isset($result->error)) {
return $result;
} else {
$units = &$result->units;
$units = $result->units;
}
// Insert all the new answers
if (isset($question->answer) && !isset($question->answers)) {
$question->answers = $question->answer;
@@ -262,7 +265,7 @@ class qtype_calculated extends question_type {
}
}
$result = $QTYPES['numerical']->save_numerical_options($question);
$result = $virtualqtype->save_unit_options($question);
if (isset($result->error)) {
return $result;
}
@@ -333,26 +336,23 @@ class qtype_calculated extends question_type {
}
}
public function restore_session_and_responses(&$question, &$state) {
global $OUTPUT;
if (!preg_match('~^dataset([0-9]+)[^-]*-(.*)$~',
$state->responses[''], $regs)) {
echo $OUTPUT->notification("Wrongly formatted raw response answer " .
"{$state->responses['']}! Could not restore session for " .
" question #{$question->id}.");
$state->options->datasetitem = 1;
$state->options->dataset = array();
$state->responses = array('' => '');
return false;
protected function initialise_question_instance(question_definition $question, $questiondata) {
parent::initialise_question_instance($question, $questiondata);
question_bank::get_qtype('numerical')->initialise_numerical_answers(
$question, $questiondata);
foreach ($questiondata->options->answers as $a) {
$question->answers[$a->id]->tolerancetype = $a->tolerancetype;
}
// Restore the chosen dataset
$state->options->datasetitem = $regs[1];
$state->options->dataset =
$this->pick_question_dataset($question, $state->options->datasetitem);
$state->responses = array('' => $regs[2]);
$virtualqtype = $this->get_virtual_qtype();
return $virtualqtype->restore_session_and_responses($question, $state);
$question->unitdisplay = $questiondata->options->showunits;
$question->unitgradingtype = $questiondata->options->unitgradingtype;
$question->unitpenalty = $questiondata->options->unitpenalty;
$question->ap = question_bank::get_qtype(
'numerical')->make_answer_processor(
$questiondata->options->units, $questiondata->options->unitsleft);
$question->datasetloader = new qtype_calculated_dataset_loader($questiondata->id);
}
public function create_session_and_responses(&$question, &$state, $cmoptions, $attempt) {
@@ -416,43 +416,6 @@ class qtype_calculated extends question_type {
return $virtualqtype->create_session_and_responses($question, $state, $cmoptions, $attempt);
}
public function save_session_and_responses(&$question, &$state) {
global $DB;
$responses = 'dataset'.$state->options->datasetitem.'-';
// regular numeric type
if (isset($state->responses['unit']) &&
isset($question->options->units[$state->responses['unit']])) {
$responses .= $state->responses['answer'] . '|||||' .
$question->options->units[$state->responses['unit']]->unit;
} else if (isset($state->responses['unit'])) {
$responses .= $state->responses['answer'] . '|||||' .
$state->responses['unit'];
} else {
$responses .= $state->responses['answer'] . '|||||';
}
// Set the legacy answer field
$DB->set_field('question_states', 'answer', $responses, array('id' => $state->id));
return true;
}
public function create_runtime_question($question, $form) {
$question = parent::create_runtime_question($question, $form);
$question->options->answers = array();
foreach ($form->answers as $key => $answer) {
$a->answer = trim($form->answer[$key]);
$a->fraction = $form->fraction[$key];//new
$a->tolerance = $form->tolerance[$key];
$a->tolerancetype = $form->tolerancetype[$key];
$a->correctanswerlength = $form->correctanswerlength[$key];
$a->correctanswerformat = $form->correctanswerformat[$key];
$question->options->answers[] = clone($a);
}
return $question;
}
public function validate_form($form) {
switch($form->wizardpage) {
case 'question':
@@ -798,70 +761,6 @@ class qtype_calculated extends question_type {
parent::delete_question($questionid, $contextid);
}
public function test_response(&$question, &$state, $answer) {
$virtualqtype = $this->get_virtual_qtype();
return $virtualqtype->test_response($question, $state, $answer);
}
public function compare_responses(&$question, $state, $teststate) {
$virtualqtype = $this->get_virtual_qtype();
return $virtualqtype->compare_responses($question, $state, $teststate);
}
public function convert_answers (&$question, &$state) {
foreach ($question->options->answers as $key => $answer) {
$answer = fullclone($question->options->answers[$key]);
$question->options->answers[$key]->answer =
$this->substitute_variables_and_eval($answer->answer,
$state->options->dataset);
}
}
public function convert_questiontext (&$question, &$state) {
$tolerancemax = 0.01;
$tolerancetypemax = 1;
$correctanswerlengthmax = 2;
$correctanswerformatmax = 1;
$tolerancemaxset = false;
foreach ($question->options->answers as $key => $answer) {
if ($answer->fraction == 1.0 && !$tolerancemaxset) {
$tolerancemax = $answer->tolerance;
$tolerancetypemax = $answer->tolerancetype;
$correctanswerlengthmax = $answer->correctanswerlength;
$correctanswerformatmax = $answer->correctanswerformat;
$tolerancemaxset = true;
}
}
$question->questiontext = $this->substitute_variables($question->questiontext,
$state->options->dataset);
//evaluate the equations i.e {=5+4)
$qtext = '';
$qtextremaining = $question->questiontext;
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].';');
$texteval= qtype_calculated_calculate_answer(
$str, $state->options->dataset, $tolerancemax,
$tolerancetypemax, $correctanswerlengthmax,
$correctanswerformatmax, '');
$str = $texteval->answer;
}
}
$qtext = $qtext.$str;
}
$question->questiontext = $qtext.$qtextremaining; // end replace equations
}
public function get_default_numerical_unit($question, $virtualqtype) {
if ($unit = $virtualqtype->get_default_numerical_unit($question)) {
$unit = $unit->unit;
@@ -871,84 +770,6 @@ class qtype_calculated extends question_type {
return $unit;
}
public function print_question_formulation_and_controls($question, $state,
$cmoptions, $options) {
// Substitute variables in questiontext before giving the data to the
// virtual type for printing
$virtualqtype = $this->get_virtual_qtype();
// why $unit as it is not use
$unit = $this->get_default_numerical_unit($question, $virtualqtype);
// We modify the question to look like a numerical question
$numericalquestion = fullclone($question);
$this->convert_answers($numericalquestion, $state);
$this->convert_questiontext($numericalquestion, $state);
$virtualqtype->print_question_formulation_and_controls(
$numericalquestion, $state, $cmoptions, $options);
}
public function grade_responses(&$question, &$state, $cmoptions) {
// Forward the grading to the virtual qtype
// We modify the question to look like a numerical question
$numericalquestion = fullclone($question);
foreach ($numericalquestion->options->answers as $key => $answer) {
$answer = $numericalquestion->options->answers[$key]->answer;
$numericalquestion->options->answers[$key]->answer =
$this->substitute_variables_and_eval($answer, $state->options->dataset);
}
$virtualqtype = $this->get_virtual_qtype();
return $virtualqtype->grade_responses($numericalquestion, $state, $cmoptions);
}
// ULPGC ecastro
public function check_response(&$question, &$state) {
// Forward the checking to the virtual qtype
// We modify the question to look like a numerical question
$numericalquestion = clone($question);
$numericalquestion->options = clone($question->options);
foreach ($question->options->answers as $key => $answer) {
$numericalquestion->options->answers[$key] = clone($answer);
}
foreach ($numericalquestion->options->answers as $key => $answer) {
$answer->answer = $this->substitute_variables_and_eval($answer->answer,
$state->options->dataset);
}
$virtualqtype = $this->get_virtual_qtype();
return $virtualqtype->check_response($numericalquestion, $state);
}
// ULPGC ecastro
public function get_actual_response(&$question, &$state) {
// Substitute variables in questiontext before giving the data to the
// virtual type
$virtualqtype = $this->get_virtual_qtype();
$unit = $virtualqtype->get_default_numerical_unit($question);
// We modify the question to look like a numerical question
$numericalquestion = clone($question);
$numericalquestion->options = clone($question->options);
foreach ($question->options->answers as $key => $answer) {
$numericalquestion->options->answers[$key] = clone($answer);
}
foreach ($numericalquestion->options->answers as $key => $answer) {
$answer = &$numericalquestion->options->answers[$key]; // for PHP 4.x
$answer->answer = $this->substitute_variables_and_eval($answer->answer,
$state->options->dataset);
// apply_unit
}
$numericalquestion->questiontext = $this->substitute_variables_and_eval(
$numericalquestion->questiontext, $state->options->dataset);
$responses = $virtualqtype->get_all_responses($numericalquestion, $state);
$response = reset($responses->responses);
$correct = $response->answer.' : ';
$responses = $virtualqtype->get_actual_response($numericalquestion, $state);
foreach ($responses as $key => $response) {
$responses[$key] = $correct.$response;
}
return $responses;
}
public function create_virtual_qtype() {
global $CFG;
@@ -960,7 +781,8 @@ class qtype_calculated extends question_type {
// Calcualted support generation of randomly distributed number data
return true;
}
public function custom_generator_tools_part(&$mform, $idx, $j) {
public function custom_generator_tools_part($mform, $idx, $j) {
$minmaxgrp = array();
$minmaxgrp[] = $mform->createElement('text', "calcmin[$idx]",
@@ -1314,8 +1136,6 @@ class qtype_calculated extends question_type {
}
$answers = fullclone($answers);
$strmin = get_string('min');
$strmax = get_string('max');
$errors = '';
$delimiter = ': ';
$virtualqtype = $qtypeobj->get_virtual_qtype();
@@ -1329,8 +1149,10 @@ class qtype_calculated extends question_type {
$answer->min = ' ';
$formattedanswer->answer = $answer->answer;
} else {
eval('$answer->answer = '.$formula.';');
$virtualqtype->get_tolerance_interval($answer);
eval('$ansvalue = '.$formula.';');
$ans = new qtype_numerical_answer(0, $ansvalue, 0, '', 0, $answer->tolerance);
$ans->tolerancetype = $answer->tolerancetype;
list($answer->min, $answer->max) = $ans->get_tolerance_interval($answer);
}
if ($answer->min === '') {
// This should mean that something is wrong
@@ -1353,8 +1175,10 @@ class qtype_calculated extends question_type {
get_string('trueanswerinsidelimits', 'qtype_calculated', $correcttrue);
}
$comment->stranswers[$key] .= '<br/>';
$comment->stranswers[$key] .= $strmin . $delimiter . $answer->min . ' --- ';
$comment->stranswers[$key] .= $strmax . $delimiter . $answer->max;
$comment->stranswers[$key] .= get_string('min', 'qtype_calculated') .
$delimiter . $answer->min . ' --- ';
$comment->stranswers[$key] .= get_string('max', 'qtype_calculated') .
$delimiter . $answer->max;
}
}
return fullclone($comment);
@@ -1375,8 +1199,6 @@ class qtype_calculated extends question_type {
}
$answers = fullclone($answers);
$strmin = get_string('min');
$strmax = get_string('max');
$errors = '';
$delimiter = ': ';
foreach ($answers as $key => $answer) {
@@ -1469,20 +1291,6 @@ class qtype_calculated extends question_type {
return $datasetmenus;
}
public function print_question_grading_details($question, $state, $cmoptions, $options) {
$virtualqtype = $this->get_virtual_qtype();
$virtualqtype->print_question_grading_details($question, $state, $cmoptions, $options);
}
public function get_correct_responses($question, $state) {
// virtual type for printing
$virtualqtype = $this->get_virtual_qtype();
$unit = $this->get_default_numerical_unit($question, $virtualqtype);
// We modify the question to look like a numerical question
$this->convert_answers($question, $state);
return $virtualqtype->get_correct_responses($question, $state);
}
public function substitute_variables($str, $dataset) {
global $OUTPUT;
// testing for wrong numerical values
@@ -1883,14 +1691,12 @@ class qtype_calculated extends question_type {
$datasetdefs = array();
$lnamemax = 22;
$namestr = get_string('name');
$minstr = get_string('min');
$maxstr = get_string('max');
$rangeofvaluestr = get_string('minmax', 'qtype_calculated');
$questionusingstr = get_string('usedinquestion', 'qtype_calculated');
$itemscountstr = get_string('itemscount', 'qtype_calculated');
$text = '';
if (!empty($form->category)) {
list($category) = explode(', ', $form->category);
list($category) = explode(',', $form->category);
$sql = "SELECT i.*, d.*
FROM {question_datasets} d,
{question_dataset_definitions} i
@@ -1962,8 +1768,6 @@ class qtype_calculated extends question_type {
$datasetdefs = array();
$lnamemax = 22;
$namestr = get_string('name', 'quiz');
$minstr = get_string('min', 'quiz');
$maxstr = get_string('max', 'quiz');
$rangeofvaluestr = get_string('minmax', 'qtype_calculated');
$questionusingstr = get_string('usedinquestion', 'qtype_calculated');
$itemscountstr = get_string('itemscount', 'qtype_calculated');
@@ -2072,8 +1876,7 @@ class qtype_calculated extends question_type {
}
public function get_virtual_qtype() {
$this->virtualqtype = $QTYPES['numerical'];
return $this->virtualqtype;
return question_bank::get_qtype('numerical');
}
/**
@@ -2124,14 +1927,11 @@ class qtype_calculated extends question_type {
return $newquestion;
}
public function move_files($questionid, $oldcontextid, $newcontextid) {
function move_files($questionid, $oldcontextid, $newcontextid) {
$fs = get_file_storage();
parent::move_files($questionid, $oldcontextid, $newcontextid);
$this->move_files_in_answers($questionid, $oldcontextid, $newcontextid);
$fs->move_area_files_to_new_context($oldcontextid,
$newcontextid, 'qtype_calculated', 'instruction', $questionid);
}
protected function delete_files($questionid, $contextid) {
@@ -2139,40 +1939,6 @@ class qtype_calculated extends question_type {
parent::delete_files($questionid, $contextid);
$this->delete_files_in_answers($questionid, $contextid);
$fs->delete_area_files($contextid, 'qtype_calculated', 'instruction', $questionid);
}
public function check_file_access($question, $state, $options, $contextid, $component,
$filearea, $args) {
$itemid = reset($args);
if ($component == 'question' && $filearea == 'answerfeedback') {
// check if answer id exists
$result = $options->feedback && array_key_exists($itemid,
$question->options->answers);
if (!$result) {
return false;
}
// check response
if (!$this->check_response($question, $state)) {
return false;
}
return true;
} else if ($filearea == 'instruction') {
// Displayed all the time like the question text. Check if question id exists
if ($itemid != $question->id) {
return false;
} else {
return true;
}
} else if (in_array($filearea, array('correctfeedback', 'partiallycorrectfeedback',
'incorrectfeedback'))) {
// Note: calculated type doesn't display question feedback yet
return false;
} else {
return parent::check_file_access($question, $state, $options, $contextid,
$component, $filearea, $args);
}
}
}
@@ -2185,7 +1951,8 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
// ->max the upper bound for an accetpable response
// Exchange formula variables with the correct values...
$answer = $QTYPES['calculated']->substitute_variables_and_eval($formula, $individualdata);
$answer = question_bank::get_qtype('calculated')->substitute_variables_and_eval(
$formula, $individualdata);
if ('1' == $answerformat) { /* Answer is to have $answerlength decimals */
/*** Adjust to the correct number of decimals ***/
if (stripos($answer, 'e')>0) {
+42 -11
View File
@@ -26,6 +26,8 @@
defined('MOODLE_INTERNAL') || die();
require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');
/**
* numerical editing form definition.
@@ -230,7 +232,18 @@ class qtype_numerical_edit_form extends question_edit_form {
public function validation($data, $files) {
$errors = parent::validation($data, $files);
$errors = $this->validate_answers($data, $errors);
$errors = $this->validate_numerical_options($data, $errors);
return $errors;
}
/**
* Validate the answers.
* @param array $data the submitted data.
* @param array $errors the errors array to add to.
* @return array the updated errors array.
*/
function validate_answers($data, $errors) {
// Check the answers.
$answercount = 0;
$maxgrade = false;
@@ -239,17 +252,19 @@ class qtype_numerical_edit_form extends question_edit_form {
$trimmedanswer = trim($answer);
if ($trimmedanswer != '') {
$answercount++;
if (!(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
$errors['answer[' . $key . ']'] =
get_string('answermustbenumberorstar', 'qtype_numerical');
if (!$this->is_valid_answer($trimmedanswer, $data)) {
$errors['answer[' . $key . ']'] = $this->valid_answer_message();
}
if ($data['fraction'][$key] == 1) {
$maxgrade = true;
}
if (!is_numeric($data['tolerance'][$key])) {
$errors['tolerance['.$key.']'] =
get_string('mustbenumeric', 'qtype_calculated');
}
} else if ($data['fraction'][$key] != 0 ||
!html_is_blank($data['feedback'][$key]['text'])) {
$errors['answer[' . $key . ']'] =
get_string('answermustbenumberorstar', 'qtype_numerical');
$errors['answer[' . $key . ']'] = $this->valid_answer_message();
$answercount++;
}
}
@@ -259,15 +274,31 @@ class qtype_numerical_edit_form extends question_edit_form {
if ($maxgrade == false) {
$errors['fraction[0]'] = get_string('fractionsnomax', 'question');
}
$errors = $this->validate_numerical_options($data, $errors);
return $errors;
}
/**
* Validate the unit options.
*/
* Validate a particular answer.
* @param string $answer an answer to validate. Known to be non-blank and already trimmed.
* @param array $data the submitted data.
* @return bool whether this is a valid answer.
*/
function is_valid_answer($answer, $data) {
return $answer == '*' || is_numeric($answer);
}
/**
* @return string erre describing what an answer should be.
*/
function valid_answer_message($answer) {
return get_string('answermustbenumberorstar', 'qtype_numerical');
}
/**
* Validate the answers.
* @param array $data the submitted data.
* @param array $errors the errors array to add to.
* @return array the updated errors array.
*/
function validate_numerical_options($data, $errors) {
if ($data['unitrole'] != qtype_numerical::UNITNONE && trim($data['unit'][0]) == '') {
$errors['unit[0]'] = get_string('unitonerequired', 'qtype_numerical');
+2 -2
View File
@@ -346,7 +346,7 @@ class qtype_numerical extends question_type {
$questiondata->options->unitsleft);
}
protected function initialise_numerical_answers(question_definition $question, $questiondata) {
public function initialise_numerical_answers(question_definition $question, $questiondata) {
$question->answers = array();
if (empty($questiondata->options->answers)) {
return;
@@ -357,7 +357,7 @@ class qtype_numerical extends question_type {
}
}
protected function make_answer_processor($units, $unitsleft) {
public function make_answer_processor($units, $unitsleft) {
if (empty($units)) {
return new qtype_numerical_answer_processor(array());
}