PageRenderTime 44ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 1ms

/question/type/calculated/datasetitems_form.php

https://bitbucket.org/moodle/moodle
PHP | 528 lines | 420 code | 46 blank | 62 comment | 72 complexity | 7c7a2847f351ad3728f19716d472898d MD5 | raw file
Possible License(s): Apache-2.0, LGPL-2.1, BSD-3-Clause, MIT, GPL-3.0
  1. <?php
  2. // This file is part of Moodle - http://moodle.org/
  3. //
  4. // Moodle is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // Moodle is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
  16. /**
  17. * Defines the editing form for the calculated question data set items.
  18. *
  19. * @package qtype
  20. * @subpackage calculated
  21. * @copyright 2007 Jamie Pratt me@jamiep.org
  22. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23. */
  24. defined('MOODLE_INTERNAL') || die();
  25. require_once($CFG->dirroot . '/question/type/edit_question_form.php');
  26. /**
  27. * Calculated question data set items editing form definition.
  28. *
  29. * @copyright 2007 Jamie Pratt me@jamiep.org
  30. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31. */
  32. class question_dataset_dependent_items_form extends question_wizard_form {
  33. /**
  34. * Question object with options and answers already loaded by get_question_options
  35. * Be careful how you use this it is needed sometimes to set up the structure of the
  36. * form in definition_inner but data is always loaded into the form with set_defaults.
  37. *
  38. * @var object
  39. */
  40. public $question;
  41. /**
  42. * Reference to question type object
  43. *
  44. * @var question_dataset_dependent_questiontype
  45. */
  46. public $qtypeobj;
  47. /** @var stdClass the question category. */
  48. protected $category;
  49. /** @var context the context of the question category. */
  50. protected $categorycontext;
  51. public $datasetdefs;
  52. public $maxnumber = -1;
  53. public $regenerate;
  54. public $noofitems;
  55. public $outsidelimit = false;
  56. public $commentanswers = array();
  57. /**
  58. * Add question-type specific form fields.
  59. *
  60. * @param MoodleQuickForm $mform the form being built.
  61. */
  62. public function __construct($submiturl, $question, $regenerate) {
  63. global $SESSION, $CFG, $DB;
  64. $this->regenerate = $regenerate;
  65. $this->question = $question;
  66. $this->qtypeobj = question_bank::get_qtype($this->question->qtype);
  67. // Validate the question category.
  68. if (!$category = $DB->get_record('question_categories',
  69. array('id' => $question->category))) {
  70. print_error('categorydoesnotexist', 'question', $returnurl);
  71. }
  72. $this->category = $category;
  73. $this->categorycontext = context::instance_by_id($category->contextid);
  74. // Get the dataset defintions for this question.
  75. if (empty($question->id)) {
  76. $this->datasetdefs = $this->qtypeobj->get_dataset_definitions(
  77. $question->id, $SESSION->calculated->definitionform->dataset);
  78. } else {
  79. if (empty($question->options)) {
  80. $this->get_question_options($question);
  81. }
  82. $this->datasetdefs = $this->qtypeobj->get_dataset_definitions(
  83. $question->id, array());
  84. }
  85. foreach ($this->datasetdefs as $datasetdef) {
  86. // Get maxnumber.
  87. if ($this->maxnumber == -1 || $datasetdef->itemcount < $this->maxnumber) {
  88. $this->maxnumber = $datasetdef->itemcount;
  89. }
  90. }
  91. foreach ($this->datasetdefs as $defid => $datasetdef) {
  92. if (isset($datasetdef->id)) {
  93. $this->datasetdefs[$defid]->items =
  94. $this->qtypeobj->get_database_dataset_items($datasetdef->id);
  95. }
  96. }
  97. parent::__construct($submiturl);
  98. }
  99. protected function definition() {
  100. global $PAGE;
  101. $labelsharedwildcard = get_string("sharedwildcard", "qtype_calculated");
  102. $mform = $this->_form;
  103. $mform->setDisableShortforms();
  104. $strquestionlabel = $this->qtypeobj->comment_header($this->question);
  105. if ($this->maxnumber != -1 ) {
  106. $this->noofitems = $this->maxnumber;
  107. } else {
  108. $this->noofitems = 0;
  109. }
  110. $label = get_string("sharedwildcards", "qtype_calculated");
  111. $html2 = $this->qtypeobj->print_dataset_definitions_category_shared(
  112. $this->question, $this->datasetdefs);
  113. $mform->addElement('static', 'listcategory', $label, $html2);
  114. // ...----------------------------------------------------------------------.
  115. $mform->addElement('submit', 'updatedatasets',
  116. get_string('updatedatasetparam', 'qtype_calculated'));
  117. $mform->registerNoSubmitButton('updatedatasets');
  118. $mform->addElement('header', 'additemhdr',
  119. get_string('itemtoadd', 'qtype_calculated'));
  120. $idx = 1;
  121. $data = array();
  122. $j = (($this->noofitems) * count($this->datasetdefs))+1;
  123. foreach ($this->datasetdefs as $defkey => $datasetdef) {
  124. if ($datasetdef->category |= 0 ) {
  125. $name = get_string('sharedwildcard', 'qtype_calculated', $datasetdef->name);
  126. } else {
  127. $name = get_string('wildcard', 'qtype_calculated', $datasetdef->name);
  128. }
  129. $mform->addElement('float', "number[{$j}]", $name);
  130. $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j);
  131. $idx++;
  132. $mform->addElement('hidden', "definition[{$j}]");
  133. $mform->setType("definition[{$j}]", PARAM_RAW);
  134. $mform->addElement('hidden', "itemid[{$j}]");
  135. $mform->setType("itemid[{$j}]", PARAM_RAW);
  136. $mform->addElement('static', "divider[{$j}]", '', '<hr />');
  137. $mform->setType("divider[{$j}]", PARAM_RAW);
  138. $j++;
  139. }
  140. $mform->addElement('header', 'updateanswershdr',
  141. get_string('answerstoleranceparam', 'qtype_calculated'));
  142. $mform->addElement('submit', 'updateanswers',
  143. get_string('updatetolerancesparam', 'qtype_calculated'));
  144. $mform->setAdvanced('updateanswers', true);
  145. $mform->registerNoSubmitButton('updateanswers');
  146. $answers = fullclone($this->question->options->answers);
  147. $key1 =1;
  148. foreach ($answers as $key => $answer) {
  149. $ans = shorten_text($answer->answer, 17, true);
  150. if ($ans === '*') {
  151. $mform->addElement('static',
  152. 'answercomment[' . ($this->noofitems+$key1) . ']', $ans);
  153. $mform->addElement('hidden', 'tolerance['.$key.']', '');
  154. $mform->setType('tolerance['.$key.']', PARAM_FLOAT); // No need to worry about localisation, as the value of this field will not be shown to users anymore.
  155. $mform->setAdvanced('tolerance['.$key.']', true);
  156. $mform->addElement('hidden', 'tolerancetype['.$key.']', '');
  157. $mform->setType('tolerancetype['.$key.']', PARAM_RAW);
  158. $mform->setAdvanced('tolerancetype['.$key.']', true);
  159. $mform->addElement('hidden', 'correctanswerlength['.$key.']', '');
  160. $mform->setType('correctanswerlength['.$key.']', PARAM_RAW);
  161. $mform->setAdvanced('correctanswerlength['.$key.']', true);
  162. $mform->addElement('hidden', 'correctanswerformat['.$key.']', '');
  163. $mform->setType('correctanswerformat['.$key.']', PARAM_RAW);
  164. $mform->setAdvanced('correctanswerformat['.$key.']', true);
  165. } else if ( $ans !== '' ) {
  166. $mform->addElement('static', 'answercomment[' . ($this->noofitems+$key1) . ']',
  167. $ans);
  168. $mform->addElement('float', 'tolerance['.$key.']',
  169. get_string('tolerance', 'qtype_calculated'));
  170. $mform->setAdvanced('tolerance['.$key.']', true);
  171. $mform->addElement('select', 'tolerancetype['.$key.']',
  172. get_string('tolerancetype', 'qtype_numerical'),
  173. $this->qtypeobj->tolerance_types());
  174. $mform->setAdvanced('tolerancetype['.$key.']', true);
  175. $mform->addElement('select', 'correctanswerlength['.$key.']',
  176. get_string('correctanswershows', 'qtype_calculated'), range(0, 9));
  177. $mform->setAdvanced('correctanswerlength['.$key.']', true);
  178. $answerlengthformats = array(
  179. '1' => get_string('decimalformat', 'qtype_numerical'),
  180. '2' => get_string('significantfiguresformat', 'qtype_calculated')
  181. );
  182. $mform->addElement('select', 'correctanswerformat['.$key.']',
  183. get_string('correctanswershowsformat', 'qtype_calculated'),
  184. $answerlengthformats);
  185. $mform->setAdvanced('correctanswerformat['.$key.']', true);
  186. $mform->addElement('static', 'dividertolerance', '', '<hr />');
  187. $mform->setAdvanced('dividertolerance', true);
  188. }
  189. $key1++;
  190. }
  191. $addremoveoptions = array();
  192. $addremoveoptions['1']='1';
  193. for ($i=10; $i<=100; $i+=10) {
  194. $addremoveoptions["{$i}"] = "{$i}";
  195. }
  196. $showoptions = Array();
  197. $showoptions['1']='1';
  198. $showoptions['2']='2';
  199. $showoptions['5']='5';
  200. for ($i=10; $i<=100; $i+=10) {
  201. $showoptions["{$i}"] = "{$i}";
  202. }
  203. $mform->addElement('header', 'addhdr', get_string('add', 'moodle'));
  204. $mform->closeHeaderBefore('addhdr');
  205. if ($this->qtypeobj->supports_dataset_item_generation()) {
  206. $radiogrp = array();
  207. $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]',
  208. null, get_string('reuseifpossible', 'qtype_calculated'), 0);
  209. $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]',
  210. null, get_string('forceregenerationshared', 'qtype_calculated'), 1);
  211. $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]',
  212. null, get_string('forceregenerationall', 'qtype_calculated'), 2);
  213. $mform->addGroup($radiogrp, 'forceregenerationgrp',
  214. get_string('nextitemtoadd', 'qtype_calculated'), "<br/>", false);
  215. }
  216. $mform->addElement('submit', 'getnextbutton', get_string('getnextnow', 'qtype_calculated'));
  217. $mform->addElement('static', "dividera", '', '<hr />');
  218. $addgrp = array();
  219. $addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('add', 'moodle'));
  220. $addgrp[] =& $mform->createElement('select', "selectadd",
  221. get_string('additem', 'qtype_calculated'), $addremoveoptions);
  222. $addgrp[] = & $mform->createElement('static', "stat", "Items",
  223. get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
  224. $mform->addGroup($addgrp, 'addgrp', get_string('additem', 'qtype_calculated'), ' ', false);
  225. $mform->addElement('static', "divideradd", '', '');
  226. if ($this->noofitems > 0) {
  227. $mform->addElement('header', 'deleteitemhdr', get_string('delete', 'moodle'));
  228. $deletegrp = array();
  229. $deletegrp[] = $mform->createElement('submit', 'deletebutton',
  230. get_string('delete', 'moodle'));
  231. $deletegrp[] = $mform->createElement('select', 'selectdelete',
  232. get_string('deleteitem', 'qtype_calculated')."1", $addremoveoptions);
  233. $deletegrp[] = $mform->createElement('static', "stat", "Items",
  234. get_string('setwildcardvalues', 'qtype_calculatedsimple'));
  235. $mform->addGroup($deletegrp, 'deletegrp', '', ' ', false);
  236. } else {
  237. $mform->addElement('static', 'warning', '', '<span class="error">' .
  238. get_string('youmustaddatleastoneitem', 'qtype_calculated').'</span>');
  239. }
  240. $addgrp1 = array();
  241. $addgrp1[] = $mform->createElement('submit', 'showbutton',
  242. get_string('showitems', 'qtype_calculated'));
  243. $addgrp1[] = $mform->createElement('select', "selectshow", '' , $showoptions);
  244. $addgrp1[] = $mform->createElement('static', "stat", '',
  245. get_string('setwildcardvalues', 'qtype_calculated'));
  246. $mform->addGroup($addgrp1, 'addgrp1', '', ' ', false);
  247. $mform->registerNoSubmitButton('showbutton');
  248. $mform->closeHeaderBefore('addgrp1');
  249. // ...----------------------------------------------------------------------.
  250. $j = $this->noofitems * count($this->datasetdefs);
  251. $k = optional_param('selectshow', 1, PARAM_INT);
  252. for ($i = $this->noofitems; $i >= 1; $i--) {
  253. if ($k > 0) {
  254. $mform->addElement('header', 'setnoheader' . $i, "<b>" .
  255. get_string('setno', 'qtype_calculated', $i)."</b>&nbsp;&nbsp;");
  256. }
  257. foreach ($this->datasetdefs as $defkey => $datasetdef) {
  258. if ($k > 0) {
  259. if ($datasetdef->category == 0 ) {
  260. $mform->addElement('float', "number[{$j}]",
  261. get_string('wildcard', 'qtype_calculated', $datasetdef->name));
  262. } else {
  263. $mform->addElement('float', "number[{$j}]", get_string(
  264. 'sharedwildcard', 'qtype_calculated', $datasetdef->name));
  265. }
  266. } else {
  267. $mform->addElement('hidden', "number[{$j}]" , '');
  268. $mform->setType("number[{$j}]", PARAM_LOCALISEDFLOAT); // Localisation handling has to be done manually.
  269. }
  270. $mform->addElement('hidden', "itemid[{$j}]");
  271. $mform->setType("itemid[{$j}]", PARAM_INT);
  272. $mform->addElement('hidden', "definition[{$j}]");
  273. $mform->setType("definition[{$j}]", PARAM_NOTAGS);
  274. $data[$datasetdef->name] =$datasetdef->items[$i]->value;
  275. $j--;
  276. }
  277. if ('' != $strquestionlabel && ($k > 0 )) {
  278. // ... $this->outsidelimit || !empty($this->numbererrors ).
  279. $repeated[] = $mform->addElement('static', "answercomment[{$i}]", $strquestionlabel);
  280. // Decode equations in question text.
  281. $qtext = $this->qtypeobj->substitute_variables(
  282. $this->question->questiontext, $data);
  283. $textequations = $this->qtypeobj->find_formulas($qtext);
  284. if ($textequations != '' && count($textequations) > 0 ) {
  285. $mform->addElement('static', "divider1[{$j}]", '',
  286. 'Formulas {=..} in question text');
  287. foreach ($textequations as $key => $equation) {
  288. if ($formulaerrors = qtype_calculated_find_formula_errors($equation)) {
  289. $str = $formulaerrors;
  290. } else {
  291. eval('$str = '.$equation.';');
  292. }
  293. $equation = shorten_text($equation, 17, true);
  294. $mform->addElement('static', "textequation", "{={$equation}}", "=".$str);
  295. }
  296. }
  297. }
  298. $k--;
  299. }
  300. $mform->addElement('static', 'outsidelimit', '', '');
  301. // Submit buttons.
  302. if ($this->noofitems > 0) {
  303. $buttonarray = [];
  304. $buttonarray[] = $mform->createElement(
  305. 'submit', 'savechanges', get_string('savechanges'));
  306. if (\core\plugininfo\qbank::is_plugin_enabled('qbank_previewquestion')) {
  307. $previewlink = $PAGE->get_renderer('qbank_previewquestion')->question_preview_link($this->question->id,
  308. $this->categorycontext, true);
  309. }
  310. $buttonarray[] = $mform->createElement('static', 'previewlink', '', $previewlink);
  311. $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
  312. $mform->closeHeaderBefore('buttonar');
  313. }
  314. $this->add_hidden_fields();
  315. $mform->addElement('hidden', 'category');
  316. $mform->setType('category', PARAM_SEQUENCE);
  317. $mform->addElement('hidden', 'wizard', 'datasetitems');
  318. $mform->setType('wizard', PARAM_ALPHA);
  319. }
  320. public function set_data($question) {
  321. $formdata = array();
  322. $fromform = new stdClass();
  323. if (isset($question->options)) {
  324. $answers = $question->options->answers;
  325. if (count($answers)) {
  326. if (optional_param('updateanswers', false, PARAM_BOOL) ||
  327. optional_param('updatedatasets', false, PARAM_BOOL)) {
  328. foreach ($answers as $key => $answer) {
  329. $fromform->tolerance[$key]= $this->_form->getElementValue(
  330. 'tolerance['.$key.']');
  331. $answer->tolerance = $fromform->tolerance[$key];
  332. $fromform->tolerancetype[$key]= $this->_form->getElementValue(
  333. 'tolerancetype['.$key.']');
  334. if (is_array($fromform->tolerancetype[$key])) {
  335. $fromform->tolerancetype[$key]= $fromform->tolerancetype[$key][0];
  336. }
  337. $answer->tolerancetype = $fromform->tolerancetype[$key];
  338. $fromform->correctanswerlength[$key]= $this->_form->getElementValue(
  339. 'correctanswerlength['.$key.']');
  340. if (is_array($fromform->correctanswerlength[$key])) {
  341. $fromform->correctanswerlength[$key] =
  342. $fromform->correctanswerlength[$key][0];
  343. }
  344. $answer->correctanswerlength = $fromform->correctanswerlength[$key];
  345. $fromform->correctanswerformat[$key] = $this->_form->getElementValue(
  346. 'correctanswerformat['.$key.']');
  347. if (is_array($fromform->correctanswerformat[$key])) {
  348. $fromform->correctanswerformat[$key] =
  349. $fromform->correctanswerformat[$key][0];
  350. }
  351. $answer->correctanswerformat = $fromform->correctanswerformat[$key];
  352. }
  353. $this->qtypeobj->save_question_calculated($question, $fromform);
  354. } else {
  355. foreach ($answers as $key => $answer) {
  356. $formdata['tolerance['.$key.']'] = $answer->tolerance;
  357. $formdata['tolerancetype['.$key.']'] = $answer->tolerancetype;
  358. $formdata['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
  359. $formdata['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
  360. }
  361. }
  362. }
  363. }
  364. // Fill out all data sets and also the fields for the next item to add.
  365. $j = $this->noofitems * count($this->datasetdefs);
  366. for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--) {
  367. $data = array();
  368. foreach ($this->datasetdefs as $defid => $datasetdef) {
  369. if (isset($datasetdef->items[$itemnumber])) {
  370. $value = $datasetdef->items[$itemnumber]->value;
  371. if ($this->_form->getElementType("number[{$j}]") == 'hidden') {
  372. // Some of the number elements are from the float type and some are from the hidden type.
  373. // We need to manually handle localised floats for hidden elements.
  374. $value = format_float($value, -1);
  375. }
  376. $formdata["number[{$j}]"] = $value;
  377. $formdata["definition[{$j}]"] = $defid;
  378. $formdata["itemid[{$j}]"] = $datasetdef->items[$itemnumber]->id;
  379. $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
  380. }
  381. $j--;
  382. }
  383. $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $question->id,
  384. $question->questiontext, $answers, $data, $itemnumber);
  385. if ($comment->outsidelimit) {
  386. $this->outsidelimit=$comment->outsidelimit;
  387. }
  388. $totalcomment='';
  389. foreach ($question->options->answers as $key => $answer) {
  390. $totalcomment .= $comment->stranswers[$key].'<br/>';
  391. }
  392. $formdata['answercomment['.$itemnumber.']'] = $totalcomment;
  393. }
  394. $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
  395. $formdata['selectdelete'] = '1';
  396. $formdata['selectadd'] = '1';
  397. $j = $this->noofitems * count($this->datasetdefs)+1;
  398. $data = array(); // Data for comment_on_datasetitems later.
  399. // Dataset generation defaults.
  400. if ($this->qtypeobj->supports_dataset_item_generation()) {
  401. $itemnumber = $this->noofitems+1;
  402. foreach ($this->datasetdefs as $defid => $datasetdef) {
  403. if (!optional_param('updatedatasets', false, PARAM_BOOL) &&
  404. !optional_param('updateanswers', false, PARAM_BOOL)) {
  405. $value = $this->qtypeobj->generate_dataset_item($datasetdef->options);
  406. } else {
  407. $value = $this->_form->getElementValue("number[{$j}]");
  408. }
  409. if ($this->_form->getElementType("number[{$j}]") == 'hidden') {
  410. // Some of the number elements are from the float type and some are from the hidden type.
  411. // We need to manually handle localised floats for hidden elements.
  412. $value = format_float($value, -1);
  413. }
  414. $formdata["number[{$j}]"] = $value;
  415. $formdata["definition[{$j}]"] = $defid;
  416. $formdata["itemid[{$j}]"] = isset($datasetdef->items[$itemnumber]) ?
  417. $datasetdef->items[$itemnumber]->id : 0;
  418. $data[$datasetdef->name] = $formdata["number[{$j}]"];
  419. $j++;
  420. }
  421. }
  422. // Existing records override generated data depending on radio element.
  423. $j = $this->noofitems * count($this->datasetdefs) + 1;
  424. if (!$this->regenerate && !optional_param('updatedatasets', false, PARAM_BOOL) &&
  425. !optional_param('updateanswers', false, PARAM_BOOL)) {
  426. $itemnumber = $this->noofitems + 1;
  427. foreach ($this->datasetdefs as $defid => $datasetdef) {
  428. if (isset($datasetdef->items[$itemnumber])) {
  429. $formdata["number[{$j}]"] = $datasetdef->items[$itemnumber]->value;
  430. $formdata["definition[{$j}]"] = $defid;
  431. $formdata["itemid[{$j}]"] = $datasetdef->items[$itemnumber]->id;
  432. $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
  433. }
  434. $j++;
  435. }
  436. }
  437. $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $question->id,
  438. $question->questiontext, $answers, $data, ($this->noofitems + 1));
  439. if (isset($comment->outsidelimit) && $comment->outsidelimit) {
  440. $this->outsidelimit=$comment->outsidelimit;
  441. }
  442. $key1 = 1;
  443. foreach ($question->options->answers as $key => $answer) {
  444. $formdata['answercomment['.($this->noofitems+$key1).']'] = $comment->stranswers[$key];
  445. $key1++;
  446. }
  447. if ($this->outsidelimit) {
  448. $formdata['outsidelimit']= '<span class="error">' .
  449. get_string('oneanswertrueansweroutsidelimits', 'qtype_calculated') . '</span>';
  450. }
  451. $formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
  452. parent::set_data((object)($formdata + (array)$question));
  453. }
  454. public function validation($data, $files) {
  455. $errors = array();
  456. if (isset($data['savechanges']) && ($this->noofitems==0) ) {
  457. $errors['warning'] = get_string('warning', 'mnet');
  458. }
  459. if ($this->outsidelimit) {
  460. $errors['outsidelimits'] =
  461. get_string('oneanswertrueansweroutsidelimits', 'qtype_calculated');
  462. }
  463. $numbers = $data['number'];
  464. foreach ($numbers as $key => $number) {
  465. if (! is_numeric($number)) {
  466. if (stristr($number, ',')) {
  467. $errors['number['.$key.']'] = get_string('nocommaallowed', 'qtype_calculated');
  468. } else {
  469. $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
  470. }
  471. } else if (stristr($number, 'x')) {
  472. $a = new stdClass();
  473. $a->name = '';
  474. $a->value = $number;
  475. $errors['number['.$key.']'] = get_string('hexanotallowed', 'qtype_calculated', $a);
  476. } else if (is_nan($number)) {
  477. $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
  478. }
  479. }
  480. return $errors;
  481. }
  482. }