MDL-25122 Quiz review page does not check and enforce separate groups mode.
[moodle.git] / question / type / calculated / edit_calculated_form.php
CommitLineData
aeb15530 1<?php
fe6ce234
DC
2
3// This file is part of Moodle - http://moodle.org/
4//
5// Moodle is free software: you can redistribute it and/or modify
6// it under the terms of the GNU General Public License as published by
7// the Free Software Foundation, either version 3 of the License, or
8// (at your option) any later version.
9//
10// Moodle is distributed in the hope that it will be useful,
11// but WITHOUT ANY WARRANTY; without even the implied warranty of
12// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13// GNU General Public License for more details.
14//
15// You should have received a copy of the GNU General Public License
16// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17
271ffe3f 18/**
19 * Defines the editing form for the calculated question type.
20 *
21 * @copyright &copy; 2007 Jamie Pratt
22 * @author Jamie Pratt me@jamiep.org
23 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
9e20fbc2 24 * @package questionbank
25 * @subpackage questiontypes
271ffe3f 26 */
27
28/**
29 * calculated editing form definition.
30 */
31class question_edit_calculated_form extends question_edit_form {
9aa022fe 32 /**
33 * Handle to the question type for this question.
34 *
35 * @var question_calculated_qtype
36 */
d90b016b 37 public $qtypeobj;
fe6ce234
DC
38 public $questiondisplay;
39 public $activecategory;
40 public $categorychanged = false;
d90b016b 41 public $initialname = '';
fe6ce234
DC
42 public $reload = false;
43
d90b016b
PP
44 function question_edit_calculated_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
45 global $QTYPES, $SESSION, $CFG, $DB;
46 $this->question = $question;
47 $this->qtypeobj =& $QTYPES[$this->question->qtype];
48 if ( "1" == optional_param('reload','', PARAM_INT )) {
49 $this->reload = true ;
50 }else {
51 $this->reload = false ;
52 }
2aef1fe5 53
d90b016b
PP
54 if(!$this->reload ){ // use database data as this is first pass
55 if(isset($this->question->id )){
56 // remove prefix #{..}# if exists
57 $this->initialname = $question->name ;
58 $regs= array();
59 if(preg_match('~#\{([^[:space:]]*)#~',$question->name , $regs)){
60 $question->name = str_replace($regs[0], '', $question->name);
fe6ce234 61 };
d90b016b
PP
62 }
63 }else {
fe6ce234 64 }
d90b016b
PP
65 parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
66 }
fe6ce234 67
2aef1fe5 68 function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
fe6ce234
DC
69 // $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
70 $repeated = array();
28a27ef1 71 $repeated[] =& $mform->createElement('header', 'answerhdr', $label);
28a27ef1 72 $repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
73 $repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
fe6ce234 74 $repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'), null, $this->editoroptions);
28a27ef1 75 $repeatedoptions['answer']['type'] = PARAM_RAW;
76 $repeatedoptions['fraction']['default'] = 0;
77 $answersoption = 'answers';
78
2aef1fe5 79 $mform->setType('answer', PARAM_NOTAGS);
80
81 $addrepeated = array();
fe6ce234
DC
82 $addrepeated[] =& $mform->createElement('text', 'tolerance', get_string('tolerance', 'qtype_calculated'));
83 $addrepeated[] =& $mform->createElement('select', 'tolerancetype', get_string('tolerancetype', 'quiz'), $this->qtypeobj->tolerance_types());
2aef1fe5 84 $repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
85 $repeatedoptions['tolerance']['default'] = 0.01;
2aef1fe5 86
87 $addrepeated[] =& $mform->createElement('select', 'correctanswerlength', get_string('correctanswershows', 'qtype_calculated'), range(0, 9));
88 $repeatedoptions['correctanswerlength']['default'] = 2;
89
90 $answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
91 $addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
92 array_splice($repeated, 3, 0, $addrepeated);
fe6ce234 93 $repeated[1]->setLabel(get_string('correctanswerformula', 'quiz').'=');
28a27ef1 94
2aef1fe5 95 return $repeated;
96 }
97
271ffe3f 98 /**
99 * Add question-type specific form fields.
100 *
9aa022fe 101 * @param MoodleQuickForm $mform the form being built.
271ffe3f 102 */
103 function definition_inner(&$mform) {
9aa022fe 104 global $QTYPES;
92186abc 105 $this->qtypeobj =& $QTYPES[$this->qtype()];
cf146692 106 $label = get_string('sharedwildcards', 'qtype_calculated');
a6d46515 107 $mform->addElement('hidden', 'initialcategory', 1);
d90b016b 108 $mform->addElement('hidden', 'reload', 1);
d18e0fe6 109 $mform->setType('initialcategory', PARAM_INT);
a6d46515 110 $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question);
111 $mform->insertElementBefore($mform->createElement('static','listcategory',$label,$html2),'name');
d90b016b
PP
112 if(isset($this->question->id )){
113 $mform->insertElementBefore($mform->createElement('static','initialname',get_string('questionstoredname','qtype_calculated'),$this->initialname),'name');
114 };
a6d46515 115 $addfieldsname='updatecategory';
116 $addstring=get_string("updatecategory", "qtype_calculated");
fe6ce234 117 $mform->registerNoSubmitButton($addfieldsname);
271e6dec 118
a6d46515 119 $mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
28a27ef1 120 $mform->registerNoSubmitButton('createoptionbutton');
aeb15530 121
ab8b5142 122 //editing as regular
fe6ce234 123 $mform->setType('single', PARAM_INT);
aeb15530 124
fe6ce234
DC
125 $mform->addElement('hidden','shuffleanswers', '1');
126 $mform->setType('shuffleanswers', PARAM_INT);
127 $mform->addElement('hidden','answernumbering', 'abc');
128 $mform->setType('answernumbering', PARAM_SAFEDIR);
271ffe3f 129
271ffe3f 130 $creategrades = get_grade_options();
ab8b5142 131
fe6ce234 132 $this->add_per_answer_fields($mform, get_string('answerhdr', 'qtype_calculated', '{no}'), $creategrades->gradeoptions, 1, 1);
92186abc 133
271e6dec 134 $repeated = array();
271ffe3f 135
cf146692
PP
136 $QTYPES['numerical']->add_units_options($mform,$this);
137 $QTYPES['numerical']->add_units_elements($mform,$this);
fe6ce234 138
9aa022fe 139 //hidden elements
e593233a 140 $mform->addElement('hidden', 'synchronize', '');
d18e0fe6 141 $mform->setType('synchronize', PARAM_INT);
60b5ecd3 142 $mform->addElement('hidden', 'wizard', 'datasetdefinitions');
143 $mform->setType('wizard', PARAM_ALPHA);
271ffe3f 144 }
145
fe6ce234 146 function data_preprocessing($question) {
81053284
PP
147 global $QTYPES;
148
cf146692 149 $default_values = array();
271ffe3f 150 if (isset($question->options)){
151 $answers = $question->options->answers;
152 if (count($answers)) {
153 $key = 0;
154 foreach ($answers as $answer){
fe6ce234 155 $draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
9af77e9d 156 $default_values['answer['.$key.']'] = $answer->answer;
92186abc 157 $default_values['fraction['.$key.']'] = $answer->fraction;
158 $default_values['tolerance['.$key.']'] = $answer->tolerance;
f7089b63 159 $default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
92186abc 160 $default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
9aa022fe 161 $default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
fe6ce234
DC
162 $default_values['feedback['.$key.']'] = array();
163 $default_values['feedback['.$key.']']['text'] = file_prepare_draft_area(
164 $draftid, // draftid
165 $this->context->id, // context
166 'question', // component
167 'answerfeedback', // filarea
168 !empty($answer->id)?(int)$answer->id:null, // itemid
169 $this->fileoptions, // options
170 $answer->feedback // text
171 );
172 $default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
173 $default_values['feedback['.$key.']']['itemid'] = $draftid;
271ffe3f 174 $key++;
175 }
176 }
fe6ce234
DC
177 $default_values['synchronize'] = $question->options->synchronize ;
178 // set unit data, prepare files in instruction area
179 $QTYPES['numerical']->set_numerical_unit_data($this, $question, $default_values);
81053284 180 }
28a27ef1 181 if (isset($question->options->single)){
cf146692
PP
182 $default_values['single'] = $question->options->single;
183 $default_values['answernumbering'] = $question->options->answernumbering;
184 $default_values['shuffleanswers'] = $question->options->shuffleanswers;
fe6ce234 185 // prepare feedback editor to display files in draft area
cf146692 186 }
8fc3e643 187 $default_values['submitbutton'] = get_string('nextpage', 'qtype_calculated');
188 $default_values['makecopy'] = get_string('makecopynextpage', 'qtype_calculated');
b800dc19 189 $default_values['returnurl'] = '0' ;
271e6dec 190 /* set the wild cards category display given that on loading the category element is
191 unselected when processing this function but have a valid value when processing the
0dd3e11c 192 update category button. The value can be obtain by
193 $qu->category =$this->_form->_elements[$this->_form->_elementIndex['category']]->_values[0];
194 but is coded using existing functions
fe6ce234
DC
195 */
196 $qu = new stdClass;
197 $el = new stdClass;
198 /* no need to call elementExists() here */
199 if ($this->_form->elementExists('category')){
79bb7202 200 $el=$this->_form->getElement('category');
fe6ce234 201 } else {
79bb7202 202 $el=$this->_form->getElement('categorymoveto');
fe6ce234
DC
203 }
204 if($value =$el->getSelected()) {
0dd3e11c 205 $qu->category =$value[0];
206 }else {
207 $qu->category=$question->category;// on load $question->category is set by question.php
271e6dec 208 }
0dd3e11c 209 $html2 = $this->qtypeobj->print_dataset_definitions_category($qu);
79bb7202 210 $this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2 ;
211 $question = (object)((array)$question + $default_values);
92186abc 212
fe6ce234 213 return $question;
271ffe3f 214 }
215
216 function qtype() {
217 return 'calculated';
218 }
219
a78890d5 220 function validation($data, $files) {
cf146692 221 global $QTYPES;
fe6ce234 222 // echo code left for testing period
28a27ef1 223
fe6ce234
DC
224 // echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
225 // echo "<p>data <pre>";print_r($data);echo "</pre></p>";
28a27ef1 226
fe93ba83 227 $errors = parent::validation($data, $files);
bfdc0bce 228 //verifying for errors in {=...} in question text;
229 $qtext = "";
fe6ce234
DC
230 $qtextremaining = $data['questiontext']['text'];
231 $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
232 foreach ($possibledatasets as $name => $value) {
bfdc0bce 233 $qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
234 }
fe6ce234
DC
235 // echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
236 while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
bfdc0bce 237 $qtextsplits = explode($regs1[0], $qtextremaining, 2);
238 $qtext =$qtext.$qtextsplits[0];
239 $qtextremaining = $qtextsplits[1];
240 if (!empty($regs1[1]) && $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])) {
241 if(!isset($errors['questiontext'])){
242 $errors['questiontext'] = $formulaerrors.':'.$regs1[1] ;
243 }else {
244 $errors['questiontext'] .= '<br/>'.$formulaerrors.':'.$regs1[1];
271e6dec 245 }
bfdc0bce 246 }
271e6dec 247 }
9af77e9d 248 $answers = $data['answer'];
271ffe3f 249 $answercount = 0;
a6d46515 250 $maxgrade = false;
fe6ce234 251 $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
f6232d58 252 $mandatorydatasets = array();
253 foreach ($answers as $key => $answer){
a6d46515 254 $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
271e6dec 255 }
a6d46515 256 if ( count($mandatorydatasets )==0){
fe6ce234 257 // $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
f6232d58 258 foreach ($answers as $key => $answer){
9af77e9d 259 $errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
271e6dec 260 }
261 }
fe6ce234
DC
262 // regular calculated
263 foreach ($answers as $key => $answer){
264 //check no of choices
265 // the * for everykind of answer not actually implemented
266 $trimmedanswer = trim($answer);
267 if (($trimmedanswer!='')||$answercount==0){
268 $eqerror = qtype_calculated_find_formula_errors($trimmedanswer);
269 if (FALSE !== $eqerror){
270 $errors['answer['.$key.']'] = $eqerror;
9aa022fe 271 }
fe6ce234
DC
272 }
273 if ($trimmedanswer!=''){
274 if ('2' == $data['correctanswerformat'][$key]
275 && '0' == $data['correctanswerlength'][$key]) {
99a77ee5 276 $errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
277 }
fe6ce234
DC
278 if (!is_numeric($data['tolerance'][$key])){
279 $errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
a6d46515 280 }
fe6ce234
DC
281 if ($data['fraction'][$key] == 1) {
282 $maxgrade = true;
283 }
284
285 $answercount++;
286 }
287 //check grades
aeb15530 288
fe6ce234 289 //TODO how should grade checking work here??
99a77ee5 290 /*if ($answer != '') {
291 if ($data['fraction'][$key] > 0) {
292 $totalfraction += $data['fraction'][$key];
293 }
294 if ($data['fraction'][$key] > $maxfraction) {
295 $maxfraction = $data['fraction'][$key];
296 }
297 }*/
fe6ce234 298 }
aeb15530 299
fe6ce234
DC
300 //grade checking :
301 /// Perform sanity checks on fractional grades
99a77ee5 302 /*if ( ) {
303 if ($maxfraction != 1) {
304 $maxfraction = $maxfraction * 100;
305 $errors['fraction[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction);
9aa022fe 306 }
99a77ee5 307 } else {
308 $totalfraction = round($totalfraction,2);
309 if ($totalfraction != 1) {
310 $totalfraction = $totalfraction * 100;
311 $errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
9aa022fe 312 }
cf146692 313 }
fe6ce234 314 $units = $data['unit'];
99a77ee5 315 if (count($units)) {
316 foreach ($units as $key => $unit){
317 if (is_numeric($unit)){
318 $errors['unit['.$key.']'] = get_string('mustnotbenumeric', 'qtype_calculated');
9aa022fe 319 }
99a77ee5 320 $trimmedunit = trim($unit);
321 $trimmedmultiplier = trim($data['multiplier'][$key]);
322 if (!empty($trimmedunit)){
323 if (empty($trimmedmultiplier)){
324 $errors['multiplier['.$key.']'] = get_string('youmustenteramultiplierhere', 'qtype_calculated');
325 }
326 if (!is_numeric($trimmedmultiplier)){
327 $errors['multiplier['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
328 }
aeb15530 329
9aa022fe 330 }
fe6ce234 331 }
cf146692 332 }*/
fe6ce234
DC
333 $QTYPES['numerical']->validate_numerical_options($data, $errors) ;
334 if ($answercount==0){
335 $errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
336 }
337 if ($maxgrade == false) {
338 $errors['fraction[0]'] = get_string('fractionsnomax', 'question');
339 }
340
9aa022fe 341
271ffe3f 342 return $errors;
343 }
344}