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