Merge branch 'MDL-76024-MOODLE_402_STABLE' of https://github.com/opitz/moodle into MOODLE_402_STABLE
This commit is contained in:
@@ -39,17 +39,17 @@ require_once($CFG->dirroot . '/question/type/numerical/question.php');
|
||||
*/
|
||||
class qtype_calculated extends question_type {
|
||||
/**
|
||||
* @const string a placeholder is a letter, followed by almost any characters. (This should probably be restricted more.)
|
||||
* @var string a placeholder is a letter, followed by almost any characters. (This should probably be restricted more.)
|
||||
*/
|
||||
const PLACEHOLDER_REGEX_PART = '[[:alpha:]][^>} <`{"\']*';
|
||||
|
||||
/**
|
||||
* @const string REGEXP for a placeholder, wrapped in its {...} delimiters, with capturing brackets around the name.
|
||||
* @var string REGEXP for a placeholder, wrapped in its {...} delimiters, with capturing brackets around the name.
|
||||
*/
|
||||
const PLACEHODLER_REGEX = '~\{(' . self::PLACEHOLDER_REGEX_PART . ')\}~';
|
||||
|
||||
/**
|
||||
* @const string Regular expression that finds the formulas in content, with capturing brackets to get the forumlas.
|
||||
* @var string Regular expression that finds the formulas in content, with capturing brackets to get the forumlas.
|
||||
*/
|
||||
const FORMULAS_IN_TEXT_REGEX = '~\{=([^{}]*(?:\{' . self::PLACEHOLDER_REGEX_PART . '\}[^{}]*)*)\}~';
|
||||
|
||||
@@ -63,7 +63,7 @@ class qtype_calculated extends question_type {
|
||||
global $CFG, $DB, $OUTPUT;
|
||||
parent::get_question_options($question);
|
||||
if (!$question->options = $DB->get_record('question_calculated_options',
|
||||
array('question' => $question->id))) {
|
||||
['question' => $question->id])) {
|
||||
$question->options = new stdClass();
|
||||
$question->options->synchronize = 0;
|
||||
$question->options->single = 0;
|
||||
@@ -83,7 +83,7 @@ class qtype_calculated extends question_type {
|
||||
{question_calculated} c
|
||||
WHERE a.question = ?
|
||||
AND a.id = c.answer
|
||||
ORDER BY a.id ASC", array($question->id))) {
|
||||
ORDER BY a.id ASC", [$question->id])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -93,7 +93,7 @@ class qtype_calculated extends question_type {
|
||||
}
|
||||
|
||||
$question->hints = $DB->get_records('question_hints',
|
||||
array('questionid' => $question->id), 'id ASC');
|
||||
['questionid' => $question->id], 'id ASC');
|
||||
|
||||
if (isset($question->export_process)&&$question->export_process) {
|
||||
$question->options->datasets = $this->get_datasets_for_export($question);
|
||||
@@ -103,12 +103,12 @@ class qtype_calculated extends question_type {
|
||||
|
||||
public function get_datasets_for_export($question) {
|
||||
global $DB, $CFG;
|
||||
$datasetdefs = array();
|
||||
$datasetdefs = [];
|
||||
if (!empty($question->id)) {
|
||||
$sql = "SELECT i.*
|
||||
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||
WHERE d.question = ? AND d.datasetdefinition = i.id";
|
||||
if ($records = $DB->get_records_sql($sql, array($question->id))) {
|
||||
if ($records = $DB->get_records_sql($sql, [$question->id])) {
|
||||
foreach ($records as $r) {
|
||||
$def = $r;
|
||||
if ($def->category == '0') {
|
||||
@@ -124,7 +124,7 @@ class qtype_calculated extends question_type {
|
||||
$def->decimals = $dec;
|
||||
if ($def->itemcount > 0) {
|
||||
// Get the datasetitems.
|
||||
$def->items = array();
|
||||
$def->items = [];
|
||||
if ($items = $this->get_database_dataset_items($def->id)) {
|
||||
$n = 0;
|
||||
foreach ($items as $ii) {
|
||||
@@ -155,7 +155,7 @@ class qtype_calculated extends question_type {
|
||||
// Calculated options.
|
||||
$update = true;
|
||||
$options = $DB->get_record('question_calculated_options',
|
||||
array('question' => $question->id));
|
||||
['question' => $question->id]);
|
||||
if (!$options) {
|
||||
$update = false;
|
||||
$options = new stdClass();
|
||||
@@ -168,11 +168,11 @@ class qtype_calculated extends question_type {
|
||||
$options->synchronize = 0;
|
||||
}
|
||||
$options->single = 0;
|
||||
$options->answernumbering = $question->answernumbering;
|
||||
$options->answernumbering = $question->answernumbering;
|
||||
$options->shuffleanswers = $question->shuffleanswers;
|
||||
|
||||
foreach (array('correctfeedback', 'partiallycorrectfeedback',
|
||||
'incorrectfeedback') as $feedbackname) {
|
||||
foreach (['correctfeedback', 'partiallycorrectfeedback',
|
||||
'incorrectfeedback'] as $feedbackname) {
|
||||
$options->$feedbackname = '';
|
||||
$feedbackformat = $feedbackname . 'format';
|
||||
$options->$feedbackformat = 0;
|
||||
@@ -186,10 +186,10 @@ class qtype_calculated extends question_type {
|
||||
|
||||
// Get old versions of the objects.
|
||||
$oldanswers = $DB->get_records('question_answers',
|
||||
array('question' => $question->id), 'id ASC');
|
||||
['question' => $question->id], 'id ASC');
|
||||
|
||||
$oldoptions = $DB->get_records('question_calculated',
|
||||
array('question' => $question->id), 'answer ASC');
|
||||
['question' => $question->id], 'answer ASC');
|
||||
|
||||
// Save the units.
|
||||
$virtualqtype = $this->get_virtual_qtype();
|
||||
@@ -248,14 +248,14 @@ class qtype_calculated extends question_type {
|
||||
// Delete old answer records.
|
||||
if (!empty($oldanswers)) {
|
||||
foreach ($oldanswers as $oa) {
|
||||
$DB->delete_records('question_answers', array('id' => $oa->id));
|
||||
$DB->delete_records('question_answers', ['id' => $oa->id]);
|
||||
}
|
||||
}
|
||||
|
||||
// Delete old answer records.
|
||||
if (!empty($oldoptions)) {
|
||||
foreach ($oldoptions as $oo) {
|
||||
$DB->delete_records('question_calculated', array('id' => $oo->id));
|
||||
$DB->delete_records('question_calculated', ['id' => $oo->id]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -284,7 +284,7 @@ class qtype_calculated extends question_type {
|
||||
$datasetdef = new stdClass();
|
||||
$datasetdef->name = $dataset->name;
|
||||
$datasetdef->type = 1;
|
||||
$datasetdef->options = $dataset->distribution . ':' . $dataset->min . ':' .
|
||||
$datasetdef->options = $dataset->distribution . ':' . $dataset->min . ':' .
|
||||
$dataset->max . ':' . $dataset->length;
|
||||
$datasetdef->itemcount = $dataset->itemcount;
|
||||
if ($dataset->status == 'private') {
|
||||
@@ -296,10 +296,10 @@ class qtype_calculated extends question_type {
|
||||
"type = '1'
|
||||
AND " . $DB->sql_equal('name', '?') . "
|
||||
AND category = ?
|
||||
ORDER BY id DESC ", array($dataset->name, $question->category)
|
||||
ORDER BY id DESC ", [$dataset->name, $question->category]
|
||||
)) { // So there is at least one.
|
||||
$sharedatasetdef = array_shift($sharedatasetdefs);
|
||||
if ($sharedatasetdef->options == $datasetdef->options) {// Identical so use it.
|
||||
if ($sharedatasetdef->options == $datasetdef->options) {// Identical so use it.
|
||||
$todo = 'useit';
|
||||
$datasetdef = $sharedatasetdef;
|
||||
} else { // Different so create a private one.
|
||||
@@ -339,7 +339,7 @@ class qtype_calculated extends question_type {
|
||||
* @param stdClass $questiondata The question data object.
|
||||
*/
|
||||
protected function initialise_calculated_answers(question_definition $question, stdClass $questiondata) {
|
||||
$question->answers = array();
|
||||
$question->answers = [];
|
||||
if (empty($questiondata->options->answers)) {
|
||||
return;
|
||||
}
|
||||
@@ -541,7 +541,7 @@ class qtype_calculated extends question_type {
|
||||
// The dataset names present in the edit_question_form and edit_calculated_form
|
||||
// are retrieved.
|
||||
$possibledatasets = $this->find_dataset_names($form->questiontext);
|
||||
$mandatorydatasets = array();
|
||||
$mandatorydatasets = [];
|
||||
foreach ($form->answer as $key => $answer) {
|
||||
$mandatorydatasets += $this->find_dataset_names($answer);
|
||||
}
|
||||
@@ -551,7 +551,7 @@ class qtype_calculated extends question_type {
|
||||
if ($questionfromid != '0') {
|
||||
$form->id = $questionfromid;
|
||||
}
|
||||
$datasets = array();
|
||||
$datasets = [];
|
||||
$key = 0;
|
||||
// Always prepare the mandatorydatasets present in the answers.
|
||||
// The $options are not used here.
|
||||
@@ -590,7 +590,7 @@ class qtype_calculated extends question_type {
|
||||
AND a.type = '1'
|
||||
AND a.category != 0
|
||||
AND b.question = ?
|
||||
ORDER BY a.name ", array($question->id));
|
||||
ORDER BY a.name ", [$question->id]);
|
||||
$questionname = $this->clean_technical_prefix_from_question_name($question->name);
|
||||
|
||||
if (!empty($categorydatasetdefs)) {
|
||||
@@ -603,7 +603,7 @@ class qtype_calculated extends question_type {
|
||||
}
|
||||
$questionname = '#' . $questionname;
|
||||
}
|
||||
$DB->set_field('question', 'name', $questionname, array('id' => $question->id));
|
||||
$DB->set_field('question', 'name', $questionname, ['id' => $question->id]);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -633,7 +633,7 @@ class qtype_calculated extends question_type {
|
||||
return $question;
|
||||
}
|
||||
|
||||
$wizardnow = optional_param('wizardnow', '', PARAM_ALPHA);
|
||||
$wizardnow = optional_param('wizardnow', '', PARAM_ALPHA);
|
||||
$id = optional_param('id', 0, PARAM_INT); // Question id.
|
||||
// In case 'question':
|
||||
// For a new question $form->id is empty
|
||||
@@ -647,7 +647,7 @@ class qtype_calculated extends question_type {
|
||||
switch($wizardnow) {
|
||||
case '' :
|
||||
case 'question': // Coming from the first page, creating the second.
|
||||
if (empty($form->id)) { // or a new question $form->id is empty.
|
||||
if (empty($form->id)) { // Or a new question $form->id is empty.
|
||||
$question = parent::save_question($question, $form);
|
||||
// Prepare the datasets using default $questionfromid.
|
||||
$this->preparedatasets($form);
|
||||
@@ -657,7 +657,7 @@ class qtype_calculated extends question_type {
|
||||
$this->addnamecategory($question);
|
||||
}
|
||||
} else {
|
||||
$questionfromid = $form->id;
|
||||
$questionfromid = $form->id;
|
||||
$question = parent::save_question($question, $form);
|
||||
// Prepare the datasets.
|
||||
$this->preparedatasets($form, $questionfromid);
|
||||
@@ -679,7 +679,7 @@ class qtype_calculated extends question_type {
|
||||
$optionssynchronize = 0;
|
||||
}
|
||||
$DB->set_field('question_calculated_options', 'synchronize', $optionssynchronize,
|
||||
array('question' => $question->id));
|
||||
['question' => $question->id]);
|
||||
if (isset($form->synchronize) && $form->synchronize == 2) {
|
||||
$this->addnamecategory($question);
|
||||
}
|
||||
@@ -700,22 +700,22 @@ class qtype_calculated extends question_type {
|
||||
public function delete_question($questionid, $contextid) {
|
||||
global $DB;
|
||||
|
||||
$DB->delete_records('question_calculated', array('question' => $questionid));
|
||||
$DB->delete_records('question_calculated_options', array('question' => $questionid));
|
||||
$DB->delete_records('question_numerical_units', array('question' => $questionid));
|
||||
if ($datasets = $DB->get_records('question_datasets', array('question' => $questionid))) {
|
||||
$DB->delete_records('question_calculated', ['question' => $questionid]);
|
||||
$DB->delete_records('question_calculated_options', ['question' => $questionid]);
|
||||
$DB->delete_records('question_numerical_units', ['question' => $questionid]);
|
||||
if ($datasets = $DB->get_records('question_datasets', ['question' => $questionid])) {
|
||||
foreach ($datasets as $dataset) {
|
||||
if (!$DB->get_records_select('question_datasets',
|
||||
"question != ? AND datasetdefinition = ? ",
|
||||
array($questionid, $dataset->datasetdefinition))) {
|
||||
[$questionid, $dataset->datasetdefinition])) {
|
||||
$DB->delete_records('question_dataset_definitions',
|
||||
array('id' => $dataset->datasetdefinition));
|
||||
['id' => $dataset->datasetdefinition]);
|
||||
$DB->delete_records('question_dataset_items',
|
||||
array('definition' => $dataset->datasetdefinition));
|
||||
['definition' => $dataset->datasetdefinition]);
|
||||
}
|
||||
}
|
||||
}
|
||||
$DB->delete_records('question_datasets', array('question' => $questionid));
|
||||
$DB->delete_records('question_datasets', ['question' => $questionid]);
|
||||
|
||||
parent::delete_question($questionid, $contextid);
|
||||
}
|
||||
@@ -736,7 +736,7 @@ class qtype_calculated extends question_type {
|
||||
|
||||
public function custom_generator_tools_part($mform, $idx, $j) {
|
||||
|
||||
$minmaxgrp = array();
|
||||
$minmaxgrp = [];
|
||||
$minmaxgrp[] = $mform->createElement('float', "calcmin[{$idx}]",
|
||||
get_string('calcmin', 'qtype_calculated'));
|
||||
$minmaxgrp[] = $mform->createElement('float', "calcmax[{$idx}]",
|
||||
@@ -748,8 +748,8 @@ class qtype_calculated extends question_type {
|
||||
$mform->addElement('select', "calclength[{$idx}]",
|
||||
get_string('calclength', 'qtype_calculated'), $precisionoptions);
|
||||
|
||||
$distriboptions = array('uniform' => get_string('uniform', 'qtype_calculated'),
|
||||
'loguniform' => get_string('loguniform', 'qtype_calculated'));
|
||||
$distriboptions = ['uniform' => get_string('uniform', 'qtype_calculated'),
|
||||
'loguniform' => get_string('loguniform', 'qtype_calculated')];
|
||||
$mform->addElement('select', "calcdistribution[{$idx}]",
|
||||
get_string('calcdistribution', 'qtype_calculated'), $distriboptions);
|
||||
}
|
||||
@@ -774,20 +774,20 @@ class qtype_calculated extends question_type {
|
||||
if (preg_match('~^(uniform|loguniform):([^:]*):([^:]*):([0-9]*)$~',
|
||||
$datasetdef->options, $regs)) {
|
||||
$defid = "{$datasetdef->type}-{$datasetdef->category}-{$datasetdef->name}";
|
||||
for ($i = 0; $i<10; ++$i) {
|
||||
for ($i = 0; $i < 10; ++$i) {
|
||||
$lengthoptions[$i] = get_string(($regs[1] == 'uniform'
|
||||
? 'decimals'
|
||||
: 'significantfigures'), 'qtype_calculated', $i);
|
||||
}
|
||||
$menu1 = html_writer::label(get_string('lengthoption', 'qtype_calculated'),
|
||||
'menucalclength', false, array('class' => 'accesshide'));
|
||||
$menu1 .= html_writer::select($lengthoptions, 'calclength[]', $regs[4], null, array('class' => 'custom-select'));
|
||||
'menucalclength', false, ['class' => 'accesshide']);
|
||||
$menu1 .= html_writer::select($lengthoptions, 'calclength[]', $regs[4], null, ['class' => 'custom-select']);
|
||||
|
||||
$options = array('uniform' => get_string('uniformbit', 'qtype_calculated'),
|
||||
'loguniform' => get_string('loguniformbit', 'qtype_calculated'));
|
||||
$options = ['uniform' => get_string('uniformbit', 'qtype_calculated'),
|
||||
'loguniform' => get_string('loguniformbit', 'qtype_calculated')];
|
||||
$menu2 = html_writer::label(get_string('distributionoption', 'qtype_calculated'),
|
||||
'menucalcdistribution', false, array('class' => 'accesshide'));
|
||||
$menu2 .= html_writer::select($options, 'calcdistribution[]', $regs[1], null, array('class' => 'custom-select'));
|
||||
'menucalcdistribution', false, ['class' => 'accesshide']);
|
||||
$menu2 .= html_writer::select($options, 'calcdistribution[]', $regs[1], null, ['class' => 'custom-select']);
|
||||
return '<input type="submit" class="btn btn-secondary" onclick="'
|
||||
. "getElementById('addform').regenerateddefid.value='{$defid}'; return true;"
|
||||
.'" value="'. get_string('generatevalue', 'qtype_calculated') . '"/><br/>'
|
||||
@@ -815,20 +815,20 @@ class qtype_calculated extends question_type {
|
||||
$uniquedefs = array_values(array_unique($form->definition));
|
||||
foreach ($uniquedefs as $key => $defid) {
|
||||
if (isset($datasetdefs[$defid])
|
||||
&& is_numeric($form->calcmin[$key+1])
|
||||
&& is_numeric($form->calcmax[$key+1])
|
||||
&& is_numeric($form->calclength[$key+1])) {
|
||||
switch ($form->calcdistribution[$key+1]) {
|
||||
&& is_numeric($form->calcmin[$key + 1])
|
||||
&& is_numeric($form->calcmax[$key + 1])
|
||||
&& is_numeric($form->calclength[$key + 1])) {
|
||||
switch ($form->calcdistribution[$key + 1]) {
|
||||
case 'uniform': case 'loguniform':
|
||||
$datasetdefs[$defid]->options =
|
||||
$form->calcdistribution[$key+1] . ':'
|
||||
. $form->calcmin[$key+1] . ':'
|
||||
. $form->calcmax[$key+1] . ':'
|
||||
. $form->calclength[$key+1];
|
||||
$datasetdefs[$defid]->options =
|
||||
$form->calcdistribution[$key + 1] . ':'
|
||||
. $form->calcmin[$key + 1] . ':'
|
||||
. $form->calcmax[$key + 1] . ':'
|
||||
. $form->calclength[$key + 1];
|
||||
break;
|
||||
default:
|
||||
echo $OUTPUT->notification(
|
||||
"Unexpected distribution ".$form->calcdistribution[$key+1]);
|
||||
"Unexpected distribution ".$form->calcdistribution[$key + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -847,7 +847,7 @@ class qtype_calculated extends question_type {
|
||||
global $DB;
|
||||
|
||||
foreach ($question->options->answers as $key => $answer) {
|
||||
if ($options = $DB->get_record('question_calculated', array('answer' => $key))) {
|
||||
if ($options = $DB->get_record('question_calculated', ['answer' => $key])) {
|
||||
$options->tolerance = trim($fromform->tolerance[$key]);
|
||||
$options->tolerancetype = trim($fromform->tolerancetype[$key]);
|
||||
$options->correctanswerlength = trim($fromform->correctanswerlength[$key]);
|
||||
@@ -866,11 +866,11 @@ class qtype_calculated extends question_type {
|
||||
*/
|
||||
public function get_database_dataset_items($definition) {
|
||||
global $CFG, $DB;
|
||||
$databasedataitems = $DB->get_records_sql(// Use number as key!!
|
||||
$databasedataitems = $DB->get_records_sql( // Hint: Use the number as a key.
|
||||
" SELECT id , itemnumber, definition, value
|
||||
FROM {question_dataset_items}
|
||||
WHERE definition = $definition order by id DESC ", array($definition));
|
||||
$dataitems = Array();
|
||||
WHERE definition = $definition order by id DESC ", [$definition]);
|
||||
$dataitems = [];
|
||||
foreach ($databasedataitems as $id => $dataitem) {
|
||||
if (!isset($dataitems[$dataitem->itemnumber])) {
|
||||
$dataitems[$dataitem->itemnumber] = $dataitem;
|
||||
@@ -896,7 +896,7 @@ class qtype_calculated extends question_type {
|
||||
}
|
||||
|
||||
// Get the old datasets for this question.
|
||||
$datasetdefs = $this->get_dataset_definitions($question->id, array());
|
||||
$datasetdefs = $this->get_dataset_definitions($question->id, []);
|
||||
// Handle generator options...
|
||||
$olddatasetdefs = fullclone($datasetdefs);
|
||||
$datasetdefs = $this->update_dataset_options($datasetdefs, $fromform);
|
||||
@@ -923,7 +923,7 @@ class qtype_calculated extends question_type {
|
||||
foreach ($fromform->definition as $key => $defid) {
|
||||
// If the delete button has not been pressed then skip the datasetitems
|
||||
// in the 'add item' part of the form.
|
||||
if ($i > count($datasetdefs)*$maxnumber) {
|
||||
if ($i > count($datasetdefs) * $maxnumber) {
|
||||
break;
|
||||
}
|
||||
$addeditem = new stdClass();
|
||||
@@ -978,7 +978,7 @@ class qtype_calculated extends question_type {
|
||||
$datasetdefs[$defid]->items =
|
||||
$this->get_database_dataset_items($datasetdef->id);
|
||||
}
|
||||
for ($numberadded = $maxnumber+1; $numberadded <= $maxnumber + $numbertoadd; $numberadded++) {
|
||||
for ($numberadded = $maxnumber + 1; $numberadded <= $maxnumber + $numbertoadd; $numberadded++) {
|
||||
if (isset($datasetdefs[$defid]->items[$numberadded])) {
|
||||
// In case of regenerate it modifies the already existing record.
|
||||
if ($defregenerate) {
|
||||
@@ -1017,16 +1017,16 @@ class qtype_calculated extends question_type {
|
||||
|
||||
if (isset($fromform->deletebutton)) {
|
||||
if (isset($fromform->selectdelete)) {
|
||||
$newmaxnumber = $maxnumber-$fromform->selectdelete;
|
||||
$newmaxnumber = $maxnumber - $fromform->selectdelete;
|
||||
} else {
|
||||
$newmaxnumber = $maxnumber-1;
|
||||
$newmaxnumber = $maxnumber - 1;
|
||||
}
|
||||
if ($newmaxnumber < 0) {
|
||||
$newmaxnumber = 0;
|
||||
}
|
||||
foreach ($datasetdefs as $datasetdef) {
|
||||
if ($datasetdef->itemcount == $maxnumber) {
|
||||
$datasetdef->itemcount= $newmaxnumber;
|
||||
$datasetdef->itemcount = $newmaxnumber;
|
||||
$DB->update_record('question_dataset_definitions', $datasetdef);
|
||||
}
|
||||
}
|
||||
@@ -1039,12 +1039,12 @@ class qtype_calculated extends question_type {
|
||||
return false;
|
||||
}
|
||||
if ($regs[1] == 'uniform') {
|
||||
$nbr = $regs[2] + ($regs[3]-$regs[2])*mt_rand()/mt_getrandmax();
|
||||
$nbr = $regs[2] + ($regs[3] - $regs[2]) * mt_rand() / mt_getrandmax();
|
||||
return sprintf("%.".$regs[4].'f', $nbr);
|
||||
|
||||
} else if ($regs[1] == 'loguniform') {
|
||||
$log0 = log(abs($regs[2])); // It would have worked the other way to.
|
||||
$nbr = exp($log0 + (log(abs($regs[3])) - $log0)*mt_rand()/mt_getrandmax());
|
||||
$nbr = exp($log0 + (log(abs($regs[3])) - $log0) * mt_rand() / mt_getrandmax());
|
||||
return sprintf("%.".$regs[4].'f', $nbr);
|
||||
|
||||
} else {
|
||||
@@ -1071,14 +1071,14 @@ class qtype_calculated extends question_type {
|
||||
$answers, $data, $number) {
|
||||
global $DB;
|
||||
$comment = new stdClass();
|
||||
$comment->stranswers = array();
|
||||
$comment->stranswers = [];
|
||||
$comment->outsidelimit = false;
|
||||
$comment->answers = array();
|
||||
$comment->answers = [];
|
||||
// Find a default unit.
|
||||
$unit = '';
|
||||
if (!empty($questionid)) {
|
||||
$units = $DB->get_records('question_numerical_units',
|
||||
array('question' => $questionid, 'multiplier' => 1.0),
|
||||
['question' => $questionid, 'multiplier' => 1.0],
|
||||
'id ASC', '*', 0, 1);
|
||||
if ($units) {
|
||||
$unit = reset($units);
|
||||
@@ -1088,7 +1088,7 @@ class qtype_calculated extends question_type {
|
||||
|
||||
$answers = fullclone($answers);
|
||||
$delimiter = ': ';
|
||||
$virtualqtype = $qtypeobj->get_virtual_qtype();
|
||||
$virtualqtype = $qtypeobj->get_virtual_qtype();
|
||||
foreach ($answers as $key => $answer) {
|
||||
$error = qtype_calculated_find_formula_errors($answer->answer);
|
||||
if ($error) {
|
||||
@@ -1121,8 +1121,8 @@ class qtype_calculated extends question_type {
|
||||
$correcttrue = new stdClass();
|
||||
$correcttrue->correct = $formattedanswer->answer;
|
||||
$correcttrue->true = '';
|
||||
if ($formattedanswer->answer < $answer->min ||
|
||||
$formattedanswer->answer > $answer->max) {
|
||||
if ((float) $formattedanswer->answer < $answer->min ||
|
||||
(float) $formattedanswer->answer > $answer->max) {
|
||||
$comment->outsidelimit = true;
|
||||
$comment->answers[$key] = $key;
|
||||
$comment->stranswers[$key] .=
|
||||
@@ -1142,11 +1142,11 @@ class qtype_calculated extends question_type {
|
||||
}
|
||||
|
||||
public function tolerance_types() {
|
||||
return array(
|
||||
return [
|
||||
'1' => get_string('relative', 'qtype_numerical'),
|
||||
'2' => get_string('nominal', 'qtype_numerical'),
|
||||
'3' => get_string('geometric', 'qtype_numerical')
|
||||
);
|
||||
'3' => get_string('geometric', 'qtype_numerical'),
|
||||
];
|
||||
}
|
||||
|
||||
public function dataset_options($form, $name, $mandatory = true,
|
||||
@@ -1166,18 +1166,18 @@ class qtype_calculated extends question_type {
|
||||
}
|
||||
if (!$selected) {
|
||||
if ($mandatory) {
|
||||
$selected = "1-0-{$name}"; // Default.
|
||||
$selected = "1-0-{$name}"; // Default.
|
||||
} else {
|
||||
$selected = '0'; // Default.
|
||||
}
|
||||
}
|
||||
return array($options, $selected);
|
||||
return [$options, $selected];
|
||||
}
|
||||
|
||||
public function construct_dataset_menus($form, $mandatorydatasets,
|
||||
$optionaldatasets) {
|
||||
global $OUTPUT;
|
||||
$datasetmenus = array();
|
||||
$datasetmenus = [];
|
||||
foreach ($mandatorydatasets as $datasetname) {
|
||||
if (!isset($datasetmenus[$datasetname])) {
|
||||
list($options, $selected) =
|
||||
@@ -1249,14 +1249,14 @@ class qtype_calculated extends question_type {
|
||||
public function get_dataset_definitions($questionid, $newdatasets) {
|
||||
global $DB;
|
||||
// Get the existing datasets for this question.
|
||||
$datasetdefs = array();
|
||||
$datasetdefs = [];
|
||||
if (!empty($questionid)) {
|
||||
global $CFG;
|
||||
$sql = "SELECT i.*
|
||||
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||
WHERE d.question = ? AND d.datasetdefinition = i.id
|
||||
ORDER BY i.id";
|
||||
if ($records = $DB->get_records_sql($sql, array($questionid))) {
|
||||
if ($records = $DB->get_records_sql($sql, [$questionid])) {
|
||||
foreach ($records as $r) {
|
||||
$datasetdefs["{$r->type}-{$r->category}-{$r->name}"] = $r;
|
||||
}
|
||||
@@ -1288,7 +1288,7 @@ class qtype_calculated extends question_type {
|
||||
// Save synchronize.
|
||||
|
||||
if (empty($form->dataset)) {
|
||||
$form->dataset = array();
|
||||
$form->dataset = [];
|
||||
}
|
||||
// Save datasets.
|
||||
$datasetdefinitions = $this->get_dataset_definitions($form->id, $form->dataset);
|
||||
@@ -1300,13 +1300,13 @@ class qtype_calculated extends question_type {
|
||||
if (!isset($tmpdatasets[$defid])) {
|
||||
// This dataset is not used any more, delete it.
|
||||
$DB->delete_records('question_datasets',
|
||||
array('question' => $form->id, 'datasetdefinition' => $datasetdef->id));
|
||||
['question' => $form->id, 'datasetdefinition' => $datasetdef->id]);
|
||||
if ($datasetdef->category == 0) {
|
||||
// Question local dataset.
|
||||
$DB->delete_records('question_dataset_definitions',
|
||||
array('id' => $datasetdef->id));
|
||||
['id' => $datasetdef->id]);
|
||||
$DB->delete_records('question_dataset_items',
|
||||
array('definition' => $datasetdef->id));
|
||||
['definition' => $datasetdef->id]);
|
||||
}
|
||||
}
|
||||
// This has already been saved or just got deleted.
|
||||
@@ -1324,12 +1324,12 @@ class qtype_calculated extends question_type {
|
||||
if ($olderdatasetdefs = $DB->get_records_select('question_dataset_definitions',
|
||||
'type = ? AND name = ? AND category = ? AND id < ?
|
||||
ORDER BY id DESC',
|
||||
array($datasetdef->type, $datasetdef->name,
|
||||
$datasetdef->category, $datasetdef->id))) {
|
||||
[$datasetdef->type, $datasetdef->name,
|
||||
$datasetdef->category, $datasetdef->id])) {
|
||||
|
||||
while ($olderdatasetdef = array_shift($olderdatasetdefs)) {
|
||||
$DB->delete_records('question_dataset_definitions',
|
||||
array('id' => $datasetdef->id));
|
||||
['id' => $datasetdef->id]);
|
||||
$datasetdef = $olderdatasetdef;
|
||||
}
|
||||
}
|
||||
@@ -1348,13 +1348,13 @@ class qtype_calculated extends question_type {
|
||||
if (!empty($datasetdefinitions)) {
|
||||
foreach ($datasetdefinitions as $def) {
|
||||
$DB->delete_records('question_datasets',
|
||||
array('question' => $form->id, 'datasetdefinition' => $def->id));
|
||||
['question' => $form->id, 'datasetdefinition' => $def->id]);
|
||||
|
||||
if ($def->category == 0) { // Question local dataset.
|
||||
$DB->delete_records('question_dataset_definitions',
|
||||
array('id' => $def->id));
|
||||
['id' => $def->id]);
|
||||
$DB->delete_records('question_dataset_items',
|
||||
array('definition' => $def->id));
|
||||
['definition' => $def->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1427,12 +1427,12 @@ class qtype_calculated extends question_type {
|
||||
if ($olderdatasetdefs = $DB->get_records_select('question_dataset_definitions',
|
||||
"type = ? AND " . $DB->sql_equal('name', '?') . " AND category = ? AND id < ?
|
||||
ORDER BY id DESC",
|
||||
array($datasetdef->type, $datasetdef->name,
|
||||
$datasetdef->category, $datasetdef->id))) {
|
||||
[$datasetdef->type, $datasetdef->name,
|
||||
$datasetdef->category, $datasetdef->id])) {
|
||||
|
||||
while ($olderdatasetdef = array_shift($olderdatasetdefs)) {
|
||||
$DB->delete_records('question_dataset_definitions',
|
||||
array('id' => $datasetdef->id));
|
||||
['id' => $datasetdef->id]);
|
||||
$datasetdef = $olderdatasetdef;
|
||||
}
|
||||
}
|
||||
@@ -1451,13 +1451,13 @@ class qtype_calculated extends question_type {
|
||||
if (!empty($datasetdefinitions)) {
|
||||
foreach ($datasetdefinitions as $def) {
|
||||
$DB->delete_records('question_datasets',
|
||||
array('question' => $form->id, 'datasetdefinition' => $def->id));
|
||||
['question' => $form->id, 'datasetdefinition' => $def->id]);
|
||||
|
||||
if ($def->category == 0) { // Question local dataset.
|
||||
$DB->delete_records('question_dataset_definitions',
|
||||
array('id' => $def->id));
|
||||
['id' => $def->id]);
|
||||
$DB->delete_records('question_dataset_items',
|
||||
array('definition' => $def->id));
|
||||
['definition' => $def->id]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1478,13 +1478,13 @@ class qtype_calculated extends question_type {
|
||||
AND q.datasetdefinition = d.id
|
||||
AND d.id = i.definition
|
||||
AND i.itemnumber = ?
|
||||
ORDER BY i.id DESC ", array($question->id, $datasetitem))) {
|
||||
ORDER BY i.id DESC ", [$question->id, $datasetitem])) {
|
||||
$a = new stdClass();
|
||||
$a->id = $question->id;
|
||||
$a->item = $datasetitem;
|
||||
throw new \moodle_exception('cannotgetdsfordependent', 'question', '', $a);
|
||||
}
|
||||
$dataset = Array();
|
||||
$dataset = [];
|
||||
foreach ($dataitems as $id => $dataitem) {
|
||||
if (!isset($dataset[$dataitem->name])) {
|
||||
$dataset[$dataitem->name] = $dataitem->value;
|
||||
@@ -1510,14 +1510,14 @@ class qtype_calculated extends question_type {
|
||||
$sql = "SELECT a.*
|
||||
FROM {question_dataset_definitions} a, {question_datasets} b
|
||||
WHERE a.id = b.datasetdefinition AND a.type = '1' AND b.question = ? AND " . $DB->sql_equal('a.name', '?');
|
||||
$currentdatasetdef = $DB->get_record_sql($sql, array($form->id, $name));
|
||||
$currentdatasetdef = $DB->get_record_sql($sql, [$form->id, $name]);
|
||||
if (!$currentdatasetdef) {
|
||||
$currentdatasetdef = new stdClass();
|
||||
$currentdatasetdef->type = '0';
|
||||
}
|
||||
$key = "{$type}-0-{$name}";
|
||||
if ($currentdatasetdef->type == $type
|
||||
and $currentdatasetdef->category == 0) {
|
||||
&& $currentdatasetdef->category == 0) {
|
||||
$options[$key] = get_string($prefix."keptlocal{$type}", $langfile);
|
||||
} else {
|
||||
$options[$key] = get_string($prefix."newlocal{$type}", $langfile);
|
||||
@@ -1531,7 +1531,7 @@ class qtype_calculated extends question_type {
|
||||
WHERE a.id = b.datasetdefinition
|
||||
AND a.type = '1'
|
||||
AND a.category = ?
|
||||
AND " . $DB->sql_equal('a.name', '?'), array($form->category, $name));
|
||||
AND " . $DB->sql_equal('a.name', '?'), [$form->category, $name]);
|
||||
$type = 1;
|
||||
$key = "{$type}-{$form->category}-{$name}";
|
||||
if (!empty($categorydatasetdefs)) {
|
||||
@@ -1546,9 +1546,9 @@ class qtype_calculated extends question_type {
|
||||
$options[$key] = get_string($prefix."newcategory{$type}", $langfile);
|
||||
}
|
||||
// All done!
|
||||
return array($options, $currentdatasetdef->type
|
||||
return [$options, $currentdatasetdef->type
|
||||
? "{$currentdatasetdef->type}-{$currentdatasetdef->category}-{$name}"
|
||||
: '');
|
||||
: ''];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -1582,13 +1582,13 @@ class qtype_calculated extends question_type {
|
||||
*/
|
||||
public function get_dataset_definitions_category($form) {
|
||||
global $CFG, $DB;
|
||||
$datasetdefs = array();
|
||||
$datasetdefs = [];
|
||||
$lnamemax = 30;
|
||||
if (!empty($form->category)) {
|
||||
$sql = "SELECT i.*, d.*
|
||||
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||
WHERE i.id = d.datasetdefinition AND i.category = ?";
|
||||
if ($records = $DB->get_records_sql($sql, array($form->category))) {
|
||||
if ($records = $DB->get_records_sql($sql, [$form->category])) {
|
||||
foreach ($records as $r) {
|
||||
if (!isset ($datasetdefs["{$r->name}"])) {
|
||||
$datasetdefs["{$r->name}"] = $r->itemcount;
|
||||
@@ -1608,7 +1608,7 @@ class qtype_calculated extends question_type {
|
||||
*/
|
||||
public function print_dataset_definitions_category($form) {
|
||||
global $CFG, $DB;
|
||||
$datasetdefs = array();
|
||||
$datasetdefs = [];
|
||||
$lnamemax = 22;
|
||||
$namestr = get_string('name');
|
||||
$rangeofvaluestr = get_string('minmax', 'qtype_calculated');
|
||||
@@ -1622,7 +1622,7 @@ class qtype_calculated extends question_type {
|
||||
{question_dataset_definitions} i
|
||||
WHERE i.id = d.datasetdefinition
|
||||
AND i.category = ?";
|
||||
if ($records = $DB->get_records_sql($sql, array($category))) {
|
||||
if ($records = $DB->get_records_sql($sql, [$category])) {
|
||||
foreach ($records as $r) {
|
||||
$sql1 = "SELECT q.*
|
||||
FROM {question} q
|
||||
@@ -1630,12 +1630,12 @@ class qtype_calculated extends question_type {
|
||||
if (!isset ($datasetdefs["{$r->type}-{$r->category}-{$r->name}"])) {
|
||||
$datasetdefs["{$r->type}-{$r->category}-{$r->name}"] = $r;
|
||||
}
|
||||
if ($questionb = $DB->get_records_sql($sql1, array($r->question))) {
|
||||
if ($questionb = $DB->get_records_sql($sql1, [$r->question])) {
|
||||
if (!isset ($datasetdefs["{$r->type}-{$r->category}-{$r->name}"]->questions[$r->question])) {
|
||||
$datasetdefs["{$r->type}-{$r->category}-{$r->name}"]->questions[$r->question] = new stdClass();
|
||||
}
|
||||
$datasetdefs["{$r->type}-{$r->category}-{$r->name}"]->questions[
|
||||
$r->question]->name = $questionb[$r->question]->name;
|
||||
$datasetdefs["{$r->type}-{$r->category}-{$r->name}"]->questions[$r->question]->name =
|
||||
$questionb[$r->question]->name;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1680,8 +1680,7 @@ class qtype_calculated extends question_type {
|
||||
* @param int $characterlimit the character limit.
|
||||
* @return string
|
||||
*/
|
||||
public function get_short_question_name($stringtoshorten, $characterlimit)
|
||||
{
|
||||
public function get_short_question_name($stringtoshorten, $characterlimit) {
|
||||
if (!empty($stringtoshorten)) {
|
||||
$returnstring = format_string($stringtoshorten);
|
||||
if (strlen($returnstring) > $characterlimit) {
|
||||
@@ -1703,7 +1702,7 @@ class qtype_calculated extends question_type {
|
||||
|
||||
public function print_dataset_definitions_category_shared($question, $datasetdefsq) {
|
||||
global $CFG, $DB;
|
||||
$datasetdefs = array();
|
||||
$datasetdefs = [];
|
||||
$lnamemax = 22;
|
||||
$namestr = get_string('name', 'quiz');
|
||||
$rangeofvaluestr = get_string('minmax', 'qtype_calculated');
|
||||
@@ -1715,7 +1714,7 @@ class qtype_calculated extends question_type {
|
||||
$sql = "SELECT i.*, d.*
|
||||
FROM {question_datasets} d, {question_dataset_definitions} i
|
||||
WHERE i.id = d.datasetdefinition AND i.category = ?";
|
||||
if ($records = $DB->get_records_sql($sql, array($category))) {
|
||||
if ($records = $DB->get_records_sql($sql, [$category])) {
|
||||
foreach ($records as $r) {
|
||||
$key = "{$r->type}-{$r->category}-{$r->name}";
|
||||
$sql1 = "SELECT q.*
|
||||
@@ -1724,7 +1723,7 @@ class qtype_calculated extends question_type {
|
||||
if (!isset($datasetdefs[$key])) {
|
||||
$datasetdefs[$key] = $r;
|
||||
}
|
||||
if ($questionb = $DB->get_records_sql($sql1, array($r->question))) {
|
||||
if ($questionb = $DB->get_records_sql($sql1, [$r->question])) {
|
||||
$datasetdefs[$key]->questions[$r->question] = new stdClass();
|
||||
$datasetdefs[$key]->questions[$r->question]->name =
|
||||
$questionb[$r->question]->name;
|
||||
@@ -1792,7 +1791,7 @@ class qtype_calculated extends question_type {
|
||||
}
|
||||
|
||||
public function get_possible_responses($questiondata) {
|
||||
$responses = array();
|
||||
$responses = [];
|
||||
|
||||
$virtualqtype = $this->get_virtual_qtype();
|
||||
$unit = $virtualqtype->get_default_numerical_unit($questiondata);
|
||||
@@ -1825,7 +1824,7 @@ class qtype_calculated extends question_type {
|
||||
|
||||
$responses[null] = question_possible_response::no_response();
|
||||
|
||||
return array($questiondata->id => $responses);
|
||||
return [$questiondata->id => $responses];
|
||||
}
|
||||
|
||||
public function move_files($questionid, $oldcontextid, $newcontextid) {
|
||||
@@ -1910,7 +1909,7 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
|
||||
$answer .= (1 == strlen($answer) ? '.' : '')
|
||||
. '00000000000000000000000000000000000000000x';
|
||||
$calculated->answer = $sign
|
||||
.substr($answer, 0, $answerlength +1).$exponent;
|
||||
.substr($answer, 0, $answerlength + 1).$exponent;
|
||||
}
|
||||
} else {
|
||||
// Stick to plain numeric format.
|
||||
@@ -1921,7 +1920,7 @@ function qtype_calculated_calculate_answer($formula, $individualdata,
|
||||
// Could be an idea to add some zeros here.
|
||||
$answer .= (preg_match('~^[0-9]*$~', $answer) ? '.' : '')
|
||||
. '00000000000000000000000000000000000000000x';
|
||||
$oklen = $answerlength + ($p10 < 1 ? 2-$p10 : 1);
|
||||
$oklen = $answerlength + ($p10 < 1 ? 2 - $p10 : 1);
|
||||
$calculated->answer = $sign.substr($answer, 0, $oklen);
|
||||
}
|
||||
}
|
||||
@@ -1980,7 +1979,7 @@ function qtype_calculated_find_formula_errors($formula) {
|
||||
}
|
||||
break;
|
||||
|
||||
// Single argument functions (the most common case).
|
||||
// Single argument functions (the most common case).
|
||||
case 'abs': case 'acos': case 'acosh': case 'asin': case 'asinh':
|
||||
case 'atan': case 'atanh': case 'bindec': case 'ceil': case 'cos':
|
||||
case 'cosh': case 'decbin': case 'decoct': case 'deg2rad':
|
||||
@@ -1995,23 +1994,23 @@ function qtype_calculated_find_formula_errors($formula) {
|
||||
|
||||
// Functions that take one or two arguments.
|
||||
case 'log': case 'round':
|
||||
if (!empty($regs[5]) || empty($regs[3])) {
|
||||
return get_string('functiontakesoneortwoargs', 'qtype_calculated', $regs[2]);
|
||||
}
|
||||
if (!empty($regs[5]) || empty($regs[3])) {
|
||||
return get_string('functiontakesoneortwoargs', 'qtype_calculated', $regs[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
// Functions that must have two arguments.
|
||||
case 'atan2': case 'fmod': case 'pow':
|
||||
if (!empty($regs[5]) || empty($regs[4])) {
|
||||
return get_string('functiontakestwoargs', 'qtype_calculated', $regs[2]);
|
||||
}
|
||||
if (!empty($regs[5]) || empty($regs[4])) {
|
||||
return get_string('functiontakestwoargs', 'qtype_calculated', $regs[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
// Functions that take two or more arguments.
|
||||
case 'min': case 'max':
|
||||
if (empty($regs[4])) {
|
||||
return get_string('functiontakesatleasttwo', 'qtype_calculated', $regs[2]);
|
||||
}
|
||||
if (empty($regs[4])) {
|
||||
return get_string('functiontakesatleasttwo', 'qtype_calculated', $regs[2]);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -2045,7 +2044,7 @@ function qtype_calculated_find_formula_errors($formula) {
|
||||
function qtype_calculated_find_formula_errors_in_text($text) {
|
||||
$formulas = question_bank::get_qtype('calculated')->find_formulas($text);
|
||||
|
||||
$errors = array();
|
||||
$errors = [];
|
||||
foreach ($formulas as $match) {
|
||||
$error = qtype_calculated_find_formula_errors($match);
|
||||
if ($error) {
|
||||
|
||||
@@ -41,7 +41,7 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
|
||||
*/
|
||||
class qtype_calculated_test_helper extends question_test_helper {
|
||||
public function get_test_questions() {
|
||||
return array('sum');
|
||||
return ['sum', 'mult'];
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -70,15 +70,15 @@ class qtype_calculated_test_helper extends question_test_helper {
|
||||
$q->unitdisplay = qtype_numerical::UNITNONE;
|
||||
$q->unitgradingtype = 0;
|
||||
$q->unitpenalty = 0;
|
||||
$q->ap = new qtype_numerical_answer_processor(array());
|
||||
$q->ap = new qtype_numerical_answer_processor([]);
|
||||
$q->synchronised = false;
|
||||
|
||||
$q->datasetloader = new qtype_calculated_test_dataset_loader(0, array(
|
||||
array('a' => 1, 'b' => 5),
|
||||
array('a' => 3, 'b' => 4),
|
||||
array('a' => 3, 'b' => 0.01416),
|
||||
array('a' => 31, 'b' => 0.01416),
|
||||
));
|
||||
$q->datasetloader = new qtype_calculated_test_dataset_loader(0, [
|
||||
['a' => 1, 'b' => 5],
|
||||
['a' => 3, 'b' => 4],
|
||||
['a' => 3, 'b' => 0.01416],
|
||||
['a' => 31, 'b' => 0.01416],
|
||||
]);
|
||||
|
||||
return $q;
|
||||
}
|
||||
@@ -115,7 +115,7 @@ class qtype_calculated_test_helper extends question_test_helper {
|
||||
$answer->correctanswerformat = 1;
|
||||
}
|
||||
|
||||
$qdata->options->units = array();
|
||||
$qdata->options->units = [];
|
||||
|
||||
return $qdata;
|
||||
}
|
||||
@@ -138,24 +138,24 @@ class qtype_calculated_test_helper extends question_test_helper {
|
||||
$fromform->unitgradingtypes = '1';
|
||||
$fromform->unitsleft = '0';
|
||||
$fromform->nounits = 1;
|
||||
$fromform->multiplier = array();
|
||||
$fromform->multiplier = [];
|
||||
$fromform->multiplier[0] = '1.0';
|
||||
$fromform->synchronize = 0;
|
||||
$fromform->answernumbering = 0;
|
||||
$fromform->shuffleanswers = 0;
|
||||
|
||||
$fromform->noanswers = 6;
|
||||
$fromform->answer = array();
|
||||
$fromform->answer = [];
|
||||
$fromform->answer[0] = '{a} + {b}';
|
||||
$fromform->answer[1] = '{a} - {b}';
|
||||
$fromform->answer[2] = '*';
|
||||
|
||||
$fromform->fraction = array();
|
||||
$fromform->fraction = [];
|
||||
$fromform->fraction[0] = '1.0';
|
||||
$fromform->fraction[1] = '0.0';
|
||||
$fromform->fraction[2] = '0.0';
|
||||
|
||||
$fromform->tolerance = array();
|
||||
$fromform->tolerance = [];
|
||||
$fromform->tolerance[0] = 0.001;
|
||||
$fromform->tolerance[1] = 0.001;
|
||||
$fromform->tolerance[2] = 0;
|
||||
@@ -172,16 +172,16 @@ class qtype_calculated_test_helper extends question_test_helper {
|
||||
$fromform->correctanswerformat[1] = 1;
|
||||
$fromform->correctanswerformat[2] = 1;
|
||||
|
||||
$fromform->feedback = array();
|
||||
$fromform->feedback[0] = array();
|
||||
$fromform->feedback = [];
|
||||
$fromform->feedback[0] = [];
|
||||
$fromform->feedback[0]['format'] = FORMAT_HTML;
|
||||
$fromform->feedback[0]['text'] = 'Very good.';
|
||||
|
||||
$fromform->feedback[1] = array();
|
||||
$fromform->feedback[1] = [];
|
||||
$fromform->feedback[1]['format'] = FORMAT_HTML;
|
||||
$fromform->feedback[1]['text'] = 'Add. not subtract!';
|
||||
|
||||
$fromform->feedback[2] = array();
|
||||
$fromform->feedback[2] = [];
|
||||
$fromform->feedback[2]['format'] = FORMAT_HTML;
|
||||
$fromform->feedback[2]['text'] = 'Completely wrong.';
|
||||
|
||||
@@ -189,6 +189,149 @@ class qtype_calculated_test_helper extends question_test_helper {
|
||||
|
||||
return $fromform;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a calculated question about multiplying two numbers.
|
||||
*
|
||||
* @return qtype_calculated_question
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function make_calculated_question_mult() {
|
||||
question_bank::load_question_definition_classes('calculated');
|
||||
$q = new qtype_calculated_question();
|
||||
test_question_maker::initialise_a_question($q);
|
||||
$q->name = 'Simple multiplication';
|
||||
$q->questiontext = 'What is {a} * {b}?';
|
||||
$q->generalfeedback = 'Generalfeedback: {={a} * {b}} is the right answer.';
|
||||
|
||||
$q->answers = [
|
||||
13 => new \qtype_calculated\qtype_calculated_answer(13, '{a} * {b}', 1.0, 'Positive.', FORMAT_HTML, 0),
|
||||
14 => new \qtype_calculated\qtype_calculated_answer(14, '-{a} * {b}', 0.0, 'Negative.', FORMAT_HTML, 0),
|
||||
];
|
||||
foreach ($q->answers as $answer) {
|
||||
$answer->correctanswerlength = 2;
|
||||
$answer->correctanswerformat = 1;
|
||||
}
|
||||
|
||||
$q->qtype = question_bank::get_qtype('calculated');
|
||||
$q->unitdisplay = qtype_numerical::UNITOPTIONAL;
|
||||
$q->unitgradingtype = 0;
|
||||
$q->unitpenalty = 0;
|
||||
$q->unit = 'cm';
|
||||
$q->ap = new qtype_numerical_answer_processor([]);
|
||||
$q->synchronised = false;
|
||||
|
||||
$q->datasetloader = new qtype_calculated_test_dataset_loader(0, [
|
||||
['a' => 1, 'b' => 5],
|
||||
['a' => 3, 'b' => 4],
|
||||
['a' => 3, 'b' => 0.01416],
|
||||
['a' => 31, 'b' => 0.01416],
|
||||
]);
|
||||
|
||||
return $q;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a calculated question about multiplying two numbers.
|
||||
*
|
||||
* @return qtype_calculated_question
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function get_calculated_question_data_mult() {
|
||||
question_bank::load_question_definition_classes('calculated');
|
||||
$qdata = new stdClass();
|
||||
test_question_maker::initialise_question_data($qdata);
|
||||
|
||||
$qdata->qtype = 'calculated';
|
||||
$qdata->name = 'Simple multiplication';
|
||||
$qdata->questiontext = 'What is {a} * {b}?';
|
||||
$qdata->generalfeedback = 'Generalfeedback: {={a} * {b}} is the right answer.';
|
||||
$qdata->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
|
||||
|
||||
$qdata->options = new stdClass();
|
||||
$qdata->options->unitgradingtype = 0;
|
||||
$qdata->options->unitpenalty = 0.0;
|
||||
$qdata->options->showunits = qtype_numerical::UNITOPTIONAL;
|
||||
$qdata->unit = 'cm';
|
||||
$qdata->options->unitsleft = 0;
|
||||
$qdata->options->synchronize = 0;
|
||||
|
||||
$qdata->options->answers = [
|
||||
13 => new \qtype_calculated\qtype_calculated_answer(13, '{a} * {b}', 1.0, 'Positive.', FORMAT_HTML, 0.001),
|
||||
14 => new \qtype_calculated\qtype_calculated_answer(14, '-{a} * {b}', 0.0, 'Negative.', FORMAT_HTML, 0.001),
|
||||
];
|
||||
foreach ($qdata->options->answers as $answer) {
|
||||
$answer->correctanswerlength = 2;
|
||||
$answer->correctanswerformat = 1;
|
||||
}
|
||||
|
||||
$qdata->options->units = [];
|
||||
|
||||
return $qdata;
|
||||
}
|
||||
|
||||
/**
|
||||
* Makes a calculated question about multiplying two numbers.
|
||||
*
|
||||
* @return qtype_calculated_question
|
||||
* @throws coding_exception
|
||||
*/
|
||||
public function get_calculated_question_form_data_mult() {
|
||||
question_bank::load_question_definition_classes('calculated');
|
||||
$fromform = new stdClass();
|
||||
|
||||
$fromform->name = 'Simple multiplication';
|
||||
$fromform->questiontext = 'What is {a} * {b}?';
|
||||
$fromform->defaultmark = 1.0;
|
||||
$fromform->generalfeedback = 'Generalfeedback: {={a} * {b}} is the right answer.';
|
||||
|
||||
$fromform->unitrole = '0';
|
||||
$fromform->unitpenalty = 0.1;
|
||||
$fromform->unitgradingtypes = '1';
|
||||
$fromform->unitsleft = '0';
|
||||
$fromform->nounits = 1;
|
||||
$fromform->multiplier = [];
|
||||
$fromform->multiplier[0] = '1.0';
|
||||
$fromform->synchronize = 0;
|
||||
$fromform->answernumbering = 0;
|
||||
$fromform->shuffleanswers = 0;
|
||||
|
||||
$fromform->noanswers = 6;
|
||||
$fromform->answer = [];
|
||||
$fromform->answer[0] = '{a} * {b}';
|
||||
$fromform->answer[1] = '-{a} * {b}';
|
||||
|
||||
$fromform->fraction = [];
|
||||
$fromform->fraction[0] = '1.0';
|
||||
$fromform->fraction[1] = '0.0';
|
||||
|
||||
$fromform->tolerance = [];
|
||||
$fromform->tolerance[0] = 0.001;
|
||||
$fromform->tolerance[1] = 0.001;
|
||||
|
||||
$fromform->tolerancetype[0] = 1;
|
||||
$fromform->tolerancetype[1] = 1;
|
||||
|
||||
$fromform->correctanswerlength[0] = 2;
|
||||
$fromform->correctanswerlength[1] = 2;
|
||||
|
||||
$fromform->correctanswerformat[0] = 1;
|
||||
$fromform->correctanswerformat[1] = 1;
|
||||
|
||||
$fromform->feedback = [];
|
||||
$fromform->feedback[0] = [];
|
||||
$fromform->feedback[0]['format'] = FORMAT_HTML;
|
||||
$fromform->feedback[0]['text'] = 'Positive.';
|
||||
|
||||
$fromform->feedback[1] = [];
|
||||
$fromform->feedback[1]['format'] = FORMAT_HTML;
|
||||
$fromform->feedback[1]['text'] = 'Negative.';
|
||||
|
||||
$fromform->status = \core_question\local\bank\question_version_status::QUESTION_STATUS_READY;
|
||||
|
||||
return $fromform;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@@ -199,9 +342,9 @@ class qtype_calculated_test_helper extends question_test_helper {
|
||||
* @copyright 2011 The Open University
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class qtype_calculated_test_dataset_loader extends qtype_calculated_dataset_loader{
|
||||
class qtype_calculated_test_dataset_loader extends qtype_calculated_dataset_loader {
|
||||
protected $valuesets;
|
||||
protected $aresynchronised = array();
|
||||
protected $aresynchronised = [];
|
||||
|
||||
public function __construct($questionid, array $valuesets) {
|
||||
parent::__construct($questionid);
|
||||
|
||||
@@ -16,7 +16,9 @@
|
||||
|
||||
namespace qtype_calculated;
|
||||
|
||||
use qtype_calculated;
|
||||
use question_attempt_step;
|
||||
use question_bank;
|
||||
use question_classified_response;
|
||||
use question_display_options;
|
||||
use question_state;
|
||||
@@ -36,74 +38,99 @@ require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
|
||||
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
|
||||
*/
|
||||
class question_test extends \advanced_testcase {
|
||||
public function test_is_complete_response() {
|
||||
/**
|
||||
* Test is complete response
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_is_complete_response(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
|
||||
$this->assertFalse($question->is_complete_response(array()));
|
||||
$this->assertTrue($question->is_complete_response(array('answer' => '0')));
|
||||
$this->assertTrue($question->is_complete_response(array('answer' => 0)));
|
||||
$this->assertFalse($question->is_complete_response(array('answer' => 'test')));
|
||||
$this->assertFalse($question->is_complete_response([]));
|
||||
$this->assertTrue($question->is_complete_response(['answer' => '0']));
|
||||
$this->assertTrue($question->is_complete_response(['answer' => 0]));
|
||||
$this->assertFalse($question->is_complete_response(['answer' => 'test']));
|
||||
}
|
||||
|
||||
public function test_is_gradable_response() {
|
||||
/**
|
||||
* Test is gradable response
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_is_gradable_response(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
|
||||
$this->assertFalse($question->is_gradable_response(array()));
|
||||
$this->assertTrue($question->is_gradable_response(array('answer' => '0')));
|
||||
$this->assertTrue($question->is_gradable_response(array('answer' => 0)));
|
||||
$this->assertTrue($question->is_gradable_response(array('answer' => 'test')));
|
||||
$this->assertFalse($question->is_gradable_response([]));
|
||||
$this->assertTrue($question->is_gradable_response(['answer' => '0']));
|
||||
$this->assertTrue($question->is_gradable_response(['answer' => 0]));
|
||||
$this->assertTrue($question->is_gradable_response(['answer' => 'test']));
|
||||
}
|
||||
|
||||
public function test_grading() {
|
||||
/**
|
||||
* Test grading
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_grading(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$question->start_attempt(new question_attempt_step(), 1);
|
||||
$values = $question->vs->get_values();
|
||||
|
||||
$this->assertEquals(array(0, question_state::$gradedwrong),
|
||||
$question->grade_response(array('answer' => $values['a'] - $values['b'])));
|
||||
$this->assertEquals(array(1, question_state::$gradedright),
|
||||
$question->grade_response(array('answer' => $values['a'] + $values['b'])));
|
||||
$this->assertEquals([0, question_state::$gradedwrong],
|
||||
$question->grade_response(['answer' => $values['a'] - $values['b']]));
|
||||
$this->assertEquals([1, question_state::$gradedright],
|
||||
$question->grade_response(['answer' => $values['a'] + $values['b']]));
|
||||
}
|
||||
|
||||
public function test_get_correct_response() {
|
||||
/**
|
||||
* Test get correct response
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_get_correct_response(): void {
|
||||
// Testing with 3.0 + 0.1416.
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$question->start_attempt(new question_attempt_step(), 3);
|
||||
$values = $question->vs->get_values();
|
||||
$this->assertSame(array('answer' => '3.01' ), $question->get_correct_response());
|
||||
$this->assertSame(['answer' => '3.01' ], $question->get_correct_response());
|
||||
foreach ($question->answers as $answer) {
|
||||
$answer->correctanswerlength = 2;
|
||||
$answer->correctanswerformat = 2;
|
||||
}
|
||||
$this->assertSame(array('answer' => '3.0' ), $question->get_correct_response());
|
||||
$this->assertSame(['answer' => '3.0' ], $question->get_correct_response());
|
||||
|
||||
// Testing with 1.0 + 5.0.
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$question->start_attempt(new question_attempt_step(), 1);
|
||||
$values = $question->vs->get_values();
|
||||
$this->assertSame(array('answer' => '6.00' ), $question->get_correct_response());
|
||||
$this->assertSame(['answer' => '6.00' ], $question->get_correct_response());
|
||||
|
||||
foreach ($question->answers as $answer) {
|
||||
$answer->correctanswerlength = 2;
|
||||
$answer->correctanswerformat = 2;
|
||||
}
|
||||
$this->assertSame(array('answer' => '6.0' ),
|
||||
$this->assertSame(['answer' => '6.0' ],
|
||||
$question->get_correct_response());
|
||||
// Testing with 31.0 + 0.01416 .
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$question->start_attempt(new question_attempt_step(), 4);
|
||||
$values = $question->vs->get_values();
|
||||
$this->assertSame(array('answer' => '31.01' ), $question->get_correct_response());
|
||||
$this->assertSame(['answer' => '31.01' ], $question->get_correct_response());
|
||||
|
||||
foreach ($question->answers as $answer) {
|
||||
$answer->correctanswerlength = 3;
|
||||
$answer->correctanswerformat = 2;
|
||||
}
|
||||
$this->assertSame(array('answer' => '31.0' ), $question->get_correct_response());
|
||||
$this->assertSame(['answer' => '31.0' ], $question->get_correct_response());
|
||||
|
||||
}
|
||||
|
||||
public function test_get_question_summary() {
|
||||
/**
|
||||
* Test get question summary
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_get_question_summary(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$question->start_attempt(new question_attempt_step(), 1);
|
||||
$values = $question->vs->get_values();
|
||||
@@ -112,65 +139,95 @@ class question_test extends \advanced_testcase {
|
||||
$this->assertEquals('What is ' . $values['a'] . ' + ' . $values['b'] . '?', $qsummary);
|
||||
}
|
||||
|
||||
public function test_summarise_response() {
|
||||
/**
|
||||
* Test summarise response
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_summarise_response(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$question->start_attempt(new question_attempt_step(), 1);
|
||||
$values = $question->vs->get_values();
|
||||
|
||||
$this->assertEquals('3.1', $question->summarise_response(array('answer' => '3.1')));
|
||||
$this->assertEquals('3.1', $question->summarise_response(['answer' => '3.1']));
|
||||
}
|
||||
|
||||
public function test_classify_response() {
|
||||
/**
|
||||
* Test classify response
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_classify_response(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$question->start_attempt(new question_attempt_step(), 1);
|
||||
$values = $question->vs->get_values();
|
||||
|
||||
$this->assertEquals(array(
|
||||
new question_classified_response(13, $values['a'] + $values['b'], 1.0)),
|
||||
$question->classify_response(array('answer' => $values['a'] + $values['b'])));
|
||||
$this->assertEquals(array(
|
||||
new question_classified_response(14, $values['a'] - $values['b'], 0.0)),
|
||||
$question->classify_response(array('answer' => $values['a'] - $values['b'])));
|
||||
$this->assertEquals(array(
|
||||
new question_classified_response(17, 7 * $values['a'], 0.0)),
|
||||
$question->classify_response(array('answer' => 7 * $values['a'])));
|
||||
$this->assertEquals(array(
|
||||
question_classified_response::no_response()),
|
||||
$question->classify_response(array('answer' => '')));
|
||||
$this->assertEquals([
|
||||
new question_classified_response(13, $values['a'] + $values['b'], 1.0)],
|
||||
$question->classify_response(['answer' => $values['a'] + $values['b']]));
|
||||
$this->assertEquals([
|
||||
new question_classified_response(14, $values['a'] - $values['b'], 0.0)],
|
||||
$question->classify_response(['answer' => $values['a'] - $values['b']]));
|
||||
$this->assertEquals([
|
||||
new question_classified_response(17, 7 * $values['a'], 0.0)],
|
||||
$question->classify_response(['answer' => 7 * $values['a']]));
|
||||
$this->assertEquals([
|
||||
question_classified_response::no_response()],
|
||||
$question->classify_response(['answer' => '']));
|
||||
}
|
||||
|
||||
public function test_classify_response_no_star() {
|
||||
/**
|
||||
* Test classify response no star
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_classify_response_no_star(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
unset($question->answers[17]);
|
||||
$question->start_attempt(new question_attempt_step(), 1);
|
||||
$values = $question->vs->get_values();
|
||||
|
||||
$this->assertEquals(array(
|
||||
new question_classified_response(13, $values['a'] + $values['b'], 1.0)),
|
||||
$question->classify_response(array('answer' => $values['a'] + $values['b'])));
|
||||
$this->assertEquals(array(
|
||||
new question_classified_response(14, $values['a'] - $values['b'], 0.0)),
|
||||
$question->classify_response(array('answer' => $values['a'] - $values['b'])));
|
||||
$this->assertEquals(array(
|
||||
new question_classified_response(0, 7 * $values['a'], 0.0)),
|
||||
$question->classify_response(array('answer' => 7 * $values['a'])));
|
||||
$this->assertEquals(array(
|
||||
question_classified_response::no_response()),
|
||||
$question->classify_response(array('answer' => '')));
|
||||
$this->assertEquals([
|
||||
new question_classified_response(13, $values['a'] + $values['b'], 1.0)],
|
||||
$question->classify_response(['answer' => $values['a'] + $values['b']]));
|
||||
$this->assertEquals([
|
||||
new question_classified_response(14, $values['a'] - $values['b'], 0.0)],
|
||||
$question->classify_response(['answer' => $values['a'] - $values['b']]));
|
||||
$this->assertEquals([
|
||||
new question_classified_response(0, 7 * $values['a'], 0.0)],
|
||||
$question->classify_response(['answer' => 7 * $values['a']]));
|
||||
$this->assertEquals([
|
||||
question_classified_response::no_response()],
|
||||
$question->classify_response(['answer' => '']));
|
||||
}
|
||||
|
||||
public function test_get_variants_selection_seed_q_not_synchronised() {
|
||||
/**
|
||||
* Test get variants selection seed q not synchronised
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_get_variants_selection_seed_q_not_synchronised(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$this->assertEquals($question->stamp, $question->get_variants_selection_seed());
|
||||
}
|
||||
|
||||
public function test_get_variants_selection_seed_q_synchronised_datasets_not() {
|
||||
/**
|
||||
* Test get variants selection seed q synchronised datasets not
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_get_variants_selection_seed_q_synchronised_datasets_not(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$question->synchronised = true;
|
||||
$this->assertEquals($question->stamp, $question->get_variants_selection_seed());
|
||||
}
|
||||
|
||||
public function test_get_variants_selection_seed_q_synchronised() {
|
||||
/**
|
||||
* Test get variants selection seed q synchronised
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_get_variants_selection_seed_q_synchronised(): void {
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
$question->synchronised = true;
|
||||
$question->datasetloader->set_are_synchronised($question->category, true);
|
||||
@@ -179,9 +236,11 @@ class question_test extends \advanced_testcase {
|
||||
}
|
||||
|
||||
/**
|
||||
* test_get_question_definition_for_external_rendering
|
||||
* Test get question definition for external rendering
|
||||
*
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_get_question_definition_for_external_rendering() {
|
||||
public function test_get_question_definition_for_external_rendering(): void {
|
||||
$this->resetAfterTest();
|
||||
|
||||
$question = \test_question_maker::make_question('calculated');
|
||||
@@ -196,4 +255,43 @@ class question_test extends \advanced_testcase {
|
||||
$this->assertEquals(qtype_numerical::UNITNONE, $options['unitdisplay']);
|
||||
$this->assertEmpty($options['unitsleft']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test that the grading of negative responses does not show false ERROR.
|
||||
*
|
||||
* @return void
|
||||
* @throws \coding_exception
|
||||
* @throws \dml_exception
|
||||
* @covers \qtype_calculated
|
||||
*/
|
||||
public function test_grading_of_negative_responses(): void {
|
||||
global $DB;
|
||||
|
||||
$this->resetAfterTest();
|
||||
|
||||
$qtype = new qtype_calculated();
|
||||
|
||||
// Create a question.
|
||||
$q = \test_question_maker::get_question_data('calculated', 'mult');
|
||||
$q->id = 99;
|
||||
|
||||
// Add units for the question. The issue to test only applies if the answer contains a unit string.
|
||||
$units = [];
|
||||
$unit = new \stdClass();
|
||||
$unit->question = $q->id;
|
||||
$unit->multiplier = 1.0;
|
||||
$unit->unit = "cm";
|
||||
$units[] = $unit;
|
||||
$DB->insert_records("question_numerical_units", $units);
|
||||
|
||||
$qtypeobj = question_bank::get_qtype($qtype->name());
|
||||
$fakedata = ["a" => "5.7", "b" => "3.3"];
|
||||
|
||||
$result = $qtype->comment_on_datasetitems($qtypeobj, $q->id, $q->questiontext, $q->options->answers, $fakedata, 1);
|
||||
|
||||
// Make sure "ERROR" is not part of the answers.
|
||||
foreach ($result->stranswers as $answer) {
|
||||
$this->assertFalse(strstr($answer, "ERROR"), "Assert that 'ERROR' is not part of the answer!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user