PageRenderTime 79ms CodeModel.GetById 26ms RepoModel.GetById 1ms app.codeStats 0ms

/question/type/calculated/edit_calculated_form.php

https://bitbucket.org/synergylearning/campusconnect
PHP | 282 lines | 180 code | 42 blank | 60 comment | 16 complexity | 945d0eae0ea50e3e6e9d27c07cb96ead 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 type.
  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/numerical/edit_numerical_form.php');
  26. /**
  27. * Calculated question type 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 qtype_calculated_edit_form extends qtype_numerical_edit_form {
  33. /**
  34. * Handle to the question type for this question.
  35. *
  36. * @var qtype_calculated
  37. */
  38. public $qtypeobj;
  39. public $questiondisplay;
  40. public $activecategory;
  41. public $categorychanged = false;
  42. public $initialname = '';
  43. public $reload = false;
  44. public function __construct($submiturl, $question, $category, $contexts,
  45. $formeditable = true) {
  46. global $CFG, $DB;
  47. $this->question = $question;
  48. $this->reload = optional_param('reload', false, PARAM_BOOL);
  49. if (!$this->reload) { // Use database data as this is first pass.
  50. if (isset($this->question->id)) {
  51. // Remove prefix #{..}# if exists.
  52. $this->initialname = $question->name;
  53. $regs= array();
  54. if (preg_match('~#\{([^[:space:]]*)#~', $question->name , $regs)) {
  55. $question->name = str_replace($regs[0], '', $question->name);
  56. };
  57. }
  58. }
  59. parent::__construct($submiturl, $question, $category, $contexts, $formeditable);
  60. }
  61. public function get_per_answer_fields($mform, $label, $gradeoptions,
  62. &$repeatedoptions, &$answersoption) {
  63. $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions,
  64. $repeatedoptions, $answersoption);
  65. // Reorganise answer options group. 0 is the answer. 1 is tolerance. 2 is Grade.
  66. $answeroptions = $repeated[0]->getElements();
  67. // Tolerance field will be part of its own group.
  68. $tolerance = $answeroptions[1];
  69. // Update Answer options group to contain only answer and grade fields.
  70. $answeroptions[0]->setSize(55);
  71. $answeroptions = array($answeroptions[0], $answeroptions[2]);
  72. $repeated[0]->setElements($answeroptions);
  73. // Update answer field and group label.
  74. $repeated[0]->setLabel(get_string('answerformula', 'qtype_calculated', '{no}') . ' =');
  75. $answeroptions[0]->setLabel(get_string('answerformula', 'qtype_calculated', '{no}') . ' =');
  76. // Get feedback field to re append later.
  77. $feedback = array_pop($repeated);
  78. // Create tolerance group.
  79. $answertolerance = array();
  80. $tolerance->setLabel(get_string('tolerance', 'qtype_calculated') . '=');
  81. $answertolerance[] = $tolerance;
  82. $answertolerance[] = $mform->createElement('select', 'tolerancetype',
  83. get_string('tolerancetype', 'qtype_calculated'), $this->qtypeobj->tolerance_types());
  84. $repeated[] = $mform->createElement('group', 'answertolerance',
  85. get_string('tolerance', 'qtype_calculated'), $answertolerance, null, false);
  86. $repeatedoptions['tolerance']['default'] = 0.01;
  87. // Create display group.
  88. $answerdisplay = array();
  89. $answerdisplay[] = $mform->createElement('select', 'correctanswerlength',
  90. get_string('answerdisplay', 'qtype_calculated'), range(0, 9));
  91. $repeatedoptions['correctanswerlength']['default'] = 2;
  92. $answerlengthformats = array(
  93. '1' => get_string('decimalformat', 'qtype_numerical'),
  94. '2' => get_string('significantfiguresformat', 'qtype_calculated')
  95. );
  96. $answerdisplay[] = $mform->createElement('select', 'correctanswerformat',
  97. get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
  98. $repeated[] = $mform->createElement('group', 'answerdisplay',
  99. get_string('answerdisplay', 'qtype_calculated'), $answerdisplay, null, false);
  100. // Add feedback.
  101. $repeated[] = $feedback;
  102. return $repeated;
  103. }
  104. /**
  105. * Add question-type specific form fields.
  106. *
  107. * @param MoodleQuickForm $mform the form being built.
  108. */
  109. protected function definition_inner($mform) {
  110. $this->qtypeobj = question_bank::get_qtype($this->qtype());
  111. $label = get_string('sharedwildcards', 'qtype_calculated');
  112. $mform->addElement('hidden', 'initialcategory', 1);
  113. $mform->addElement('hidden', 'reload', 1);
  114. $mform->setType('initialcategory', PARAM_INT);
  115. $mform->setType('reload', PARAM_BOOL);
  116. $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question);
  117. $mform->insertElementBefore(
  118. $mform->createElement('static', 'listcategory', $label, $html2), 'name');
  119. if (isset($this->question->id)) {
  120. $mform->insertElementBefore($mform->createElement('static', 'initialname',
  121. get_string('questionstoredname', 'qtype_calculated'),
  122. $this->initialname), 'name');
  123. };
  124. $addfieldsname = 'updatecategory';
  125. $addstring = get_string('updatecategory', 'qtype_calculated');
  126. $mform->registerNoSubmitButton($addfieldsname);
  127. $mform->insertElementBefore(
  128. $mform->createElement('submit', $addfieldsname, $addstring), 'listcategory');
  129. $mform->registerNoSubmitButton('createoptionbutton');
  130. // Editing as regular question.
  131. $mform->setType('single', PARAM_INT);
  132. $mform->addElement('hidden', 'shuffleanswers', '1');
  133. $mform->setType('shuffleanswers', PARAM_INT);
  134. $mform->addElement('hidden', 'answernumbering', 'abc');
  135. $mform->setType('answernumbering', PARAM_SAFEDIR);
  136. $this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'),
  137. question_bank::fraction_options(), 1, 1);
  138. $repeated = array();
  139. $this->add_unit_options($mform, $this);
  140. $this->add_unit_fields($mform, $this);
  141. $this->add_interactive_settings();
  142. // Hidden elements.
  143. $mform->addElement('hidden', 'synchronize', '');
  144. $mform->setType('synchronize', PARAM_INT);
  145. $mform->addElement('hidden', 'wizard', 'datasetdefinitions');
  146. $mform->setType('wizard', PARAM_ALPHA);
  147. }
  148. public function data_preprocessing($question) {
  149. $question = parent::data_preprocessing($question);
  150. $question = $this->data_preprocessing_answers($question);
  151. $question = $this->data_preprocessing_hints($question);
  152. $question = $this->data_preprocessing_units($question);
  153. $question = $this->data_preprocessing_unit_options($question);
  154. if (isset($question->options->synchronize)) {
  155. $question->synchronize = $question->options->synchronize;
  156. }
  157. return $question;
  158. }
  159. protected function data_preprocessing_answers($question, $withanswerfiles = false) {
  160. $question = parent::data_preprocessing_answers($question, $withanswerfiles);
  161. if (empty($question->options->answers)) {
  162. return $question;
  163. }
  164. $key = 0;
  165. foreach ($question->options->answers as $answer) {
  166. // See comment in the parent method about this hack.
  167. unset($this->_form->_defaultValues["tolerancetype[$key]"]);
  168. unset($this->_form->_defaultValues["correctanswerlength[$key]"]);
  169. unset($this->_form->_defaultValues["correctanswerformat[$key]"]);
  170. $question->tolerancetype[$key] = $answer->tolerancetype;
  171. $question->correctanswerlength[$key] = $answer->correctanswerlength;
  172. $question->correctanswerformat[$key] = $answer->correctanswerformat;
  173. $key++;
  174. }
  175. return $question;
  176. }
  177. public function qtype() {
  178. return 'calculated';
  179. }
  180. /**
  181. * Validate the equations in the some question content.
  182. * @param array $errors where errors are being accumulated.
  183. * @param string $field the field being validated.
  184. * @param string $text the content of that field.
  185. * @return array the updated $errors array.
  186. */
  187. protected function validate_text($errors, $field, $text) {
  188. $problems = qtype_calculated_find_formula_errors_in_text($text);
  189. if ($problems) {
  190. $errors[$field] = $problems;
  191. }
  192. return $errors;
  193. }
  194. public function validation($data, $files) {
  195. $errors = parent::validation($data, $files);
  196. // Verifying for errors in {=...} in question text.
  197. $errors = $this->validate_text($errors, 'questiontext', $data['questiontext']['text']);
  198. $errors = $this->validate_text($errors, 'generalfeedback', $data['generalfeedback']['text']);
  199. // Check that the answers use datasets.
  200. $answers = $data['answer'];
  201. $mandatorydatasets = array();
  202. foreach ($answers as $key => $answer) {
  203. $problems = qtype_calculated_find_formula_errors($answer);
  204. if ($problems) {
  205. $errors['answeroptions['.$key.']'] = $problems;
  206. }
  207. $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
  208. $errors = $this->validate_text($errors, 'feedback[' . $key . ']',
  209. $data['feedback'][$key]['text']);
  210. }
  211. if (empty($mandatorydatasets)) {
  212. foreach ($answers as $key => $answer) {
  213. $errors['answeroptions['.$key.']'] =
  214. get_string('atleastonewildcard', 'qtype_calculated');
  215. }
  216. }
  217. // Validate the answer format.
  218. foreach ($answers as $key => $answer) {
  219. $trimmedanswer = trim($answer);
  220. if (trim($answer)) {
  221. if ($data['correctanswerformat'][$key] == 2 &&
  222. $data['correctanswerlength'][$key] == '0') {
  223. $errors['answerdisplay['.$key.']'] =
  224. get_string('zerosignificantfiguresnotallowed', 'qtype_calculated');
  225. }
  226. }
  227. }
  228. return $errors;
  229. }
  230. protected function is_valid_answer($answer, $data) {
  231. return !qtype_calculated_find_formula_errors($answer);
  232. }
  233. protected function valid_answer_message($answer) {
  234. if (!$answer) {
  235. return get_string('mustenteraformulaorstar', 'qtype_numerical');
  236. } else {
  237. return qtype_calculated_find_formula_errors($answer);
  238. }
  239. }
  240. }