PageRenderTime 50ms CodeModel.GetById 18ms RepoModel.GetById 0ms app.codeStats 0ms

/question/type/calculated/datasetitems_form.php

https://bitbucket.org/synergylearning/campusconnect
PHP | 503 lines | 405 code | 41 blank | 57 comment | 67 complexity | b4a5b64aed03b8f06563bac0e0ff3075 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception, LGPL-3.0, GPL-3.0, LGPL-2.1, Apache-2.0, BSD-3-Clause, AGPL-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. public $datasetdefs;
  48. public $maxnumber = -1;
  49. public $regenerate;
  50. public $noofitems;
  51. public $outsidelimit = false;
  52. public $commentanswers = array();
  53. /**
  54. * Add question-type specific form fields.
  55. *
  56. * @param MoodleQuickForm $mform the form being built.
  57. */
  58. public function __construct($submiturl, $question, $regenerate) {
  59. global $SESSION, $CFG, $DB;
  60. $this->regenerate = $regenerate;
  61. $this->question = $question;
  62. $this->qtypeobj = question_bank::get_qtype($this->question->qtype);
  63. // Validate the question category.
  64. if (!$category = $DB->get_record('question_categories',
  65. array('id' => $question->category))) {
  66. print_error('categorydoesnotexist', 'question', $returnurl);
  67. }
  68. $this->category = $category;
  69. $this->categorycontext = context::instance_by_id($category->contextid);
  70. // Get the dataset defintions for this question.
  71. if (empty($question->id)) {
  72. $this->datasetdefs = $this->qtypeobj->get_dataset_definitions(
  73. $question->id, $SESSION->calculated->definitionform->dataset);
  74. } else {
  75. if (empty($question->options)) {
  76. $this->get_question_options($question);
  77. }
  78. $this->datasetdefs = $this->qtypeobj->get_dataset_definitions(
  79. $question->id, array());
  80. }
  81. foreach ($this->datasetdefs as $datasetdef) {
  82. // Get maxnumber.
  83. if ($this->maxnumber == -1 || $datasetdef->itemcount < $this->maxnumber) {
  84. $this->maxnumber = $datasetdef->itemcount;
  85. }
  86. }
  87. foreach ($this->datasetdefs as $defid => $datasetdef) {
  88. if (isset($datasetdef->id)) {
  89. $this->datasetdefs[$defid]->items =
  90. $this->qtypeobj->get_database_dataset_items($datasetdef->id);
  91. }
  92. }
  93. parent::__construct($submiturl);
  94. }
  95. protected function definition() {
  96. $labelsharedwildcard = get_string("sharedwildcard", "qtype_calculated");
  97. $mform =& $this->_form;
  98. $mform->setDisableShortforms();
  99. $strquestionlabel = $this->qtypeobj->comment_header($this->question);
  100. if ($this->maxnumber != -1 ) {
  101. $this->noofitems = $this->maxnumber;
  102. } else {
  103. $this->noofitems = 0;
  104. }
  105. $label = get_string("sharedwildcards", "qtype_calculated");
  106. $html2 = $this->qtypeobj->print_dataset_definitions_category_shared(
  107. $this->question, $this->datasetdefs);
  108. $mform->addElement('static', 'listcategory', $label, $html2);
  109. // ...----------------------------------------------------------------------.
  110. $mform->addElement('submit', 'updatedatasets',
  111. get_string('updatedatasetparam', 'qtype_calculated'));
  112. $mform->registerNoSubmitButton('updatedatasets');
  113. $mform->addElement('header', 'additemhdr',
  114. get_string('itemtoadd', 'qtype_calculated'));
  115. $idx = 1;
  116. $data = array();
  117. $j = (($this->noofitems) * count($this->datasetdefs))+1;
  118. foreach ($this->datasetdefs as $defkey => $datasetdef) {
  119. if ($datasetdef->category |= 0 ) {
  120. $name = get_string('sharedwildcard', 'qtype_calculated', $datasetdef->name);
  121. } else {
  122. $name = get_string('wildcard', 'qtype_calculated', $datasetdef->name);
  123. }
  124. $mform->addElement('text', "number[$j]", $name);
  125. $mform->setType("number[$j]", PARAM_RAW); // This parameter will be validated in validation().
  126. $this->qtypeobj->custom_generator_tools_part($mform, $idx, $j);
  127. $idx++;
  128. $mform->addElement('hidden', "definition[$j]");
  129. $mform->setType("definition[$j]", PARAM_RAW);
  130. $mform->addElement('hidden', "itemid[$j]");
  131. $mform->setType("itemid[$j]", PARAM_RAW);
  132. $mform->addElement('static', "divider[$j]", '', '<hr />');
  133. $mform->setType("divider[$j]", PARAM_RAW);
  134. $j++;
  135. }
  136. $mform->addElement('header', 'updateanswershdr',
  137. get_string('answerstoleranceparam', 'qtype_calculated'));
  138. $mform->addElement('submit', 'updateanswers',
  139. get_string('updatetolerancesparam', 'qtype_calculated'));
  140. $mform->setAdvanced('updateanswers', true);
  141. $mform->registerNoSubmitButton('updateanswers');
  142. $answers = fullclone($this->question->options->answers);
  143. $key1 =1;
  144. foreach ($answers as $key => $answer) {
  145. $ans = shorten_text($answer->answer, 17, true);
  146. if ($ans === '*') {
  147. $mform->addElement('static',
  148. 'answercomment[' . ($this->noofitems+$key1) . ']', $ans);
  149. $mform->addElement('hidden', 'tolerance['.$key.']', '');
  150. $mform->setType('tolerance['.$key.']', PARAM_RAW);
  151. $mform->setAdvanced('tolerance['.$key.']', true);
  152. $mform->addElement('hidden', 'tolerancetype['.$key.']', '');
  153. $mform->setType('tolerancetype['.$key.']', PARAM_RAW);
  154. $mform->setAdvanced('tolerancetype['.$key.']', true);
  155. $mform->addElement('hidden', 'correctanswerlength['.$key.']', '');
  156. $mform->setType('correctanswerlength['.$key.']', PARAM_RAW);
  157. $mform->setAdvanced('correctanswerlength['.$key.']', true);
  158. $mform->addElement('hidden', 'correctanswerformat['.$key.']', '');
  159. $mform->setType('correctanswerformat['.$key.']', PARAM_RAW);
  160. $mform->setAdvanced('correctanswerformat['.$key.']', true);
  161. } else if ( $ans !== '' ) {
  162. $mform->addElement('static', 'answercomment[' . ($this->noofitems+$key1) . ']',
  163. $ans);
  164. $mform->addElement('text', 'tolerance['.$key.']',
  165. get_string('tolerance', 'qtype_calculated'));
  166. $mform->setType('tolerance['.$key.']', PARAM_RAW);
  167. $mform->setAdvanced('tolerance['.$key.']', true);
  168. $mform->addElement('select', 'tolerancetype['.$key.']',
  169. get_string('tolerancetype', 'qtype_numerical'),
  170. $this->qtypeobj->tolerance_types());
  171. $mform->setAdvanced('tolerancetype['.$key.']', true);
  172. $mform->addElement('select', 'correctanswerlength['.$key.']',
  173. get_string('correctanswershows', 'qtype_calculated'), range(0, 9));
  174. $mform->setAdvanced('correctanswerlength['.$key.']', true);
  175. $answerlengthformats = array(
  176. '1' => get_string('decimalformat', 'qtype_numerical'),
  177. '2' => get_string('significantfiguresformat', 'qtype_calculated')
  178. );
  179. $mform->addElement('select', 'correctanswerformat['.$key.']',
  180. get_string('correctanswershowsformat', 'qtype_calculated'),
  181. $answerlengthformats);
  182. $mform->setAdvanced('correctanswerformat['.$key.']', true);
  183. $mform->addElement('static', 'dividertolerance', '', '<hr />');
  184. $mform->setAdvanced('dividertolerance', true);
  185. }
  186. $key1++;
  187. }
  188. $addremoveoptions = array();
  189. $addremoveoptions['1']='1';
  190. for ($i=10; $i<=100; $i+=10) {
  191. $addremoveoptions["$i"]="$i";
  192. }
  193. $showoptions = Array();
  194. $showoptions['1']='1';
  195. $showoptions['2']='2';
  196. $showoptions['5']='5';
  197. for ($i=10; $i<=100; $i+=10) {
  198. $showoptions["$i"]="$i";
  199. }
  200. $mform->addElement('header', 'addhdr', get_string('add', 'moodle'));
  201. $mform->closeHeaderBefore('addhdr');
  202. if ($this->qtypeobj->supports_dataset_item_generation()) {
  203. $radiogrp = array();
  204. $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]',
  205. null, get_string('reuseifpossible', 'qtype_calculated'), 0);
  206. $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]',
  207. null, get_string('forceregenerationshared', 'qtype_calculated'), 1);
  208. $radiogrp[] =& $mform->createElement('radio', 'nextpageparam[forceregeneration]',
  209. null, get_string('forceregenerationall', 'qtype_calculated'), 2);
  210. $mform->addGroup($radiogrp, 'forceregenerationgrp',
  211. get_string('nextitemtoadd', 'qtype_calculated'), "<br/>", false);
  212. }
  213. $mform->addElement('submit', 'getnextbutton', get_string('getnextnow', 'qtype_calculated'));
  214. $mform->addElement('static', "dividera", '', '<hr />');
  215. $addgrp = array();
  216. $addgrp[] =& $mform->createElement('submit', 'addbutton', get_string('add', 'moodle'));
  217. $addgrp[] =& $mform->createElement('select', "selectadd",
  218. get_string('additem', 'qtype_calculated'), $addremoveoptions);
  219. $addgrp[] = & $mform->createElement('static', "stat", "Items",
  220. get_string('newsetwildcardvalues', 'qtype_calculatedsimple'));
  221. $mform->addGroup($addgrp, 'addgrp', get_string('additem', 'qtype_calculated'), ' ', false);
  222. $mform->addElement('static', "divideradd", '', '');
  223. if ($this->noofitems > 0) {
  224. $mform->addElement('header', 'deleteitemhdr', get_string('delete', 'moodle'));
  225. $deletegrp = array();
  226. $deletegrp[] = $mform->createElement('submit', 'deletebutton',
  227. get_string('delete', 'moodle'));
  228. $deletegrp[] = $mform->createElement('select', 'selectdelete',
  229. get_string('deleteitem', 'qtype_calculated')."1", $addremoveoptions);
  230. $deletegrp[] = $mform->createElement('static', "stat", "Items",
  231. get_string('setwildcardvalues', 'qtype_calculatedsimple'));
  232. $mform->addGroup($deletegrp, 'deletegrp', '', ' ', false);
  233. } else {
  234. $mform->addElement('static', 'warning', '', '<span class="error">' .
  235. get_string('youmustaddatleastoneitem', 'qtype_calculated').'</span>');
  236. }
  237. $addgrp1 = array();
  238. $addgrp1[] = $mform->createElement('submit', 'showbutton',
  239. get_string('showitems', 'qtype_calculated'));
  240. $addgrp1[] = $mform->createElement('select', "selectshow", '' , $showoptions);
  241. $addgrp1[] = $mform->createElement('static', "stat", '',
  242. get_string('setwildcardvalues', 'qtype_calculated'));
  243. $mform->addGroup($addgrp1, 'addgrp1', '', ' ', false);
  244. $mform->registerNoSubmitButton('showbutton');
  245. $mform->closeHeaderBefore('addgrp1');
  246. // ...----------------------------------------------------------------------.
  247. $j = $this->noofitems * count($this->datasetdefs);
  248. $k = optional_param('selectshow', 1, PARAM_INT);
  249. for ($i = $this->noofitems; $i >= 1; $i--) {
  250. if ($k > 0) {
  251. $mform->addElement('header', 'setnoheader' . $i, "<b>" .
  252. get_string('setno', 'qtype_calculated', $i)."</b>&nbsp;&nbsp;");
  253. }
  254. foreach ($this->datasetdefs as $defkey => $datasetdef) {
  255. if ($k > 0) {
  256. if ($datasetdef->category == 0 ) {
  257. $mform->addElement('text', "number[$j]",
  258. get_string('wildcard', 'qtype_calculated', $datasetdef->name));
  259. } else {
  260. $mform->addElement('text', "number[$j]", get_string(
  261. 'sharedwildcard', 'qtype_calculated', $datasetdef->name));
  262. }
  263. } else {
  264. $mform->addElement('hidden', "number[$j]" , '');
  265. }
  266. $mform->setType("number[$j]", PARAM_RAW); // This parameter will be validated in validation().
  267. $mform->addElement('hidden', "itemid[$j]");
  268. $mform->setType("itemid[$j]", PARAM_INT);
  269. $mform->addElement('hidden', "definition[$j]");
  270. $mform->setType("definition[$j]", PARAM_NOTAGS);
  271. $data[$datasetdef->name] =$datasetdef->items[$i]->value;
  272. $j--;
  273. }
  274. if ('' != $strquestionlabel && ($k > 0 )) {
  275. // ... $this->outsidelimit || !empty($this->numbererrors ).
  276. $repeated[] = $mform->addElement('static', "answercomment[$i]", $strquestionlabel);
  277. // Decode equations in question text.
  278. $qtext = $this->qtypeobj->substitute_variables(
  279. $this->question->questiontext, $data);
  280. $textequations = $this->qtypeobj->find_math_equations($qtext);
  281. if ($textequations != '' && count($textequations) > 0 ) {
  282. $mform->addElement('static', "divider1[$j]", '',
  283. 'Formulas {=..} in question text');
  284. foreach ($textequations as $key => $equation) {
  285. if ($formulaerrors = qtype_calculated_find_formula_errors($equation)) {
  286. $str = $formulaerrors;
  287. } else {
  288. eval('$str = '.$equation.';');
  289. }
  290. $equation = shorten_text($equation, 17, true);
  291. $mform->addElement('static', "textequation", "{=$equation}", "=".$str);
  292. }
  293. }
  294. }
  295. $k--;
  296. }
  297. $mform->addElement('static', 'outsidelimit', '', '');
  298. // ...----------------------------------------------------------------------
  299. // Non standard name for button element needed so not using add_action_buttons.
  300. if (!($this->noofitems==0) ) {
  301. $mform->addElement('submit', 'savechanges', get_string('savechanges'));
  302. $mform->closeHeaderBefore('savechanges');
  303. }
  304. $this->add_hidden_fields();
  305. $mform->addElement('hidden', 'category');
  306. $mform->setType('category', PARAM_SEQUENCE);
  307. $mform->addElement('hidden', 'wizard', 'datasetitems');
  308. $mform->setType('wizard', PARAM_ALPHA);
  309. }
  310. public function set_data($question) {
  311. $formdata = array();
  312. $fromform = new stdClass();
  313. if (isset($question->options)) {
  314. $answers = $question->options->answers;
  315. if (count($answers)) {
  316. if (optional_param('updateanswers', false, PARAM_BOOL) ||
  317. optional_param('updatedatasets', false, PARAM_BOOL)) {
  318. foreach ($answers as $key => $answer) {
  319. $fromform->tolerance[$key]= $this->_form->getElementValue(
  320. 'tolerance['.$key.']');
  321. $answer->tolerance = $fromform->tolerance[$key];
  322. $fromform->tolerancetype[$key]= $this->_form->getElementValue(
  323. 'tolerancetype['.$key.']');
  324. if (is_array($fromform->tolerancetype[$key])) {
  325. $fromform->tolerancetype[$key]= $fromform->tolerancetype[$key][0];
  326. }
  327. $answer->tolerancetype = $fromform->tolerancetype[$key];
  328. $fromform->correctanswerlength[$key]= $this->_form->getElementValue(
  329. 'correctanswerlength['.$key.']');
  330. if (is_array($fromform->correctanswerlength[$key])) {
  331. $fromform->correctanswerlength[$key] =
  332. $fromform->correctanswerlength[$key][0];
  333. }
  334. $answer->correctanswerlength = $fromform->correctanswerlength[$key];
  335. $fromform->correctanswerformat[$key] = $this->_form->getElementValue(
  336. 'correctanswerformat['.$key.']');
  337. if (is_array($fromform->correctanswerformat[$key])) {
  338. $fromform->correctanswerformat[$key] =
  339. $fromform->correctanswerformat[$key][0];
  340. }
  341. $answer->correctanswerformat = $fromform->correctanswerformat[$key];
  342. }
  343. $this->qtypeobj->save_question_calculated($question, $fromform);
  344. } else {
  345. foreach ($answers as $key => $answer) {
  346. $formdata['tolerance['.$key.']'] = $answer->tolerance;
  347. $formdata['tolerancetype['.$key.']'] = $answer->tolerancetype;
  348. $formdata['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
  349. $formdata['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
  350. }
  351. }
  352. }
  353. }
  354. // Fill out all data sets and also the fields for the next item to add.
  355. $j = $this->noofitems * count($this->datasetdefs);
  356. for ($itemnumber = $this->noofitems; $itemnumber >= 1; $itemnumber--) {
  357. $data = array();
  358. foreach ($this->datasetdefs as $defid => $datasetdef) {
  359. if (isset($datasetdef->items[$itemnumber])) {
  360. $formdata["number[$j]"] = $datasetdef->items[$itemnumber]->value;
  361. $formdata["definition[$j]"] = $defid;
  362. $formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
  363. $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
  364. }
  365. $j--;
  366. }
  367. $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $question->id,
  368. $question->questiontext, $answers, $data, $itemnumber);
  369. if ($comment->outsidelimit) {
  370. $this->outsidelimit=$comment->outsidelimit;
  371. }
  372. $totalcomment='';
  373. foreach ($question->options->answers as $key => $answer) {
  374. $totalcomment .= $comment->stranswers[$key].'<br/>';
  375. }
  376. $formdata['answercomment['.$itemnumber.']'] = $totalcomment;
  377. }
  378. $formdata['nextpageparam[forceregeneration]'] = $this->regenerate;
  379. $formdata['selectdelete'] = '1';
  380. $formdata['selectadd'] = '1';
  381. $j = $this->noofitems * count($this->datasetdefs)+1;
  382. $data = array(); // Data for comment_on_datasetitems later.
  383. // Dataset generation defaults.
  384. if ($this->qtypeobj->supports_dataset_item_generation()) {
  385. $itemnumber = $this->noofitems+1;
  386. foreach ($this->datasetdefs as $defid => $datasetdef) {
  387. if (!optional_param('updatedatasets', false, PARAM_BOOL) &&
  388. !optional_param('updateanswers', false, PARAM_BOOL)) {
  389. $formdata["number[$j]"] = $this->qtypeobj->generate_dataset_item(
  390. $datasetdef->options);
  391. } else {
  392. $formdata["number[$j]"] = $this->_form->getElementValue("number[$j]");
  393. }
  394. $formdata["definition[$j]"] = $defid;
  395. $formdata["itemid[$j]"] = isset($datasetdef->items[$itemnumber]) ?
  396. $datasetdef->items[$itemnumber]->id : 0;
  397. $data[$datasetdef->name] = $formdata["number[$j]"];
  398. $j++;
  399. }
  400. }
  401. // Existing records override generated data depending on radio element.
  402. $j = $this->noofitems * count($this->datasetdefs) + 1;
  403. if (!$this->regenerate && !optional_param('updatedatasets', false, PARAM_BOOL) &&
  404. !optional_param('updateanswers', false, PARAM_BOOL)) {
  405. $idx = 1;
  406. $itemnumber = $this->noofitems + 1;
  407. foreach ($this->datasetdefs as $defid => $datasetdef) {
  408. if (isset($datasetdef->items[$itemnumber])) {
  409. $formdata["number[$j]"] = $datasetdef->items[$itemnumber]->value;
  410. $formdata["definition[$j]"] = $defid;
  411. $formdata["itemid[$j]"] = $datasetdef->items[$itemnumber]->id;
  412. $data[$datasetdef->name] = $datasetdef->items[$itemnumber]->value;
  413. }
  414. $j++;
  415. }
  416. }
  417. $comment = $this->qtypeobj->comment_on_datasetitems($this->qtypeobj, $question->id,
  418. $question->questiontext, $answers, $data, ($this->noofitems + 1));
  419. if (isset($comment->outsidelimit) && $comment->outsidelimit) {
  420. $this->outsidelimit=$comment->outsidelimit;
  421. }
  422. $key1 = 1;
  423. foreach ($question->options->answers as $key => $answer) {
  424. $formdata['answercomment['.($this->noofitems+$key1).']'] = $comment->stranswers[$key];
  425. $key1++;
  426. }
  427. if ($this->outsidelimit) {
  428. $formdata['outsidelimit']= '<span class="error">' .
  429. get_string('oneanswertrueansweroutsidelimits', 'qtype_calculated') . '</span>';
  430. }
  431. $formdata = $this->qtypeobj->custom_generator_set_data($this->datasetdefs, $formdata);
  432. parent::set_data((object)($formdata + (array)$question));
  433. }
  434. public function validation($data, $files) {
  435. $errors = array();
  436. if (isset($data['savechanges']) && ($this->noofitems==0) ) {
  437. $errors['warning'] = get_string('warning', 'mnet');
  438. }
  439. if ($this->outsidelimit) {
  440. $errors['outsidelimits'] =
  441. get_string('oneanswertrueansweroutsidelimits', 'qtype_calculated');
  442. }
  443. $numbers = $data['number'];
  444. foreach ($numbers as $key => $number) {
  445. if (! is_numeric($number)) {
  446. if (stristr($number, ',')) {
  447. $errors['number['.$key.']'] = get_string('nocommaallowed', 'qtype_calculated');
  448. } else {
  449. $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
  450. }
  451. } else if (stristr($number, 'x')) {
  452. $a = new stdClass();
  453. $a->name = '';
  454. $a->value = $number;
  455. $errors['number['.$key.']'] = get_string('hexanotallowed', 'qtype_calculated', $a);
  456. } else if (is_nan($number)) {
  457. $errors['number['.$key.']'] = get_string('notvalidnumber', 'qtype_calculated');
  458. }
  459. }
  460. return $errors;
  461. }
  462. }