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