PageRenderTime 52ms CodeModel.GetById 22ms RepoModel.GetById 0ms app.codeStats 0ms

/question/type/calculatedsimple/questiontype.php

https://bitbucket.org/synergylearning/campusconnect
PHP | 301 lines | 210 code | 37 blank | 54 comment | 39 complexity | 0d1373c53a907100a236f035880a5317 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. * Question type class for the simple calculated question type.
  18. *
  19. * @package qtype
  20. * @subpackage calculatedsimple
  21. * @copyright 2009 Pierre Pichet
  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/calculated/questiontype.php');
  26. /**
  27. * The simple calculated question type.
  28. *
  29. * @copyright 2009 Pierre Pichet
  30. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  31. */
  32. class qtype_calculatedsimple extends qtype_calculated {
  33. // Used by the function custom_generator_tools.
  34. public $wizard_pages_number = 1;
  35. public function save_question_options($question) {
  36. global $CFG, $DB;
  37. $context = $question->context;
  38. // Make it impossible to save bad formulas anywhere.
  39. $this->validate_question_data($question);
  40. // Get old versions of the objects.
  41. if (!$oldanswers = $DB->get_records('question_answers',
  42. array('question' => $question->id), 'id ASC')) {
  43. $oldanswers = array();
  44. }
  45. if (!$oldoptions = $DB->get_records('question_calculated',
  46. array('question' => $question->id), 'answer ASC')) {
  47. $oldoptions = array();
  48. }
  49. // Save the units.
  50. $virtualqtype = $this->get_virtual_qtype();
  51. $result = $virtualqtype->save_units($question);
  52. if (isset($result->error)) {
  53. return $result;
  54. } else {
  55. $units = &$result->units;
  56. }
  57. // Insert all the new answers.
  58. foreach ($question->answer as $key => $answerdata) {
  59. if (is_array($answerdata)) {
  60. $answerdata = $answerdata['text'];
  61. }
  62. if (trim($answerdata) == '') {
  63. continue;
  64. }
  65. // Update an existing answer if possible.
  66. $answer = array_shift($oldanswers);
  67. if (!$answer) {
  68. $answer = new stdClass();
  69. $answer->question = $question->id;
  70. $answer->answer = '';
  71. $answer->feedback = '';
  72. $answer->id = $DB->insert_record('question_answers', $answer);
  73. }
  74. $answer->answer = trim($answerdata);
  75. $answer->fraction = $question->fraction[$key];
  76. $answer->feedback = $this->import_or_save_files($question->feedback[$key],
  77. $context, 'question', 'answerfeedback', $answer->id);
  78. $answer->feedbackformat = $question->feedback[$key]['format'];
  79. $DB->update_record("question_answers", $answer);
  80. // Set up the options object.
  81. if (!$options = array_shift($oldoptions)) {
  82. $options = new stdClass();
  83. }
  84. $options->question = $question->id;
  85. $options->answer = $answer->id;
  86. $options->tolerance = trim($question->tolerance[$key]);
  87. $options->tolerancetype = trim($question->tolerancetype[$key]);
  88. $options->correctanswerlength = trim($question->correctanswerlength[$key]);
  89. $options->correctanswerformat = trim($question->correctanswerformat[$key]);
  90. // Save options.
  91. if (isset($options->id)) {
  92. // Reusing existing record.
  93. $DB->update_record('question_calculated', $options);
  94. } else {
  95. // New options.
  96. $DB->insert_record('question_calculated', $options);
  97. }
  98. }
  99. // Delete old answer records.
  100. if (!empty($oldanswers)) {
  101. foreach ($oldanswers as $oa) {
  102. $DB->delete_records('question_answers', array('id' => $oa->id));
  103. }
  104. }
  105. // Delete old answer records.
  106. if (!empty($oldoptions)) {
  107. foreach ($oldoptions as $oo) {
  108. $DB->delete_records('question_calculated', array('id' => $oo->id));
  109. }
  110. }
  111. if (isset($question->import_process) && $question->import_process) {
  112. $this->import_datasets($question);
  113. } else {
  114. // Save datasets and datatitems from form i.e in question.
  115. $question->dataset = $question->datasetdef;
  116. // Save datasets.
  117. $datasetdefinitions = $this->get_dataset_definitions($question->id, $question->dataset);
  118. $tmpdatasets = array_flip($question->dataset);
  119. $defids = array_keys($datasetdefinitions);
  120. $datasetdefs = array();
  121. foreach ($defids as $defid) {
  122. $datasetdef = &$datasetdefinitions[$defid];
  123. if (isset($datasetdef->id)) {
  124. if (!isset($tmpdatasets[$defid])) {
  125. // This dataset is not used any more, delete it.
  126. $DB->delete_records('question_datasets', array('question' => $question->id,
  127. 'datasetdefinition' => $datasetdef->id));
  128. $DB->delete_records('question_dataset_definitions',
  129. array('id' => $datasetdef->id));
  130. $DB->delete_records('question_dataset_items',
  131. array('definition' => $datasetdef->id));
  132. }
  133. // This has already been saved or just got deleted.
  134. unset($datasetdefinitions[$defid]);
  135. continue;
  136. }
  137. $datasetdef->id = $DB->insert_record('question_dataset_definitions', $datasetdef);
  138. $datasetdefs[] = clone($datasetdef);
  139. $questiondataset = new stdClass();
  140. $questiondataset->question = $question->id;
  141. $questiondataset->datasetdefinition = $datasetdef->id;
  142. $DB->insert_record('question_datasets', $questiondataset);
  143. unset($datasetdefinitions[$defid]);
  144. }
  145. // Remove local obsolete datasets as well as relations
  146. // to datasets in other categories.
  147. if (!empty($datasetdefinitions)) {
  148. foreach ($datasetdefinitions as $def) {
  149. $DB->delete_records('question_datasets', array('question' => $question->id,
  150. 'datasetdefinition' => $def->id));
  151. if ($def->category == 0) { // Question local dataset.
  152. $DB->delete_records('question_dataset_definitions',
  153. array('id' => $def->id));
  154. $DB->delete_records('question_dataset_items',
  155. array('definition' => $def->id));
  156. }
  157. }
  158. }
  159. $datasetdefs = $this->get_dataset_definitions($question->id, $question->dataset);
  160. // Handle adding and removing of dataset items.
  161. $i = 1;
  162. ksort($question->definition);
  163. foreach ($question->definition as $key => $defid) {
  164. $addeditem = new stdClass();
  165. $addeditem->definition = $datasetdefs[$defid]->id;
  166. $addeditem->value = $question->number[$i];
  167. $addeditem->itemnumber = ceil($i / count($datasetdefs));
  168. if (empty($question->makecopy) && $question->itemid[$i]) {
  169. // Reuse any previously used record.
  170. $addeditem->id = $question->itemid[$i];
  171. $DB->update_record('question_dataset_items', $addeditem);
  172. } else {
  173. $DB->insert_record('question_dataset_items', $addeditem);
  174. }
  175. $i++;
  176. }
  177. $maxnumber = -1;
  178. if (isset($addeditem->itemnumber) && $maxnumber < $addeditem->itemnumber) {
  179. $maxnumber = $addeditem->itemnumber;
  180. foreach ($datasetdefs as $key => $newdef) {
  181. if (isset($newdef->id) && $newdef->itemcount <= $maxnumber) {
  182. $newdef->itemcount = $maxnumber;
  183. // Save the new value for options.
  184. $DB->update_record('question_dataset_definitions', $newdef);
  185. }
  186. }
  187. }
  188. }
  189. $this->save_hints($question);
  190. // Report any problems.
  191. if (!empty($question->makecopy) && !empty($question->convert)) {
  192. $DB->set_field('question', 'qtype', 'calculated', array('id' => $question->id));
  193. }
  194. $result = $virtualqtype->save_unit_options($question);
  195. if (isset($result->error)) {
  196. return $result;
  197. }
  198. if (!empty($result->notice)) {
  199. return $result;
  200. }
  201. return true;
  202. }
  203. public function finished_edit_wizard($form) {
  204. return true;
  205. }
  206. public function wizard_pages_number() {
  207. return 1;
  208. }
  209. public function custom_generator_tools_part($mform, $idx, $j) {
  210. $minmaxgrp = array();
  211. $minmaxgrp[] = $mform->createElement('text', "calcmin[$idx]",
  212. get_string('calcmin', 'qtype_calculated'));
  213. $minmaxgrp[] = $mform->createElement('text', "calcmax[$idx]",
  214. get_string('calcmax', 'qtype_calculated'));
  215. $mform->addGroup($minmaxgrp, 'minmaxgrp',
  216. get_string('minmax', 'qtype_calculated'), ' - ', false);
  217. $mform->setType("calcmin[$idx]", PARAM_FLOAT);
  218. $mform->setType("calcmax[$idx]", PARAM_FLOAT);
  219. $precisionoptions = range(0, 10);
  220. $mform->addElement('select', "calclength[$idx]",
  221. get_string('calclength', 'qtype_calculated'), $precisionoptions);
  222. $distriboptions = array('uniform' => get_string('uniform', 'qtype_calculated'),
  223. 'loguniform' => get_string('loguniform', 'qtype_calculated'));
  224. $mform->addElement('hidden', "calcdistribution[$idx]", 'uniform');
  225. $mform->setType("calcdistribution[$idx]", PARAM_INT);
  226. }
  227. public function comment_header($answers) {
  228. $strheader = "";
  229. $delimiter = '';
  230. foreach ($answers as $key => $answer) {
  231. $ans = shorten_text($answer->answer, 17, true);
  232. $strheader .= $delimiter.$ans;
  233. $delimiter = '<br/><br/><br/>';
  234. }
  235. return $strheader;
  236. }
  237. public function tolerance_types() {
  238. return array(
  239. '1' => get_string('relative', 'qtype_numerical'),
  240. '2' => get_string('nominal', 'qtype_numerical'),
  241. );
  242. }
  243. public function dataset_options($form, $name, $mandatory = true, $renameabledatasets = false) {
  244. // Takes datasets from the parent implementation but
  245. // filters options that are currently not accepted by calculated.
  246. // It also determines a default selection
  247. // $renameabledatasets not implemented anywhere.
  248. list($options, $selected) = $this->dataset_options_from_database(
  249. $form, $name, '', 'qtype_calculated');
  250. foreach ($options as $key => $whatever) {
  251. if (!preg_match('~^1-~', $key) && $key != '0') {
  252. unset($options[$key]);
  253. }
  254. }
  255. if (!$selected) {
  256. if ($mandatory) {
  257. $selected = "1-0-$name"; // Default.
  258. } else {
  259. $selected = "0"; // Default.
  260. }
  261. }
  262. return array($options, $selected);
  263. }
  264. }