MDL-47919 tool_monitor: adjustments to behat tests
[moodle.git] / question / type / calculatedsimple / questiontype.php
blob68f45cb82028ef0f397189337fa881b049de31e3
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.
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/>.
17 /**
18 * Question type class for the simple calculated question type.
20 * @package qtype
21 * @subpackage calculatedsimple
22 * @copyright 2009 Pierre Pichet
23 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
27 defined('MOODLE_INTERNAL') || die();
29 require_once($CFG->dirroot . '/question/type/calculated/questiontype.php');
32 /**
33 * The simple calculated question type.
35 * @copyright 2009 Pierre Pichet
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
38 class qtype_calculatedsimple extends qtype_calculated {
40 // Used by the function custom_generator_tools.
41 public $wizard_pages_number = 1;
43 public function save_question_options($question) {
44 global $CFG, $DB;
45 $context = $question->context;
47 // Make it impossible to save bad formulas anywhere.
48 $this->validate_question_data($question);
50 // Get old versions of the objects.
51 if (!$oldanswers = $DB->get_records('question_answers',
52 array('question' => $question->id), 'id ASC')) {
53 $oldanswers = array();
56 if (!$oldoptions = $DB->get_records('question_calculated',
57 array('question' => $question->id), 'answer ASC')) {
58 $oldoptions = array();
61 // Save the units.
62 $virtualqtype = $this->get_virtual_qtype();
63 $result = $virtualqtype->save_units($question);
64 if (isset($result->error)) {
65 return $result;
66 } else {
67 $units = &$result->units;
69 // Insert all the new answers.
70 foreach ($question->answer as $key => $answerdata) {
71 if (is_array($answerdata)) {
72 $answerdata = $answerdata['text'];
74 if (trim($answerdata) == '') {
75 continue;
78 // Update an existing answer if possible.
79 $answer = array_shift($oldanswers);
80 if (!$answer) {
81 $answer = new stdClass();
82 $answer->question = $question->id;
83 $answer->answer = '';
84 $answer->feedback = '';
85 $answer->id = $DB->insert_record('question_answers', $answer);
88 $answer->answer = trim($answerdata);
89 $answer->fraction = $question->fraction[$key];
90 $answer->feedback = $this->import_or_save_files($question->feedback[$key],
91 $context, 'question', 'answerfeedback', $answer->id);
92 $answer->feedbackformat = $question->feedback[$key]['format'];
94 $DB->update_record("question_answers", $answer);
96 // Set up the options object.
97 if (!$options = array_shift($oldoptions)) {
98 $options = new stdClass();
100 $options->question = $question->id;
101 $options->answer = $answer->id;
102 $options->tolerance = trim($question->tolerance[$key]);
103 $options->tolerancetype = trim($question->tolerancetype[$key]);
104 $options->correctanswerlength = trim($question->correctanswerlength[$key]);
105 $options->correctanswerformat = trim($question->correctanswerformat[$key]);
107 // Save options.
108 if (isset($options->id)) {
109 // Reusing existing record.
110 $DB->update_record('question_calculated', $options);
111 } else {
112 // New options.
113 $DB->insert_record('question_calculated', $options);
117 // Delete old answer records.
118 if (!empty($oldanswers)) {
119 foreach ($oldanswers as $oa) {
120 $DB->delete_records('question_answers', array('id' => $oa->id));
124 // Delete old answer records.
125 if (!empty($oldoptions)) {
126 foreach ($oldoptions as $oo) {
127 $DB->delete_records('question_calculated', array('id' => $oo->id));
131 if (isset($question->import_process) && $question->import_process) {
132 $this->import_datasets($question);
133 } else {
134 // Save datasets and datatitems from form i.e in question.
135 $question->dataset = $question->datasetdef;
137 // Save datasets.
138 $datasetdefinitions = $this->get_dataset_definitions($question->id, $question->dataset);
139 $tmpdatasets = array_flip($question->dataset);
140 $defids = array_keys($datasetdefinitions);
141 $datasetdefs = array();
142 foreach ($defids as $defid) {
143 $datasetdef = &$datasetdefinitions[$defid];
144 if (isset($datasetdef->id)) {
145 if (!isset($tmpdatasets[$defid])) {
146 // This dataset is not used any more, delete it.
147 $DB->delete_records('question_datasets', array('question' => $question->id,
148 'datasetdefinition' => $datasetdef->id));
149 $DB->delete_records('question_dataset_definitions',
150 array('id' => $datasetdef->id));
151 $DB->delete_records('question_dataset_items',
152 array('definition' => $datasetdef->id));
154 // This has already been saved or just got deleted.
155 unset($datasetdefinitions[$defid]);
156 continue;
158 $datasetdef->id = $DB->insert_record('question_dataset_definitions', $datasetdef);
159 $datasetdefs[] = clone($datasetdef);
160 $questiondataset = new stdClass();
161 $questiondataset->question = $question->id;
162 $questiondataset->datasetdefinition = $datasetdef->id;
163 $DB->insert_record('question_datasets', $questiondataset);
164 unset($datasetdefinitions[$defid]);
166 // Remove local obsolete datasets as well as relations
167 // to datasets in other categories.
168 if (!empty($datasetdefinitions)) {
169 foreach ($datasetdefinitions as $def) {
170 $DB->delete_records('question_datasets', array('question' => $question->id,
171 'datasetdefinition' => $def->id));
172 if ($def->category == 0) { // Question local dataset.
173 $DB->delete_records('question_dataset_definitions',
174 array('id' => $def->id));
175 $DB->delete_records('question_dataset_items',
176 array('definition' => $def->id));
180 $datasetdefs = $this->get_dataset_definitions($question->id, $question->dataset);
181 // Handle adding and removing of dataset items.
182 $i = 1;
183 ksort($question->definition);
184 foreach ($question->definition as $key => $defid) {
185 $addeditem = new stdClass();
186 $addeditem->definition = $datasetdefs[$defid]->id;
187 $addeditem->value = $question->number[$i];
188 $addeditem->itemnumber = ceil($i / count($datasetdefs));
189 if (empty($question->makecopy) && $question->itemid[$i]) {
190 // Reuse any previously used record.
191 $addeditem->id = $question->itemid[$i];
192 $DB->update_record('question_dataset_items', $addeditem);
193 } else {
194 $DB->insert_record('question_dataset_items', $addeditem);
196 $i++;
198 $maxnumber = -1;
199 if (isset($addeditem->itemnumber) && $maxnumber < $addeditem->itemnumber) {
200 $maxnumber = $addeditem->itemnumber;
201 foreach ($datasetdefs as $key => $newdef) {
202 if (isset($newdef->id) && $newdef->itemcount <= $maxnumber) {
203 $newdef->itemcount = $maxnumber;
204 // Save the new value for options.
205 $DB->update_record('question_dataset_definitions', $newdef);
211 $this->save_hints($question);
213 // Report any problems.
214 if (!empty($question->makecopy) && !empty($question->convert)) {
215 $DB->set_field('question', 'qtype', 'calculated', array('id' => $question->id));
218 $result = $virtualqtype->save_unit_options($question);
219 if (isset($result->error)) {
220 return $result;
223 if (!empty($result->notice)) {
224 return $result;
227 return true;
230 public function finished_edit_wizard($form) {
231 return true;
234 public function wizard_pages_number() {
235 return 1;
238 public function custom_generator_tools_part($mform, $idx, $j) {
240 $minmaxgrp = array();
241 $minmaxgrp[] = $mform->createElement('text', "calcmin[{$idx}]",
242 get_string('calcmin', 'qtype_calculated'));
243 $minmaxgrp[] = $mform->createElement('text', "calcmax[{$idx}]",
244 get_string('calcmax', 'qtype_calculated'));
245 $mform->addGroup($minmaxgrp, 'minmaxgrp',
246 get_string('minmax', 'qtype_calculated'), ' - ', false);
247 $mform->setType("calcmin[{$idx}]", PARAM_FLOAT);
248 $mform->setType("calcmax[{$idx}]", PARAM_FLOAT);
250 $precisionoptions = range(0, 10);
251 $mform->addElement('select', "calclength[{$idx}]",
252 get_string('calclength', 'qtype_calculated'), $precisionoptions);
254 $distriboptions = array('uniform' => get_string('uniform', 'qtype_calculated'),
255 'loguniform' => get_string('loguniform', 'qtype_calculated'));
256 $mform->addElement('hidden', "calcdistribution[{$idx}]", 'uniform');
257 $mform->setType("calcdistribution[{$idx}]", PARAM_INT);
260 public function comment_header($answers) {
261 $strheader = "";
262 $delimiter = '';
264 foreach ($answers as $key => $answer) {
265 $ans = shorten_text($answer->answer, 17, true);
266 $strheader .= $delimiter.$ans;
267 $delimiter = '<br/><br/><br/>';
269 return $strheader;
272 public function tolerance_types() {
273 return array(
274 '1' => get_string('relative', 'qtype_numerical'),
275 '2' => get_string('nominal', 'qtype_numerical'),
279 public function dataset_options($form, $name, $mandatory = true, $renameabledatasets = false) {
280 // Takes datasets from the parent implementation but
281 // filters options that are currently not accepted by calculated.
282 // It also determines a default selection
283 // $renameabledatasets not implemented anywhere.
284 list($options, $selected) = $this->dataset_options_from_database(
285 $form, $name, '', 'qtype_calculated');
287 foreach ($options as $key => $whatever) {
288 if (!preg_match('~^1-~', $key) && $key != '0') {
289 unset($options[$key]);
292 if (!$selected) {
293 if ($mandatory) {
294 $selected = "1-0-{$name}"; // Default.
295 } else {
296 $selected = "0"; // Default.
299 return array($options, $selected);