MDL-20636 Fix new stdClass -> stdClass(), and trailing whitespace.
[moodle.git] / question / type / calculatedmulti / edit_calculatedmulti_form.php
CommitLineData
2d279432
PP
1<?php
2/**
3 * Defines the editing form for the calculated question type.
4 *
b04a4319
TH
5 * @package qtype
6 * @subpackage calculatedmult
7 * @copyright 2007 Jamie Pratt me@jamiep.org
8 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2d279432
PP
9 */
10
11/**
12 * calculated editing form definition.
b04a4319
TH
13 *
14 * @copyright 2007 Jamie Pratt me@jamiep.org
15 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
2d279432
PP
16 */
17class question_edit_calculatedmulti_form extends question_edit_form {
18 /**
19 * Handle to the question type for this question.
20 *
21 * @var question_calculatedmulti_qtype
22 */
fe6ce234 23 public $qtypeobj;
d90b016b
PP
24 public $questiondisplay ;
25 public $initialname = '';
26 public $reload = false ;
fe6ce234 27 function question_edit_calculatedmulti_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true) {
2d279432 28 global $QTYPES, $SESSION, $CFG, $DB;
2d279432
PP
29 $this->question = $question;
30 $this->qtypeobj =& $QTYPES[$this->question->qtype];
d90b016b
PP
31 if ( "1" == optional_param('reload','', PARAM_INT )) {
32 $this->reload = true ;
33 }else {
34 $this->reload = false ;
35 }
36 if(!$this->reload ){ // use database data as this is first pass
37 if(isset($this->question->id )){
38 // remove prefix #{..}# if exists
39 $this->initialname = $question->name ;
40 $regs= array();
41 if(preg_match('~#\{([^[:space:]]*)#~',$question->name , $regs)){
42 $question->name = str_replace($regs[0], '', $question->name);
fe6ce234 43 };
d90b016b
PP
44 }
45 }else {
fe6ce234 46 }
2d279432
PP
47 parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
48 }
49
2d279432 50 function get_per_answer_fields(&$mform, $label, $gradeoptions, &$repeatedoptions, &$answersoption) {
fe6ce234
DC
51 // $repeated = parent::get_per_answer_fields($mform, $label, $gradeoptions, $repeatedoptions, $answersoption);
52 $repeated = array();
2d279432 53 $repeated[] =& $mform->createElement('header', 'answerhdr', $label);
fe6ce234 54 // if ($this->editasmultichoice == 1){
2d279432
PP
55 $repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'), array('size' => 50));
56 $repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
fe6ce234 57 $repeated[] =& $mform->createElement('editor', 'feedback', get_string('feedback', 'quiz'), null, $this->editoroptions);
2d279432
PP
58 $repeatedoptions['answer']['type'] = PARAM_RAW;
59 $repeatedoptions['fraction']['default'] = 0;
60 $answersoption = 'answers';
61
62 $mform->setType('answer', PARAM_NOTAGS);
63
64 $addrepeated = array();
fe6ce234
DC
65 $addrepeated[] =& $mform->createElement('hidden', 'tolerance');
66 $addrepeated[] =& $mform->createElement('hidden', 'tolerancetype',1);
2d279432
PP
67 $repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
68 $repeatedoptions['tolerance']['default'] = 0.01;
69
70 $addrepeated[] =& $mform->createElement('select', 'correctanswerlength', get_string('correctanswershows', 'qtype_calculated'), range(0, 9));
71 $repeatedoptions['correctanswerlength']['default'] = 2;
72
73 $answerlengthformats = array('1' => get_string('decimalformat', 'quiz'), '2' => get_string('significantfiguresformat', 'quiz'));
74 $addrepeated[] =& $mform->createElement('select', 'correctanswerformat', get_string('correctanswershowsformat', 'qtype_calculated'), $answerlengthformats);
75 array_splice($repeated, 3, 0, $addrepeated);
fe6ce234 76 $repeated[1]->setLabel('...<strong>{={x}+..}</strong>...');
2d279432
PP
77
78 return $repeated;
79 }
80
81 /**
82 * Add question-type specific form fields.
83 *
84 * @param MoodleQuickForm $mform the form being built.
85 */
86 function definition_inner(&$mform) {
87 global $QTYPES;
88 $this->qtypeobj =& $QTYPES[$this->qtype()];
fe6ce234
DC
89 // echo code left for testing period
90 // echo "<p>question ".optional_param('multichoice', '', PARAM_RAW)." optional<pre>";print_r($this->question);echo "</pre></p>";
d7be65a3 91 $label = get_string("sharedwildcards", "qtype_calculated");
2d279432 92 $mform->addElement('hidden', 'initialcategory', 1);
d90b016b 93 $mform->addElement('hidden', 'reload', 1);
2d279432
PP
94 $mform->setType('initialcategory', PARAM_INT);
95
fe6ce234
DC
96 // $html2 = $this->qtypeobj->print_dataset_definitions_category($this->question);
97 $html2 ="";
2d279432 98 $mform->insertElementBefore($mform->createElement('static','listcategory',$label,$html2),'name');
d90b016b
PP
99 if(isset($this->question->id )){
100 $mform->insertElementBefore($mform->createElement('static','initialname',get_string('questionstoredname','qtype_calculated'),$this->initialname),'name');
101 };
2d279432
PP
102 $addfieldsname='updatecategory';
103 $addstring=get_string("updatecategory", "qtype_calculated");
fe6ce234 104 $mform->registerNoSubmitButton($addfieldsname);
2d279432 105 $this->editasmultichoice = 1 ;
fe6ce234 106
2d279432
PP
107
108 $mform->insertElementBefore( $mform->createElement('submit', $addfieldsname, $addstring),'listcategory');
109 $mform->registerNoSubmitButton('createoptionbutton');
fe6ce234
DC
110 $mform->addElement('hidden', 'multichoice',$this->editasmultichoice);
111 $mform->setType('multichoice', PARAM_INT);
2d279432 112
fe6ce234
DC
113
114 // $mform->addElement('header', 'choicehdr',get_string('multichoicecalculatedquestion', 'qtype_calculated'));
115 $menu = array(get_string('answersingleno', 'qtype_multichoice'), get_string('answersingleyes', 'qtype_multichoice'));
116 $mform->addElement('select', 'single', get_string('answerhowmany', 'qtype_multichoice'), $menu);
117 $mform->setDefault('single', 1);
118
119 $mform->addElement('advcheckbox', 'shuffleanswers', get_string('shuffleanswers', 'qtype_multichoice'), null, null, array(0,1));
ed14ad02 120 $mform->addHelpButton('shuffleanswers', 'shuffleanswers', 'qtype_multichoice');
fe6ce234
DC
121 $mform->setDefault('shuffleanswers', 1);
122
123 $numberingoptions = $QTYPES['multichoice']->get_numbering_styles();
124 $menu = array();
125 foreach ($numberingoptions as $numberingoption) {
126 $menu[$numberingoption] = get_string('answernumbering' . $numberingoption, 'qtype_multichoice');
127 }
128 $mform->addElement('select', 'answernumbering', get_string('answernumbering', 'qtype_multichoice'), $menu);
129 $mform->setDefault('answernumbering', 'abc');
2d279432
PP
130
131 $creategrades = get_grade_options();
fe6ce234
DC
132 $this->add_per_answer_fields($mform, get_string('choiceno', 'qtype_multichoice', '{no}'),
133 $creategrades->gradeoptionsfull, max(5, QUESTION_NUMANS_START));
134
2d279432
PP
135
136 $repeated = array();
fe6ce234
DC
137 // if ($this->editasmultichoice == 1){
138 $nounits = optional_param('nounits', 1, PARAM_INT);
139 $mform->addElement('hidden', 'nounits', $nounits);
140 $mform->setType('nounits', PARAM_INT);
141 $mform->setConstants(array('nounits'=>$nounits));
142 for ($i=0; $i< $nounits; $i++) {
143 $mform->addElement('hidden','unit'."[$i]", optional_param('unit'."[$i]", '', PARAM_NOTAGS));
144 $mform->setType('unit'."[$i]", PARAM_NOTAGS);
145 $mform->addElement('hidden', 'multiplier'."[$i]", optional_param('multiplier'."[$i]", '', PARAM_NUMBER));
146 $mform->setType('multiplier'."[$i]", PARAM_NUMBER);
147 }
2d279432 148
fe6ce234
DC
149 $mform->setType('addunits','hidden');
150 $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
2d279432 151
fe6ce234
DC
152 foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
153 $mform->addElement('editor', $feedbackname, get_string($feedbackname, 'qtype_multichoice'), null, $this->editoroptions);
154 $mform->setType($feedbackname, PARAM_RAW);
155 }
2d279432
PP
156 //hidden elements
157 $mform->addElement('hidden', 'synchronize', '');
158 $mform->setType('synchronize', PARAM_INT);
159 if (isset($this->question->options)&& isset($this->question->options->synchronize) ){
160 $mform->setDefault("synchronize", $this->question->options->synchronize);
161 } else {
162 $mform->setDefault("synchronize", 0 );
163 }
164 $mform->addElement('hidden', 'wizard', 'datasetdefinitions');
165 $mform->setType('wizard', PARAM_ALPHA);
2d279432
PP
166 }
167
fe6ce234
DC
168 function data_preprocessing($question) {
169 $default_values['multichoice']= $this->editasmultichoice ; //$this->editasmultichoice ;
2d279432
PP
170 if (isset($question->options)){
171 $answers = $question->options->answers;
172 if (count($answers)) {
173 $key = 0;
174 foreach ($answers as $answer){
fe6ce234 175 $draftid = file_get_submitted_draft_itemid('feedback['.$key.']');
2d279432
PP
176 $default_values['answer['.$key.']'] = $answer->answer;
177 $default_values['fraction['.$key.']'] = $answer->fraction;
178 $default_values['tolerance['.$key.']'] = $answer->tolerance;
179 $default_values['tolerancetype['.$key.']'] = $answer->tolerancetype;
180 $default_values['correctanswerlength['.$key.']'] = $answer->correctanswerlength;
181 $default_values['correctanswerformat['.$key.']'] = $answer->correctanswerformat;
fe6ce234
DC
182 $default_values['feedback['.$key.']'] = array();
183 // prepare draftarea
41dcc2a5 184 $default_values['feedback['.$key.']']['text'] = file_prepare_draft_area($draftid, $this->context->id, 'question', 'answerfeedback', empty($answer->id)?null:(int)$answer->id, $this->fileoptions, $answer->feedback);
fe6ce234
DC
185 $default_values['feedback['.$key.']']['format'] = $answer->feedbackformat;
186 $default_values['feedback['.$key.']']['itemid'] = $draftid;
2d279432
PP
187 $key++;
188 }
189 }
fe6ce234 190 $default_values['synchronize'] = $question->options->synchronize ;
2d279432
PP
191
192 if (isset($question->options->units)){
193 $units = array_values($question->options->units);
194 // make sure the default unit is at index 0
195 usort($units, create_function('$a, $b',
fe6ce234
DC
196 'if (1.0 === (float)$a->multiplier) { return -1; } else '.
197 'if (1.0 === (float)$b->multiplier) { return 1; } else { return 0; }'));
2d279432
PP
198 if (count($units)) {
199 $key = 0;
200 foreach ($units as $unit){
201 $default_values['unit['.$key.']'] = $unit->unit;
202 $default_values['multiplier['.$key.']'] = $unit->multiplier;
203 $key++;
204 }
205 }
206 }
207 }
208 if (isset($question->options->single)){
fe6ce234
DC
209 $default_values['single'] = $question->options->single;
210 $default_values['answernumbering'] = $question->options->answernumbering;
211 $default_values['shuffleanswers'] = $question->options->shuffleanswers;
212 }
2d279432
PP
213 $default_values['submitbutton'] = get_string('nextpage', 'qtype_calculated');
214 $default_values['makecopy'] = get_string('makecopynextpage', 'qtype_calculated');
fe6ce234
DC
215
216 // prepare draft files
217 foreach (array('correctfeedback', 'partiallycorrectfeedback', 'incorrectfeedback') as $feedbackname) {
218 if (!isset($question->options->$feedbackname)) {
219 continue;
220 }
221 $text = $question->options->$feedbackname;
222 $draftid = file_get_submitted_draft_itemid($feedbackname);
223 $feedbackformat = $feedbackname . 'format';
224 $format = $question->options->$feedbackformat;
225 $default_values[$feedbackname] = array();
226 $default_values[$feedbackname]['text'] = file_prepare_draft_area(
227 $draftid, // draftid
228 $this->context->id, // context
229 'qtype_calculatedmulti', // component
230 $feedbackname, // filarea
231 !empty($question->id)?(int)$question->id:null, // itemid
232 $this->fileoptions, // options
233 $text // text
234 );
235 $default_values[$feedbackname]['format'] = $format;
236 $default_values[$feedbackname]['itemid'] = $draftid;
237 }
238 /**
239 * set the wild cards category display given that on loading the category element is
240 * unselected when processing this function but have a valid value when processing the
241 * update category button. The value can be obtain by
242 * $qu->category =$this->_form->_elements[$this->_form->_elementIndex['category']]->_values[0];
243 * but is coded using existing functions
244 */
0ff4bd08
TH
245 $qu = new stdClass();
246 $el = new stdClass();
fe6ce234
DC
247 /* no need to call elementExists() here */
248 if ($this->_form->elementExists('category')){
2d279432 249 $el=$this->_form->getElement('category');
fe6ce234 250 } else {
2d279432 251 $el=$this->_form->getElement('categorymoveto');
fe6ce234
DC
252 }
253 if($value =$el->getSelected()) {
2d279432
PP
254 $qu->category =$value[0];
255 }else {
256 $qu->category=$question->category;// on load $question->category is set by question.php
257 }
258 $html2 = $this->qtypeobj->print_dataset_definitions_category($qu);
259 $this->_form->_elements[$this->_form->_elementIndex['listcategory']]->_text = $html2 ;
260 $question = (object)((array)$question + $default_values);
fe6ce234 261 return $question;
2d279432
PP
262 }
263
264 function qtype() {
265 return 'calculatedmulti';
266 }
267
268 function validation($data, $files) {
fe6ce234
DC
269 // echo code left for testing period
270 // echo "<p>question <pre>";print_r($this->question);echo "</pre></p>";
271 // echo "<p>data <pre>";print_r($data);echo "</pre></p>";
2d279432
PP
272
273 $errors = parent::validation($data, $files);
274 //verifying for errors in {=...} in question text;
275 $qtext = "";
fe6ce234
DC
276 $qtextremaining = $data['questiontext']['text'];
277 $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
278 foreach ($possibledatasets as $name => $value) {
2d279432
PP
279 $qtextremaining = str_replace('{'.$name.'}', '1', $qtextremaining);
280 }
fe6ce234
DC
281 // echo "numericalquestion qtextremaining <pre>";print_r($possibledatasets);
282 while (preg_match('~\{=([^[:space:]}]*)}~', $qtextremaining, $regs1)) {
2d279432
PP
283 $qtextsplits = explode($regs1[0], $qtextremaining, 2);
284 $qtext =$qtext.$qtextsplits[0];
285 $qtextremaining = $qtextsplits[1];
286 if (!empty($regs1[1]) && $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])) {
287 if(!isset($errors['questiontext'])){
288 $errors['questiontext'] = $formulaerrors.':'.$regs1[1] ;
289 }else {
290 $errors['questiontext'] .= '<br/>'.$formulaerrors.':'.$regs1[1];
291 }
292 }
293 }
294 $answers = $data['answer'];
295 $answercount = 0;
296 $maxgrade = false;
fe6ce234 297 $possibledatasets = $this->qtypeobj->find_dataset_names($data['questiontext']['text']);
2d279432
PP
298 $mandatorydatasets = array();
299 foreach ($answers as $key => $answer){
300 $mandatorydatasets += $this->qtypeobj->find_dataset_names($answer);
301 }
302 if ( count($mandatorydatasets )==0){
fe6ce234 303 // $errors['questiontext']=get_string('atleastonewildcard', 'qtype_datasetdependent');
2d279432
PP
304 foreach ($answers as $key => $answer){
305 $errors['answer['.$key.']'] = get_string('atleastonewildcard', 'qtype_datasetdependent');
306 }
307 }
308 if ($data['multichoice']== 1 ){
309 foreach ($answers as $key => $answer){
310 $trimmedanswer = trim($answer);
fe6ce234 311 if (($trimmedanswer!='')||$answercount==0){
2d279432
PP
312 //verifying for errors in {=...} in answer text;
313 $qanswer = "";
314 $qanswerremaining = $trimmedanswer ;
315 $possibledatasets = $this->qtypeobj->find_dataset_names($trimmedanswer);
fe6ce234 316 foreach ($possibledatasets as $name => $value) {
2d279432
PP
317 $qanswerremaining = str_replace('{'.$name.'}', '1', $qanswerremaining);
318 }
fe6ce234 319 // echo "numericalquestion qanswerremaining <pre>";print_r($possibledatasets);
2d279432
PP
320 while (preg_match('~\{=([^[:space:]}]*)}~', $qanswerremaining, $regs1)) {
321 $qanswersplits = explode($regs1[0], $qanswerremaining, 2);
322 $qanswer =$qanswer.$qanswersplits[0];
323 $qanswerremaining = $qanswersplits[1];
324 if (!empty($regs1[1]) && $formulaerrors = qtype_calculated_find_formula_errors($regs1[1])) {
325 if(!isset($errors['answer['.$key.']'])){
326 $errors['answer['.$key.']'] = $formulaerrors.':'.$regs1[1] ;
327 }else {
328 $errors['answer['.$key.']'] .= '<br/>'.$formulaerrors.':'.$regs1[1];
329 }
330 }
331 }
332 }
333 if ($trimmedanswer!=''){
334 if ('2' == $data['correctanswerformat'][$key]
fe6ce234
DC
335 && '0' == $data['correctanswerlength'][$key]) {
336 $errors['correctanswerlength['.$key.']'] = get_string('zerosignificantfiguresnotallowed','quiz');
337 }
2d279432
PP
338 if (!is_numeric($data['tolerance'][$key])){
339 $errors['tolerance['.$key.']'] = get_string('mustbenumeric', 'qtype_calculated');
340 }
341 if ($data['fraction'][$key] == 1) {
fe6ce234 342 $maxgrade = true;
2d279432 343 }
fe6ce234 344
2d279432
PP
345 $answercount++;
346 }
347 //check grades
348 $totalfraction = 0 ;
349 $maxfraction = 0 ;
350 if ($answer != '') {
351 if ($data['fraction'][$key] > 0) {
352 $totalfraction += $data['fraction'][$key];
353 }
354 if ($data['fraction'][$key] > $maxfraction) {
355 $maxfraction = $data['fraction'][$key];
356 }
fe6ce234 357 }
2d279432
PP
358 }
359 if ($answercount==0){
360 $errors['answer[0]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
361 $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
362 } elseif ($answercount==1){
363 $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
fe6ce234 364
2d279432
PP
365 }
366
367 /// Perform sanity checks on fractional grades
368 if ($data['single']) {
369 if ($maxfraction > 0.999 ) {
370 $maxfraction = $maxfraction * 100;
371 $errors['fraction[0]'] = get_string('errfractionsnomax', 'qtype_multichoice', $maxfraction);
372 }
373 } else {
374 $totalfraction = round($totalfraction,2);
375 if ($totalfraction != 1) {
376 $totalfraction = $totalfraction * 100;
377 $errors['fraction[0]'] = get_string('errfractionsaddwrong', 'qtype_multichoice', $totalfraction);
378 }
379 }
fe6ce234 380
2d279432
PP
381 if ($answercount==0){
382 $errors['answer[0]'] = get_string('atleastoneanswer', 'qtype_calculated');
383 }
384 if ($maxgrade == false) {
385 $errors['fraction[0]'] = get_string('fractionsnomax', 'question');
386 }
fe6ce234 387
2d279432
PP
388 }
389 return $errors;
390 }
391}