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 /** 18 * Question type class for the simple calculated question type. 19 * 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 24 */ 25 26 27 defined('MOODLE_INTERNAL') || die(); 28 29 require_once($CFG->dirroot . '/question/type/calculated/questiontype.php'); 30 31 32 /** 33 * The simple calculated question type. 34 * 35 * @copyright 2009 Pierre Pichet 36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 37 */ 38 class qtype_calculatedsimple extends qtype_calculated { 39 40 // Used by the function custom_generator_tools. 41 public $wizard_pages_number = 1; 42 43 public function save_question_options($question) { 44 global $CFG, $DB; 45 $context = $question->context; 46 47 // Make it impossible to save bad formulas anywhere. 48 $this->validate_question_data($question); 49 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(); 54 } 55 56 if (!$oldoptions = $DB->get_records('question_calculated', 57 array('question' => $question->id), 'answer ASC')) { 58 $oldoptions = array(); 59 } 60 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; 68 } 69 // Insert all the new answers. 70 foreach ($question->answer as $key => $answerdata) { 71 if (is_array($answerdata)) { 72 $answerdata = $answerdata['text']; 73 } 74 if (trim($answerdata) == '') { 75 continue; 76 } 77 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); 86 } 87 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']; 93 94 $DB->update_record("question_answers", $answer); 95 96 // Set up the options object. 97 if (!$options = array_shift($oldoptions)) { 98 $options = new stdClass(); 99 } 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]); 106 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); 114 } 115 } 116 117 // Delete old answer records. 118 if (!empty($oldanswers)) { 119 foreach ($oldanswers as $oa) { 120 $DB->delete_records('question_answers', array('id' => $oa->id)); 121 } 122 } 123 124 // Delete old answer records. 125 if (!empty($oldoptions)) { 126 foreach ($oldoptions as $oo) { 127 $DB->delete_records('question_calculated', array('id' => $oo->id)); 128 } 129 } 130 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; 136 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)); 153 } 154 // This has already been saved or just got deleted. 155 unset($datasetdefinitions[$defid]); 156 continue; 157 } 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]); 165 } 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)); 177 } 178 } 179 } 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); 195 } 196 $i++; 197 } 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); 206 } 207 } 208 } 209 } 210 211 $this->save_hints($question); 212 213 // Report any problems. 214 if (!empty($question->makecopy) && !empty($question->convert)) { 215 $DB->set_field('question', 'qtype', 'calculated', array('id' => $question->id)); 216 } 217 218 $result = $virtualqtype->save_unit_options($question); 219 if (isset($result->error)) { 220 return $result; 221 } 222 223 if (!empty($result->notice)) { 224 return $result; 225 } 226 227 return true; 228 } 229 230 public function finished_edit_wizard($form) { 231 return true; 232 } 233 234 public function wizard_pages_number() { 235 return 1; 236 } 237 238 public function custom_generator_tools_part($mform, $idx, $j) { 239 240 $minmaxgrp = array(); 241 $minmaxgrp[] = $mform->createElement('float', "calcmin[{$idx}]", 242 get_string('calcmin', 'qtype_calculated')); 243 $minmaxgrp[] = $mform->createElement('float', "calcmax[{$idx}]", 244 get_string('calcmax', 'qtype_calculated')); 245 $mform->addGroup($minmaxgrp, 'minmaxgrp', 246 get_string('minmax', 'qtype_calculated'), ' - ', false); 247 248 $precisionoptions = range(0, 10); 249 $mform->addElement('select', "calclength[{$idx}]", 250 get_string('calclength', 'qtype_calculated'), $precisionoptions); 251 252 $distriboptions = array('uniform' => get_string('uniform', 'qtype_calculated'), 253 'loguniform' => get_string('loguniform', 'qtype_calculated')); 254 $mform->addElement('hidden', "calcdistribution[{$idx}]", 'uniform'); 255 $mform->setType("calcdistribution[{$idx}]", PARAM_INT); 256 } 257 258 public function comment_header($answers) { 259 $strheader = ""; 260 $delimiter = ''; 261 262 foreach ($answers as $key => $answer) { 263 $ans = shorten_text($answer->answer, 17, true); 264 $strheader .= $delimiter.$ans; 265 $delimiter = '<br/><br/><br/>'; 266 } 267 return $strheader; 268 } 269 270 public function tolerance_types() { 271 return array( 272 '1' => get_string('relative', 'qtype_numerical'), 273 '2' => get_string('nominal', 'qtype_numerical'), 274 ); 275 } 276 277 public function dataset_options($form, $name, $mandatory = true, $renameabledatasets = false) { 278 // Takes datasets from the parent implementation but 279 // filters options that are currently not accepted by calculated. 280 // It also determines a default selection 281 // $renameabledatasets not implemented anywhere. 282 list($options, $selected) = $this->dataset_options_from_database( 283 $form, $name, '', 'qtype_calculated'); 284 285 foreach ($options as $key => $whatever) { 286 if (!preg_match('~^1-~', $key) && $key != '0') { 287 unset($options[$key]); 288 } 289 } 290 if (!$selected) { 291 if ($mandatory) { 292 $selected = "1-0-{$name}"; // Default. 293 } else { 294 $selected = "0"; // Default. 295 } 296 } 297 return array($options, $selected); 298 } 299 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body