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