Permalink
Browse files

MDL-29691 Improve numerical format in multianswer

Allow the use of , as decsep in multianswer numerical subquestions
  • Loading branch information...
1 parent a5ec499 commit 1649a4f7ea00c10fd53c036dd614a8e6997df3da @ppichet ppichet committed Jan 18, 2013
Showing with 36 additions and 15 deletions.
  1. +35 −14 question/type/multianswer/edit_multianswer_form.php
  2. +1 −1 question/type/multianswer/renderer.php
@@ -26,6 +26,8 @@
defined('MOODLE_INTERNAL') || die();
+require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');
+
/**
* Form for editing multi-answer questions.
@@ -35,11 +37,11 @@
*/
class qtype_multianswer_edit_form extends question_edit_form {
- // $questiondisplay will contain the qtype_multianswer_extract_question from
- // the questiontext
+ // The variable $questiondisplay will contain the qtype_multianswer_extract_question from
+ // the questiontext.
public $questiondisplay;
- // $savedquestiondisplay will contain the qtype_multianswer_extract_question
- // from the questiontext in database
+ // The variable $savedquestiondisplay will contain the qtype_multianswer_extract_question
+ // from the questiontext in database.
public $savedquestion;
public $savedquestiondisplay;
public $used_in_quiz = false;
@@ -49,6 +51,9 @@ class qtype_multianswer_edit_form extends question_edit_form {
public $nb_of_attempts = 0;
public $confirm = 0;
public $reload = false;
+ /** @var qtype_numerical_answer_processor used when validating numerical answers. */
+ protected $ap = null;
+
public function __construct($submiturl, $question, $category, $contexts, $formeditable = true) {
global $SESSION, $CFG, $DB;
@@ -86,14 +91,14 @@ protected function definition_inner($mform) {
// Make questiontext a required field for this question type.
$mform->addRule('questiontext', null, 'required', null, 'client');
- // display the questions from questiontext;
+ // Display the questions from questiontext.
if ($questiontext = optional_param_array('questiontext', false, PARAM_RAW)) {
$this->questiondisplay = fullclone(qtype_multianswer_extract_question($questiontext));
} else {
if (!$this->reload && !empty($this->savedquestiondisplay->id)) {
- // use database data as this is first pass
- // question->id == 0 so no stored datasets
+ // Use database data as this is first pass
+ // question->id == 0 so no stored datasets.
$this->questiondisplay = fullclone($this->savedquestiondisplay);
foreach ($this->questiondisplay->options->questions as $subquestion) {
if (!empty($subquestion)) {
@@ -261,7 +266,7 @@ public function set_data($question) {
foreach ($question->options->questions as $key => $wrapped) {
if (!empty($wrapped)) {
// The old way of restoring the definitions is kept to gradually
- // update all multianswer questions
+ // update all multianswer questions.
if (empty($wrapped->questiontext)) {
$parsableanswerdef = '{' . $wrapped->defaultmark . ':';
switch ($wrapped->qtype) {
@@ -288,7 +293,7 @@ public function set_data($question) {
$parsableanswerdef .= $subanswer->answer;
}
if (!empty($wrapped->options->tolerance)) {
- // Special for numerical answers:
+ // Special for numerical answers.
$parsableanswerdef .= ":{$wrapped->options->tolerance}";
// We only want tolerance for the first alternative, it will
// be applied to all of the alternatives.
@@ -300,7 +305,7 @@ public function set_data($question) {
$separator = '~';
}
$parsableanswerdef .= '}';
- // Fix the questiontext fields of old questions
+ // Fix the questiontext fields of old questions.
$DB->set_field('question', 'questiontext', $parsableanswerdef,
array('id' => $wrapped->id));
} else {
@@ -312,7 +317,7 @@ public function set_data($question) {
}
}
- // set default to $questiondisplay questions elements
+ // Set default to $questiondisplay questions elements.
if ($this->reload) {
if (isset($this->questiondisplay->options->questions)) {
$subquestions = fullclone($this->questiondisplay->options->questions);
@@ -321,7 +326,7 @@ public function set_data($question) {
foreach ($subquestions as $subquestion) {
$prefix = 'sub_'.$sub.'_';
- // validate parameters
+ // Validate parameters.
$answercount = 0;
$maxgrade = false;
$maxfraction = -1;
@@ -370,7 +375,7 @@ public function set_data($question) {
if ($trimmedanswer !== '') {
$answercount++;
if ($subquestion->qtype == 'numerical' &&
- !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
+ !($this->is_valid_number($trimmedanswer) || $trimmedanswer == '*')) {
$this->_form->setElementError($prefix.'answer['.$key.']',
get_string('answermustbenumberorstar',
'qtype_numerical'));
@@ -423,6 +428,22 @@ public function set_data($question) {
parent::set_data($question);
}
+ /**
+ * Validate that a string is a nubmer formatted correctly for the current locale.
+ * @param string $x a string
+ * @return bool whether $x is a number that the numerical question type can interpret.
+ */
+ protected function is_valid_number($x) {
+ if (is_null($this->ap)) {
+ $this->ap = new qtype_numerical_answer_processor(array());
+ }
+
+ list($value, $unit) = $this->ap->apply_units($x);
+
+ return !is_null($value) && !$unit;
+ }
+
+
public function validation($data, $files) {
$errors = parent::validation($data, $files);
@@ -451,7 +472,7 @@ public function validation($data, $files) {
if ($trimmedanswer !== '') {
$answercount++;
if ($subquestion->qtype == 'numerical' &&
- !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
+ !($this->is_valid_number($trimmedanswer) || $trimmedanswer == '*')) {
$errors[$prefix.'answer['.$key.']'] =
get_string('answermustbenumberorstar', 'qtype_numerical');
}
@@ -194,7 +194,7 @@ public function subquestion(question_attempt $qa, question_display_options $opti
$size = max($size, strlen(trim($ans->answer)));
}
$size = min(60, round($size + rand(0, $size*0.15)));
- // The rand bit is to make guessing harder
+ // The rand bit is to make guessing harder.
$inputattributes = array(
'type' => 'text',

0 comments on commit 1649a4f

Please sign in to comment.