|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00027 defined('MOODLE_INTERNAL') || die(); 00028 00029 require_once($CFG->dirroot . '/question/type/edit_question_form.php'); 00030 require_once($CFG->dirroot . '/question/type/numerical/questiontype.php'); 00031 00032 00039 class qtype_numerical_edit_form extends question_edit_form { 00040 protected $ap = null; 00041 00042 protected function definition_inner($mform) { 00043 $this->add_per_answer_fields($mform, get_string('answerno', 'qtype_numerical', '{no}'), 00044 question_bank::fraction_options()); 00045 00046 $this->add_unit_options($mform); 00047 $this->add_unit_fields($mform); 00048 $this->add_interactive_settings(); 00049 } 00050 00051 protected function get_per_answer_fields($mform, $label, $gradeoptions, 00052 &$repeatedoptions, &$answersoption) { 00053 $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, 00054 $repeatedoptions, $answersoption); 00055 00056 $tolerance = $mform->createElement('text', 'tolerance', 00057 get_string('acceptederror', 'qtype_numerical')); 00058 $repeatedoptions['tolerance']['type'] = PARAM_NUMBER; 00059 $repeatedoptions['tolerance']['default'] = 0; 00060 array_splice($repeated, 3, 0, array($tolerance)); 00061 $repeated[1]->setSize(10); 00062 00063 return $repeated; 00064 } 00065 00070 protected function add_unit_options($mform) { 00071 00072 $mform->addElement('header', 'unithandling', 00073 get_string('unithandling', 'qtype_numerical')); 00074 00075 $unitoptions = array( 00076 qtype_numerical::UNITNONE => get_string('onlynumerical', 'qtype_numerical'), 00077 qtype_numerical::UNITOPTIONAL => get_string('manynumerical', 'qtype_numerical'), 00078 qtype_numerical::UNITGRADED => get_string('unitgraded', 'qtype_numerical'), 00079 ); 00080 $mform->addElement('select', 'unitrole', 00081 get_string('unithandling', 'qtype_numerical'), $unitoptions); 00082 00083 $penaltygrp = array(); 00084 $penaltygrp[] = $mform->createElement('text', 'unitpenalty', 00085 get_string('unitpenalty', 'qtype_numerical'), array('size' => 6)); 00086 $mform->setType('unitpenalty', PARAM_NUMBER); 00087 $mform->setDefault('unitpenalty', 0.1000000); 00088 00089 $unitgradingtypes = array( 00090 qtype_numerical::UNITGRADEDOUTOFMARK => 00091 get_string('decfractionofresponsegrade', 'qtype_numerical'), 00092 qtype_numerical::UNITGRADEDOUTOFMAX => 00093 get_string('decfractionofquestiongrade', 'qtype_numerical'), 00094 ); 00095 $penaltygrp[] = $mform->createElement('select', 'unitgradingtypes', '', $unitgradingtypes); 00096 $mform->setDefault('unitgradingtypes', 1); 00097 00098 $mform->addGroup($penaltygrp, 'penaltygrp', 00099 get_string('unitpenalty', 'qtype_numerical'), ' ', false); 00100 $mform->addHelpButton('penaltygrp', 'unitpenalty', 'qtype_numerical'); 00101 00102 $unitinputoptions = array( 00103 qtype_numerical::UNITINPUT => get_string('editableunittext', 'qtype_numerical'), 00104 qtype_numerical::UNITRADIO => get_string('unitchoice', 'qtype_numerical'), 00105 qtype_numerical::UNITSELECT => get_string('unitselect', 'qtype_numerical'), 00106 ); 00107 $mform->addElement('select', 'multichoicedisplay', 00108 get_string('studentunitanswer', 'qtype_numerical'), $unitinputoptions); 00109 00110 $unitsleftoptions = array( 00111 0 => get_string('rightexample', 'qtype_numerical'), 00112 1 => get_string('leftexample', 'qtype_numerical') 00113 ); 00114 $mform->addElement('select', 'unitsleft', 00115 get_string('unitposition', 'qtype_numerical'), $unitsleftoptions); 00116 $mform->setDefault('unitsleft', 0); 00117 00118 $mform->disabledIf('penaltygrp', 'unitrole', 'eq', qtype_numerical::UNITNONE); 00119 $mform->disabledIf('penaltygrp', 'unitrole', 'eq', qtype_numerical::UNITOPTIONAL); 00120 00121 $mform->disabledIf('unitsleft', 'unitrole', 'eq', qtype_numerical::UNITNONE); 00122 00123 $mform->disabledIf('multichoicedisplay', 'unitrole', 'eq', qtype_numerical::UNITNONE); 00124 $mform->disabledIf('multichoicedisplay', 'unitrole', 'eq', qtype_numerical::UNITOPTIONAL); 00125 } 00126 00131 protected function add_unit_fields($mform) { 00132 $repeated = array( 00133 $mform->createElement('header', 'unithdr', 00134 get_string('unithdr', 'qtype_numerical', '{no}')), 00135 $mform->createElement('text', 'unit', get_string('unit', 'quiz')), 00136 $mform->createElement('text', 'multiplier', get_string('multiplier', 'quiz')), 00137 ); 00138 00139 $repeatedoptions['unit']['type'] = PARAM_NOTAGS; 00140 $repeatedoptions['multiplier']['type'] = PARAM_NUMBER; 00141 $repeatedoptions['unit']['disabledif'] = 00142 array('unitrole', 'eq', qtype_numerical::UNITNONE); 00143 $repeatedoptions['multiplier']['disabledif'] = 00144 array('unitrole', 'eq', qtype_numerical::UNITNONE); 00145 00146 if (isset($this->question->options->units)) { 00147 $countunits = count($this->question->options->units); 00148 } else { 00149 $countunits = 0; 00150 } 00151 if ($this->question->formoptions->repeatelements) { 00152 $repeatsatstart = $countunits + 1; 00153 } else { 00154 $repeatsatstart = $countunits; 00155 } 00156 $this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, 'nounits', 00157 'addunits', 2, get_string('addmoreunitblanks', 'qtype_calculated', '{no}')); 00158 00159 if ($mform->elementExists('multiplier[0]')) { 00160 $firstunit = $mform->getElement('multiplier[0]'); 00161 $firstunit->freeze(); 00162 $firstunit->setValue('1.0'); 00163 $firstunit->setPersistantFreeze(true); 00164 $mform->addHelpButton('multiplier[0]', 'numericalmultiplier', 'qtype_numerical'); 00165 } 00166 } 00167 00168 protected function data_preprocessing($question) { 00169 $question = parent::data_preprocessing($question); 00170 $question = $this->data_preprocessing_answers($question); 00171 $question = $this->data_preprocessing_hints($question); 00172 $question = $this->data_preprocessing_units($question); 00173 $question = $this->data_preprocessing_unit_options($question); 00174 return $question; 00175 } 00176 00177 protected function data_preprocessing_answers($question) { 00178 $question = parent::data_preprocessing_answers($question); 00179 if (empty($question->options->answers)) { 00180 return $question; 00181 } 00182 00183 $key = 0; 00184 foreach ($question->options->answers as $answer) { 00185 // See comment in the parent method about this hack. 00186 unset($this->_form->_defaultValues["tolerance[$key]"]); 00187 00188 $question->tolerance[$key] = $answer->tolerance; 00189 $key++; 00190 } 00191 00192 return $question; 00193 } 00194 00201 protected function data_preprocessing_units($question) { 00202 if (empty($question->options->units)) { 00203 return $question; 00204 } 00205 00206 foreach ($question->options->units as $key => $unit) { 00207 $question->unit[$key] = $unit->unit; 00208 $question->multiplier[$key] = $unit->multiplier; 00209 } 00210 00211 return $question; 00212 } 00213 00220 protected function data_preprocessing_unit_options($question) { 00221 if (empty($question->options)) { 00222 return $question; 00223 } 00224 00225 $question->unitpenalty = $question->options->unitpenalty; 00226 $question->unitsleft = $question->options->unitsleft; 00227 00228 if ($question->options->unitgradingtype) { 00229 $question->unitgradingtypes = $question->options->unitgradingtype; 00230 $question->multichoicedisplay = $question->options->showunits; 00231 $question->unitrole = qtype_numerical::UNITGRADED; 00232 } else { 00233 $question->unitrole = $question->options->showunits; 00234 } 00235 00236 return $question; 00237 } 00238 00239 public function validation($data, $files) { 00240 $errors = parent::validation($data, $files); 00241 $errors = $this->validate_answers($data, $errors); 00242 $errors = $this->validate_numerical_options($data, $errors); 00243 return $errors; 00244 } 00245 00252 protected function validate_answers($data, $errors) { 00253 // Check the answers. 00254 $answercount = 0; 00255 $maxgrade = false; 00256 $answers = $data['answer']; 00257 foreach ($answers as $key => $answer) { 00258 $trimmedanswer = trim($answer); 00259 if ($trimmedanswer != '') { 00260 $answercount++; 00261 if (!$this->is_valid_answer($trimmedanswer, $data)) { 00262 $errors['answer[' . $key . ']'] = $this->valid_answer_message($trimmedanswer); 00263 } 00264 if ($data['fraction'][$key] == 1) { 00265 $maxgrade = true; 00266 } 00267 if ($answer !== '*' && !is_numeric($data['tolerance'][$key])) { 00268 $errors['tolerance['.$key.']'] = 00269 get_string('mustbenumeric', 'qtype_calculated'); 00270 } 00271 } else if ($data['fraction'][$key] != 0 || 00272 !html_is_blank($data['feedback'][$key]['text'])) { 00273 $errors['answer[' . $key . ']'] = $this->valid_answer_message($trimmedanswer); 00274 $answercount++; 00275 } 00276 } 00277 if ($answercount == 0) { 00278 $errors['answer[0]'] = get_string('notenoughanswers', 'qtype_numerical'); 00279 } 00280 if ($maxgrade == false) { 00281 $errors['fraction[0]'] = get_string('fractionsnomax', 'question'); 00282 } 00283 00284 return $errors; 00285 } 00286 00293 protected function is_valid_answer($answer, $data) { 00294 return $answer == '*' || $this->is_valid_number($answer); 00295 } 00296 00302 protected function is_valid_number($x) { 00303 if (is_null($this->ap)) { 00304 $this->ap = new qtype_numerical_answer_processor(array()); 00305 } 00306 00307 list($value, $unit) = $this->ap->apply_units($x); 00308 00309 return !is_null($value) && !$unit; 00310 } 00311 00315 protected function valid_answer_message($answer) { 00316 return get_string('answermustbenumberorstar', 'qtype_numerical'); 00317 } 00318 00325 protected function validate_numerical_options($data, $errors) { 00326 if ($data['unitrole'] != qtype_numerical::UNITNONE && trim($data['unit'][0]) == '') { 00327 $errors['unit[0]'] = get_string('unitonerequired', 'qtype_numerical'); 00328 } 00329 00330 if (empty($data['unit'])) { 00331 return $errors; 00332 } 00333 00334 // Basic unit validation. 00335 foreach ($data['unit'] as $key => $unit) { 00336 if (is_numeric($unit)) { 00337 $errors['unit[' . $key . ']'] = 00338 get_string('mustnotbenumeric', 'qtype_calculated'); 00339 } 00340 00341 $trimmedunit = trim($unit); 00342 if (empty($trimmedunit)) { 00343 continue; 00344 } 00345 00346 $trimmedmultiplier = trim($data['multiplier'][$key]); 00347 if (empty($trimmedmultiplier)) { 00348 $errors['multiplier[' . $key . ']'] = 00349 get_string('youmustenteramultiplierhere', 'qtype_calculated'); 00350 } else if (!is_numeric($trimmedmultiplier)) { 00351 $errors['multiplier[' . $key . ']'] = 00352 get_string('mustbenumeric', 'qtype_calculated'); 00353 } 00354 } 00355 00356 // Check for repeated units. 00357 $alreadyseenunits = array(); 00358 foreach ($data['unit'] as $key => $unit) { 00359 $trimmedunit = trim($unit); 00360 if ($trimmedunit == '') { 00361 continue; 00362 } 00363 00364 if (in_array($trimmedunit, $alreadyseenunits)) { 00365 $errors['unit[' . $key . ']'] = 00366 get_string('errorrepeatedunit', 'qtype_numerical'); 00367 } else { 00368 $alreadyseenunits[] = $trimmedunit; 00369 } 00370 } 00371 00372 return $errors; 00373 } 00374 00375 public function qtype() { 00376 return 'numerical'; 00377 } 00378 }