MDL-20636 fix some more coding style issues in the question code.
[moodle.git] / question / type / multianswer / edit_multianswer_form.php
CommitLineData
aeb15530 1<?php
d3603157
TH
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
271ffe3f 17/**
d3603157 18 * Defines the editing form for the multi-answer question type.
271ffe3f 19 *
b04a4319
TH
20 * @package qtype
21 * @subpackage multianswer
22 * @copyright 2007 Jamie Pratt me@jamiep.org
23 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
271ffe3f 24 */
25
d3603157 26
a17b297d
TH
27defined('MOODLE_INTERNAL') || die();
28
29
271ffe3f 30/**
d3603157 31 * Form for editing multi-answer questions.
b04a4319
TH
32 *
33 * @copyright 2007 Jamie Pratt me@jamiep.org
34 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
271ffe3f 35 */
36class question_edit_multianswer_form extends question_edit_form {
37
705b5874 38 // $questiondisplay will contain the qtype_multianswer_extract_question from the questiontext
fe6ce234 39 public $questiondisplay ;
d3e3bd6c 40 // $savedquestiondisplay will contain the qtype_multianswer_extract_question from the questiontext in database
fe6ce234
DC
41 public $savedquestion ;
42 public $savedquestiondisplay ;
43 public $used_in_quiz = false ;
44 public $qtype_change = false ;
45 public $negative_diff = 0 ;
46 public $nb_of_quiz = 0;
47 public $nb_of_attempts = 0;
d3e3bd6c 48 public $confirm = 0 ;
49 public $reload = false ;
aeb15530 50
d3e3bd6c 51 function question_edit_multianswer_form(&$submiturl, &$question, &$category, &$contexts, $formeditable = true){
52 global $QTYPES, $SESSION, $CFG, $DB;
347fb175 53 $this->regenerate = true;
d3e3bd6c 54 if ( "1" == optional_param('reload','', PARAM_INT )) {
55 $this->reload = true ;
56 }else {
57 $this->reload = false ;
58 }
fe6ce234
DC
59 // $this->question = $question;
60 $this->used_in_quiz =false;
61 // echo "<p> question <pre>";print_r($question);echo "</pre></p>";
347fb175 62 if(isset($question->id) && $question->id != 0 ){
d3e3bd6c 63 $this->savedquestiondisplay =fullclone($question ) ;
64 if ($list = $DB->get_records('quiz_question_instances', array( 'question'=> $question->id))){
65 foreach($list as $key => $li){
66 $this->nb_of_quiz ++;
67 if($att = $DB->get_records('quiz_attempts',array( 'quiz'=> $li->quiz, 'preview'=> '0'))){
68 $this->nb_of_attempts+= count($att);
69 $this->used_in_quiz = true;
70 }
71 }
72 }
73 }
74
d3e3bd6c 75 parent::question_edit_form($submiturl, $question, $category, $contexts, $formeditable);
76 }
77
c7df5006 78 protected function definition_inner($mform) {
347fb175 79 $mform->addElement('hidden', 'reload', 1);
0bc0a265 80 // $mform->addElement('hidden', 'generalfeedback','');
347fb175 81 $mform->setType('reload', PARAM_INT);
705b5874 82
fe648028 83 // Remove meaningless defaultgrade field.
84 $mform->removeElement('defaultgrade');
347fb175 85 $this->confirm = optional_param('confirm','0', PARAM_RAW);
f34488b2 86
fe6ce234 87 // display the questions from questiontext;
705b5874 88 if ( "" != optional_param('questiontext','', PARAM_RAW)) {
0bc0a265 89 // echo "<p> optional_param('questiontext' <pre>";print_r(optional_param('questiontext','', PARAM_RAW));echo "</pre></p>";
f34488b2 90
705b5874 91 $this->questiondisplay = fullclone(qtype_multianswer_extract_question(optional_param('questiontext','', PARAM_RAW))) ;
f34488b2 92
705b5874 93 }else {
aeb15530
PS
94 if(!$this->reload && !empty($this->savedquestiondisplay->id)){
95 // use database data as this is first pass
d3e3bd6c 96 // question->id == 0 so no stored datasets
97 $this->questiondisplay = fullclone($this->savedquestiondisplay);
98 foreach($this->questiondisplay->options->questions as $subquestion){
fe6ce234
DC
99 if (!empty($subquestion)){
100 $subquestion->answer = array('');
101 foreach($subquestion->options->answers as $ans){
102 $subquestion->answer[]=$ans->answer ;
103 }
104 // $subquestion->answer = fullclone($subquestion->options->answers);
d3e3bd6c 105 }
aeb15530 106 }
aeb15530 107 }else {
d3e3bd6c 108 $this->questiondisplay = "";
109 }
f34488b2 110 }
705b5874 111
d3e3bd6c 112 if ( isset($this->savedquestiondisplay->options->questions) && is_array($this->savedquestiondisplay->options->questions) ) {
113 $countsavedsubquestions =0;
114 foreach($this->savedquestiondisplay->options->questions as $subquestion){
103a800d 115 if (!empty($subquestion)){
fe6ce234 116 $countsavedsubquestions++;
df79079f 117 }
f34488b2 118 }
705b5874 119 } else {
d3e3bd6c 120 $countsavedsubquestions =0;
705b5874 121 }
d3e3bd6c 122 if ($this->reload){
123 if ( isset($this->questiondisplay->options->questions) && is_array($this->questiondisplay->options->questions) ) {
124 $countsubquestions =0;
125 foreach($this->questiondisplay->options->questions as $subquestion){
126 if (!empty($subquestion)){
fe6ce234 127 $countsubquestions++;
d3e3bd6c 128 }
129 }
fe6ce234
DC
130 } else {
131 $countsubquestions =0;
705b5874 132 }
fe6ce234
DC
133 }else{
134 $countsubquestions =$countsavedsubquestions ;
135 }
0bc0a265
PP
136 // echo "<p> count subquestion $countsubquestions <pre>";print_r($this->savedquestiondisplay);echo "</pre></p>";
137 // // echo "<p> saved question $countsubquestions <pre>";print_r($this->questiondisplay);echo "</pre></p>";
aeb15530
PS
138
139
fe6ce234
DC
140 $mform->addElement('submit', 'analyzequestion', get_string('decodeverifyquestiontext','qtype_multianswer'));
141 $mform->registerNoSubmitButton('analyzequestion');
fe6ce234 142 if ( $this->reload ){
5bb96cf6
TH
143 $mform->addElement('html', '<div class="ablock clearfix">');
144 $mform->addElement('html', '<div class=" clearfix">');
d3e3bd6c 145 for ($sub =1;$sub <=$countsubquestions ;$sub++) {
aeb15530 146
d3e3bd6c 147 $this->editas[$sub] = 'unknown type';
148 if (isset( $this->questiondisplay->options->questions[$sub]->qtype) ) {
149 $this->editas[$sub] = $this->questiondisplay->options->questions[$sub]->qtype ;
150 } else if (optional_param('sub_'.$sub."_".'qtype', '', PARAM_RAW) != '') {
151 $this->editas[$sub] = optional_param('sub_'.$sub."_".'qtype', '', PARAM_RAW);
fd97082c 152 }
d3e3bd6c 153 $storemess = '';
fe6ce234
DC
154 if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
155 $this->savedquestiondisplay->options->questions[$sub]->qtype != $this->questiondisplay->options->questions[$sub]->qtype ){
156 $this->qtype_change = true ;
d649fb02 157 $storemess = "<font class=\"error\"> STORED QTYPE ".question_bank::get_qtype_name($this->savedquestiondisplay->options->questions[$sub]->qtype)."</font >";
fe6ce234 158 }
aeb15530 159
5e8a85aa 160 $mform->addElement('header', 'subhdr'.$sub, get_string('questionno', 'question',
d649fb02 161 '{#'.$sub.'}').'&nbsp;'.question_bank::get_qtype_name($this->questiondisplay->options->questions[$sub]->qtype).$storemess);
aeb15530 162
d3e3bd6c 163 $mform->addElement('static', 'sub_'.$sub."_".'questiontext', get_string('questiondefinition','qtype_multianswer'),array('cols'=>60, 'rows'=>3));
aeb15530 164
d3e3bd6c 165 if (isset ( $this->questiondisplay->options->questions[$sub]->questiontext)) {
0bc0a265 166 $mform->setDefault('sub_'.$sub."_".'questiontext', $this->questiondisplay->options->questions[$sub]->questiontext['text']);
f34488b2 167 }
aeb15530 168
5e8a85aa 169 $mform->addElement('static', 'sub_'.$sub."_".'defaultgrade', get_string('defaultgrade', 'question'));
d3e3bd6c 170 $mform->setDefault('sub_'.$sub."_".'defaultgrade',$this->questiondisplay->options->questions[$sub]->defaultgrade);
aeb15530 171
fe6ce234 172 if ($this->questiondisplay->options->questions[$sub]->qtype =='shortanswer' ) {
5e8a85aa 173 $mform->addElement('static', 'sub_'.$sub."_".'usecase', get_string('casesensitive', 'question'));
fe6ce234 174 }
aeb15530 175
fe6ce234
DC
176 if ($this->questiondisplay->options->questions[$sub]->qtype =='multichoice' ) {
177 $mform->addElement('static', 'sub_'.$sub."_".'layout', get_string('layout', 'qtype_multianswer'),array('cols'=>60, 'rows'=>1)) ;//, $gradeoptions);
178 }
d3e3bd6c 179 foreach ($this->questiondisplay->options->questions[$sub]->answer as $key =>$ans) {
aeb15530 180
5e8a85aa 181 $mform->addElement('static', 'sub_'.$sub."_".'answer['.$key.']', get_string('answer', 'question'), array('cols'=>60, 'rows'=>1));
aeb15530 182
d3e3bd6c 183 if ($this->questiondisplay->options->questions[$sub]->qtype =='numerical' && $key == 0 ) {
184 $mform->addElement('static', 'sub_'.$sub."_".'tolerance['.$key.']', get_string('acceptederror', 'quiz')) ;//, $gradeoptions);
185 }
aeb15530 186
d3e3bd6c 187 $mform->addElement('static', 'sub_'.$sub."_".'fraction['.$key.']', get_string('grade')) ;//, $gradeoptions);
aeb15530 188
5e8a85aa 189 $mform->addElement('static', 'sub_'.$sub."_".'feedback['.$key.']', get_string('feedback', 'question'));
d3e3bd6c 190 }
aeb15530 191
f34488b2 192 }
5bb96cf6 193 $mform->addElement('html', '</div>');
90a92bd0 194 $this->negative_diff =$countsavedsubquestions - $countsubquestions ;
f26c5297 195 if ( ($this->negative_diff > 0 ) ||$this->qtype_change || ($this->used_in_quiz && $this->negative_diff != 0)){
fe6ce234
DC
196 $mform->addElement('header', 'additemhdr', get_string('warningquestionmodified','qtype_multianswer'));
197 }
90a92bd0 198 if($this->negative_diff > 0) {
fe6ce234 199 $mform->addElement('static', 'alert1', "<strong>".get_string('questiondeleted','qtype_multianswer')."</strong>",get_string('questionsless','qtype_multianswer',$this->negative_diff));
d3e3bd6c 200 }
fe6ce234
DC
201 if($this->qtype_change ) {
202 $mform->addElement('static', 'alert1', "<strong>".get_string('questiontypechanged','qtype_multianswer')."</strong>",get_string('questiontypechangedcomment','qtype_multianswer'));
d3e3bd6c 203 }
5bb96cf6 204 $mform->addElement('html', '</div>');
d3e3bd6c 205 }
206 if( $this->used_in_quiz){
c4979f02
PP
207 if($this->negative_diff < 0) {
208 $diff = $countsubquestions - $countsavedsubquestions;
209 $mform->addElement('static', 'alert1', "<strong>".get_string('questionsadded','qtype_multianswer')."</strong>","<strong>".get_string('questionsmore','qtype_multianswer',$diff)."</strong>");
210 }
0ff4bd08 211 $a = new stdClass() ;
c4979f02
PP
212 $a->nb_of_quiz = $this->nb_of_quiz;
213 $a->nb_of_attempts = $this->nb_of_attempts;
214 $mform->addElement('header', 'additemhdr2', get_string('questionusedinquiz','qtype_multianswer',$a));
215 $mform->addElement('static', 'alertas', get_string('youshouldnot','qtype_multianswer'));
d3e3bd6c 216 }
f26c5297
PP
217 if ( ($this->negative_diff > 0 || $this->used_in_quiz && ($this->negative_diff > 0 ||$this->negative_diff < 0 || $this->qtype_change ) ) && $this->reload ){
218 $mform->addElement('header', 'additemhdr', get_string('questionsaveasedited', 'qtype_multianswer'));
219 $mform->addElement('checkbox', 'confirm','' ,get_string('confirmquestionsaveasedited', 'qtype_multianswer'));
d3e3bd6c 220 $mform->setDefault('confirm', 0);
aeb15530 221 }else {
d3e3bd6c 222 $mform->addElement('hidden', 'confirm',0);
705b5874 223 }
347fb175 224
120e5cbf 225 }
705b5874 226
f34488b2 227
32db0d42 228 function set_data($question) {
f34488b2 229 global $DB;
705b5874 230 $default_values =array();
120e5cbf 231 if (isset($question->id) and $question->id and $question->qtype and $question->questiontext) {
c6fc9988 232
233 foreach ($question->options->questions as $key => $wrapped) {
103a800d 234 if(!empty($wrapped)){
fe6ce234
DC
235 // The old way of restoring the definitions is kept to gradually
236 // update all multianswer questions
237 if (empty($wrapped->questiontext)) {
238 $parsableanswerdef = '{' . $wrapped->defaultgrade . ':';
239 switch ($wrapped->qtype) {
c6fc9988 240 case 'multichoice':
241 $parsableanswerdef .= 'MULTICHOICE:';
242 break;
243 case 'shortanswer':
244 $parsableanswerdef .= 'SHORTANSWER:';
245 break;
246 case 'numerical':
247 $parsableanswerdef .= 'NUMERICAL:';
248 break;
249 default:
2471ef86 250 print_error('unknownquestiontype', 'question', '', $wrapped->qtype);
c6fc9988 251 }
fe6ce234
DC
252 $separator= '';
253 foreach ($wrapped->options->answers as $subanswer) {
254 $parsableanswerdef .= $separator
255 . '%' . round(100*$subanswer->fraction) . '%';
256 $parsableanswerdef .= $subanswer->answer;
257 if (!empty($wrapped->options->tolerance)) {
258 // Special for numerical answers:
259 $parsableanswerdef .= ":{$wrapped->options->tolerance}";
260 // We only want tolerance for the first alternative, it will
261 // be applied to all of the alternatives.
262 unset($wrapped->options->tolerance);
263 }
264 if ($subanswer->feedback) {
265 $parsableanswerdef .= "#$subanswer->feedback";
266 }
267 $separator = '~';
c6fc9988 268 }
fe6ce234
DC
269 $parsableanswerdef .= '}';
270 // Fix the questiontext fields of old questions
271 $DB->set_field('question', 'questiontext', $parsableanswerdef, array('id' => $wrapped->id));
272 } else {
273 $parsableanswerdef = str_replace('&#', '&\#', $wrapped->questiontext);
c6fc9988 274 }
fe6ce234 275 $question->questiontext = str_replace("{#$key}", $parsableanswerdef, $question->questiontext);
c6fc9988 276 }
c6fc9988 277 }
278 }
347fb175 279
705b5874 280 // set default to $questiondisplay questions elements
c4979f02 281 if ( $this->reload ){
fe6ce234
DC
282 if (isset($this->questiondisplay->options->questions)) {
283 $subquestions = fullclone($this->questiondisplay->options->questions) ;
284 if (count($subquestions)) {
285 $sub =1;
286 foreach ($subquestions as $subquestion) {
287 $prefix = 'sub_'.$sub.'_' ;
288
289 // validate parameters
290 $answercount = 0;
291 $maxgrade = false;
292 $maxfraction = -1;
293 if ($subquestion->qtype =='shortanswer' ) {
294 switch ($subquestion->usecase) {
fd97082c 295 case '1':
5e8a85aa 296 $default_values[$prefix.'usecase']= get_string('caseyes', 'qtype_shortanswer');
aeb15530 297 break;
fd97082c 298 case '0':
299 default :
5e8a85aa 300 $default_values[$prefix.'usecase']= get_string('caseno', 'qtype_shortanswer');
fe6ce234 301 }
fd97082c 302 }
fd97082c 303
fe6ce234
DC
304 if ($subquestion->qtype == 'multichoice' ) {
305 $default_values[$prefix.'layout'] = $subquestion->layout ;
306 switch ($subquestion->layout) {
e5ebbd53 307 case '0':
665e82f8 308 $default_values[$prefix.'layout']= get_string('layoutselectinline', 'qtype_multianswer');
e5ebbd53 309 break;
310 case '1':
665e82f8 311 $default_values[$prefix.'layout']= get_string('layoutvertical', 'qtype_multianswer');
aeb15530 312 break;
e5ebbd53 313 case '2':
665e82f8 314 $default_values[$prefix.'layout']= get_string('layouthorizontal', 'qtype_multianswer');
e5ebbd53 315 break;
316 default:
665e82f8 317 $default_values[$prefix.'layout']= get_string('layoutundefined', 'qtype_multianswer');
fe6ce234 318 }
aeb15530 319 }
fe6ce234
DC
320 foreach ($subquestion->answer as $key=>$answer) {
321 if ( $subquestion->qtype == 'numerical' && $key == 0 ) {
322 $default_values[$prefix.'tolerance['.$key.']'] = $subquestion->tolerance[0] ;
705b5874 323 }
fe6ce234
DC
324 $trimmedanswer = trim($answer);
325 if ($trimmedanswer !== '') {
326 $answercount++;
327 if ($subquestion->qtype == 'numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
328 $this->_form->setElementError($prefix.'answer['.$key.']' , get_string('answermustbenumberorstar', 'qtype_numerical'));
329 }
330 if ($subquestion->fraction[$key] == 1) {
331 $maxgrade = true;
332 }
333 if ($subquestion->fraction[$key] > $maxfraction) {
334 $maxfraction = $subquestion->fraction[$key] ;
335 }
f34488b2 336 }
fe6ce234
DC
337
338 $default_values[$prefix.'answer['.$key.']'] = htmlspecialchars ($answer);
339 }
340 if ($answercount == 0) {
341 if ($subquestion->qtype == 'multichoice' ) {
342 $this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'qtype_multichoice', 2));
343 } else {
5e8a85aa 344 $this->_form->setElementError($prefix.'answer[0]' , get_string('notenoughanswers', 'question', 1));
705b5874 345 }
346 }
fe6ce234
DC
347 if ($maxgrade == false) {
348 $this->_form->setElementError($prefix.'fraction[0]' ,get_string('fractionsnomax', 'question'));
705b5874 349 }
fe6ce234 350 foreach ($subquestion->feedback as $key=>$answer) {
f34488b2 351
0bc0a265 352 $default_values[$prefix.'feedback['.$key.']'] = htmlspecialchars ($answer['text']);
fe6ce234
DC
353 }
354 foreach ( $subquestion->fraction as $key=>$answer) {
355 $default_values[$prefix.'fraction['.$key.']'] = $answer;
356 }
f34488b2 357
358
fe6ce234
DC
359 $sub++;
360 }
705b5874 361 }
362 }
363 }
fe6ce234 364 $default_values['alertas']= "<strong>".get_string('questioninquiz','qtype_multianswer')."</strong>";
347fb175 365
d3e3bd6c 366 if( $default_values != "") {
705b5874 367 $question = (object)((array)$question + $default_values);
368 }
120e5cbf 369 parent::set_data($question);
370 }
371
a78890d5 372 function validation($data, $files) {
373 $errors = parent::validation($data, $files);
8e8f9f3d 374
0bc0a265
PP
375 $questiondisplay = qtype_multianswer_extract_question($data['questiontext']);
376// echo "<p> questiondisplay ".$data['questiontext']['text']." <pre>";print_r($questiondisplay);echo "</pre></p>";
f34488b2 377
347fb175 378 if (isset($questiondisplay->options->questions)) {
fe6ce234 379 $subquestions = fullclone($questiondisplay->options->questions) ;
705b5874 380 if (count($subquestions)) {
f34488b2 381 $sub =1;
382 foreach ($subquestions as $subquestion) {
705b5874 383 $prefix = 'sub_'.$sub.'_' ;
384 $answercount = 0;
385 $maxgrade = false;
386 $maxfraction = -1;
fe6ce234
DC
387 if(isset($this->savedquestiondisplay->options->questions[$sub]->qtype) &&
388 $this->savedquestiondisplay->options->questions[$sub]->qtype != $questiondisplay->options->questions[$sub]->qtype ){
d649fb02 389 $storemess = " STORED QTYPE ".question_bank::get_qtype_name($this->savedquestiondisplay->options->questions[$sub]->qtype);
fe6ce234 390 }
705b5874 391 foreach ( $subquestion->answer as $key=>$answer) {
392 $trimmedanswer = trim($answer);
393 if ($trimmedanswer !== '') {
394 $answercount++;
395 if ($subquestion->qtype =='numerical' && !(is_numeric($trimmedanswer) || $trimmedanswer == '*')) {
396 $errors[$prefix.'answer['.$key.']']= get_string('answermustbenumberorstar', 'qtype_numerical');
fe6ce234 397 }
705b5874 398 if ($subquestion->fraction[$key] == 1) {
399 $maxgrade = true;
f34488b2 400 }
705b5874 401 if ($subquestion->fraction[$key] > $maxfraction) {
402 $maxfraction = $subquestion->fraction[$key] ;
403 }
f34488b2 404 }
405 }
705b5874 406 if ($answercount==0) {
407 if ( $subquestion->qtype =='multichoice' ) {
408 $errors[$prefix.'answer[0]']= get_string('notenoughanswers', 'qtype_multichoice', 2);
409 }else {
5e8a85aa 410 $errors[$prefix.'answer[0]'] = get_string('notenoughanswers', 'question', 1);
705b5874 411 }
412 }
413 if ($maxgrade == false) {
414 $errors[$prefix.'fraction[0]']=get_string('fractionsnomax', 'question');
f34488b2 415 }
416 $sub++;
705b5874 417 }
418 } else {
f34488b2 419 $errors['questiontext']=get_string('questionsmissing', 'qtype_multianswer');
705b5874 420 }
120e5cbf 421 }
fe6ce234
DC
422 // $question = qtype_multianswer_extract_question($data['questiontext']);
423 // if (isset $question->options->questions
f26c5297 424 if (( $this->negative_diff > 0 || $this->used_in_quiz && ($this->negative_diff > 0 ||$this->negative_diff < 0 || $this->qtype_change ))&& $this->confirm == 0 ){
fe6ce234 425 $errors['confirm']=get_string('confirmsave', 'qtype_multianswer',$this->negative_diff);
347fb175 426 }
705b5874 427
fe6ce234
DC
428
429 return $errors;
c6fc9988 430 }
271ffe3f 431
432 function qtype() {
433 return 'multianswer';
434 }
435}