ILIAS  release_5-4 Revision v5.4.26-12-gabc799a52e6
class.ilAssClozeTestFeedback.php
Go to the documentation of this file.
1<?php
2/* Copyright (c) 1998-2013 ILIAS open source, Extended GPL, see docs/LICENSE */
3
4require_once 'Modules/TestQuestionPool/classes/feedback/class.ilAssMultiOptionQuestionFeedback.php';
5require_once 'Services/Randomization/classes/class.ilArrayElementOrderKeeper.php';
6
16{
20 const FB_MODE_GAP_QUESTION = 'gapQuestion';
21 const FB_MODE_GAP_ANSWERS = 'gapAnswers';
22
27 const FB_TEXT_GAP_NOMATCH_INDEX = -2; // indexes for preset answers: 0 - n
28 const FB_SELECT_GAP_EMPTY_INDEX = -1; // indexes for given select options: 0 - n
34
36
43 protected $questionOBJ = null;
44
51 protected function getGapsByIndex()
52 {
53 return $this->questionOBJ->gaps;
54 }
55
60 {
61 return true;
62 }
63
73 protected function buildGapFeedbackLabel($gapIndex, $gap)
74 {
75 global $DIC; /* @var ILIAS\DI\Container $DIC */
76
77 $answers = array();
78
79 foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $item) {
80 $answers[] = '"' . $item->getAnswertext() . '"';
81 }
82
83 $answers = implode(' / ', $answers);
84
85 $label = sprintf(
86 $DIC->language()->txt('ass_cloze_gap_fb_gap_label'),
87 $gapIndex + 1,
88 $answers
89 );
90
91 return $label;
92 }
93
99 protected function buildTextGapGivenAnswerFeedbackLabel($gapIndex, $item)
100 {
101 global $DIC; /* @var ILIAS\DI\Container $DIC */
102
103 return sprintf(
104 $DIC->language()->txt('ass_cloze_gap_fb_txt_match_label'),
105 $gapIndex + 1,
106 $item->getAnswertext()
107 );
108 }
109
114 protected function buildTextGapWrongAnswerFeedbackLabel($gapIndex)
115 {
116 global $DIC; /* @var ILIAS\DI\Container $DIC */
117 return sprintf($DIC->language()->txt('ass_cloze_gap_fb_txt_nomatch_label'), $gapIndex + 1);
118 }
119
124 protected function buildTextGapEmptyFeedbackLabel($gapIndex)
125 {
126 global $DIC; /* @var ILIAS\DI\Container $DIC */
127 return sprintf($DIC->language()->txt('ass_cloze_gap_fb_txt_empty_label'), $gapIndex + 1);
128 }
129
135 protected function buildSelectGapOptionFeedbackLabel($gapIndex, $item)
136 {
137 global $DIC; /* @var ILIAS\DI\Container $DIC */
138
139 return sprintf(
140 $DIC->language()->txt('ass_cloze_gap_fb_sel_opt_label'),
141 $gapIndex + 1,
142 $item->getAnswertext()
143 );
144 }
145
150 protected function buildSelectGapEmptyFeedbackLabel($gapIndex)
151 {
152 global $DIC; /* @var ILIAS\DI\Container $DIC */
153 return sprintf($DIC->language()->txt('ass_cloze_gap_fb_sel_empty_label'), $gapIndex + 1);
154 }
155
160 protected function buildNumericGapValueHitFeedbackLabel($gapIndex)
161 {
162 global $DIC; /* @var ILIAS\DI\Container $DIC */
163 return sprintf($DIC->language()->txt('ass_cloze_gap_fb_num_valuehit_label'), $gapIndex + 1);
164 }
165
170 protected function buildNumericGapRangeHitFeedbackLabel($gapIndex)
171 {
172 global $DIC; /* @var ILIAS\DI\Container $DIC */
173 return sprintf($DIC->language()->txt('ass_cloze_gap_fb_num_rangehit_label'), $gapIndex + 1);
174 }
175
180 protected function buildNumericGapTooLowFeedbackLabel($gapIndex)
181 {
182 global $DIC; /* @var ILIAS\DI\Container $DIC */
183 return sprintf($DIC->language()->txt('ass_cloze_gap_fb_num_toolow_label'), $gapIndex + 1);
184 }
185
190 protected function buildNumericGapTooHighFeedbackLabel($gapIndex)
191 {
192 global $DIC; /* @var ILIAS\DI\Container $DIC */
193 return sprintf($DIC->language()->txt('ass_cloze_gap_fb_num_toohigh_label'), $gapIndex + 1);
194 }
195
200 protected function buildNumericGapEmptyFeedbackLabel($gapIndex)
201 {
202 global $DIC; /* @var ILIAS\DI\Container $DIC */
203 return sprintf($DIC->language()->txt('ass_cloze_gap_fb_num_empty_label'), $gapIndex + 1);
204 }
205
207 {
208 global $DIC; /* @var ILIAS\DI\Container $DIC */
209
210 if (!$this->questionOBJ->getSelfAssessmentEditingMode()) {
212 $header->setTitle($this->lng->txt('feedback_answers'));
213 $form->addItem($header);
214
215 $feedbackMode = new ilRadioGroupInputGUI(
216 $DIC->language()->txt('ass_cloze_fb_mode'),
217 'feedback_mode'
218 );
219 $feedbackMode->setRequired(true);
220 $form->addItem($feedbackMode);
221
222 $fbModeGapQuestion = new ilRadioOption(
223 $DIC->language()->txt('ass_cloze_fb_mode_gap_qst'),
224 self::FB_MODE_GAP_QUESTION,
225 $DIC->language()->txt('ass_cloze_fb_mode_gap_qst_info')
226 );
227 $this->completeFormPropsForFeedbackModeGapQuestion($fbModeGapQuestion);
228 $feedbackMode->addOption($fbModeGapQuestion);
229
230 $fbModeGapAnswers = new ilRadioOption(
231 $DIC->language()->txt('ass_cloze_fb_mode_gap_answ'),
232 self::FB_MODE_GAP_ANSWERS,
233 $DIC->language()->txt('ass_cloze_fb_mode_gap_answ_info')
234 );
235 $this->completeFormPropsForFeedbackModeGapAnswers($fbModeGapAnswers);
236 $feedbackMode->addOption($fbModeGapAnswers);
237 }
238 }
239
241 {
242 foreach ($this->getGapsByIndex() as $gapIndex => $gap) {
243 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
244 $this->buildGapFeedbackLabel($gapIndex, $gap),
245 true
246 );
247
249 $propertyLabel,
250 $this->buildPostVarForFbFieldPerGapQuestion($gapIndex),
251 $this->questionOBJ->isAdditionalContentEditingModePageObject()
252 ));
253 }
254 }
255
257 {
258 foreach ($this->getGapsByIndex() as $gapIndex => $gap) {
259 switch ($gap->getType()) {
261
262 $this->completeFbPropsForTextGap($fbModeOpt, $gap, $gapIndex);
263 break;
264
266
267 $this->completeFbPropsForSelectGap($fbModeOpt, $gap, $gapIndex);
268 break;
269
271
272 $this->completeFbPropsForNumericGap($fbModeOpt, $gapIndex, $gap);
273 break;
274 }
275 }
276 }
277
283 protected function completeFbPropsForTextGap(ilRadioOption $fbModeOpt, assClozeGap $gap, $gapIndex)
284 {
285 foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $answerIndex => $item) {
286 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
287 $this->buildTextGapGivenAnswerFeedbackLabel($gapIndex, $item),
288 true
289 );
290
291 $propertyPostVar = "feedback_answer_{$gapIndex}_{$answerIndex}";
292
294 $propertyLabel,
295 $propertyPostVar,
296 $this->questionOBJ->isAdditionalContentEditingModePageObject()
297 ));
298 }
299
300 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
301 $this->buildTextGapWrongAnswerFeedbackLabel($gapIndex),
302 true
303 );
304
305 $propertyPostVar = "feedback_answer_{$gapIndex}_" . self::FB_TEXT_GAP_NOMATCH_INDEX;
306
308 $propertyLabel,
309 $propertyPostVar,
310 $this->questionOBJ->isAdditionalContentEditingModePageObject()
311 ));
312
313 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
314 $this->buildTextGapEmptyFeedbackLabel($gapIndex),
315 true
316 );
317
318 $propertyPostVar = "feedback_answer_{$gapIndex}_" . self::FB_TEXT_GAP_EMPTY_INDEX;
319
321 $propertyLabel,
322 $propertyPostVar,
323 $this->questionOBJ->isAdditionalContentEditingModePageObject()
324 ));
325 }
326
332 protected function completeFbPropsForSelectGap(ilRadioOption $fbModeOpt, assClozeGap $gap, $gapIndex)
333 {
334 foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $optIndex => $item) {
335 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
336 $this->buildSelectGapOptionFeedbackLabel($gapIndex, $item),
337 true
338 );
339
340 $propertyPostVar = "feedback_answer_{$gapIndex}_{$optIndex}";
341
343 $propertyLabel,
344 $propertyPostVar,
345 $this->questionOBJ->isAdditionalContentEditingModePageObject()
346 ));
347 }
348
349 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
350 $this->buildSelectGapEmptyFeedbackLabel($gapIndex),
351 true
352 );
353
354 $propertyPostVar = "feedback_answer_{$gapIndex}_" . self::FB_SELECT_GAP_EMPTY_INDEX;
355
357 $propertyLabel,
358 $propertyPostVar,
359 $this->questionOBJ->isAdditionalContentEditingModePageObject()
360 ));
361 }
362
368 protected function completeFbPropsForNumericGap(ilRadioOption $fbModeOpt, $gapIndex, assClozeGap $gap)
369 {
370 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
371 $this->buildNumericGapValueHitFeedbackLabel($gapIndex),
372 true
373 );
374
375 $propertyPostVar = "feedback_answer_{$gapIndex}_" . self::FB_NUMERIC_GAP_VALUE_HIT_INDEX;
376
378 $propertyLabel,
379 $propertyPostVar,
380 $this->questionOBJ->isAdditionalContentEditingModePageObject()
381 ));
382
383 if ($gap->numericRangeExists()) {
384 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
385 $this->buildNumericGapRangeHitFeedbackLabel($gapIndex),
386 true
387 );
388
389 $propertyPostVar = "feedback_answer_{$gapIndex}_" . self::FB_NUMERIC_GAP_RANGE_HIT_INDEX;
390
392 $propertyLabel,
393 $propertyPostVar,
394 $this->questionOBJ->isAdditionalContentEditingModePageObject()
395 ));
396 }
397
398 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
399 $this->buildNumericGapTooLowFeedbackLabel($gapIndex),
400 true
401 );
402
403 $propertyPostVar = "feedback_answer_{$gapIndex}_" . self::FB_NUMERIC_GAP_TOO_LOW_INDEX;
404
406 $propertyLabel,
407 $propertyPostVar,
408 $this->questionOBJ->isAdditionalContentEditingModePageObject()
409 ));
410
411 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
412 $this->buildNumericGapTooHighFeedbackLabel($gapIndex),
413 true
414 );
415
416 $propertyPostVar = "feedback_answer_{$gapIndex}_" . self::FB_NUMERIC_GAP_TOO_HIGH_INDEX;
417
419 $propertyLabel,
420 $propertyPostVar,
421 $this->questionOBJ->isAdditionalContentEditingModePageObject()
422 ));
423
424 $propertyLabel = $this->questionOBJ->prepareTextareaOutput(
425 $this->buildNumericGapEmptyFeedbackLabel($gapIndex),
426 true
427 );
428
429 $propertyPostVar = "feedback_answer_{$gapIndex}_" . self::FB_NUMERIC_GAP_EMPTY_INDEX;
430
432 $propertyLabel,
433 $propertyPostVar,
434 $this->questionOBJ->isAdditionalContentEditingModePageObject()
435 ));
436 }
437
439 {
440 if (!$this->questionOBJ->getSelfAssessmentEditingMode()) {
441 /* @var ilRadioGroupInputGUI $fbMode */
442 $fbMode = $form->getItemByPostVar('feedback_mode');
443 $fbMode->setValue($this->questionOBJ->getFeedbackMode());
444
445 if ($this->questionOBJ->isAdditionalContentEditingModePageObject()) {
448 } else {
449 switch ($this->questionOBJ->getFeedbackMode()) {
451
453 break;
454
456
458 break;
459 }
460 }
461 }
462 }
463
465 {
466 foreach ($this->getGapsByIndex() as $gapIndex => $gap) {
467 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, self::SINGLE_GAP_FB_ANSWER_INDEX);
468 $form->getItemByPostVar($this->buildPostVarForFbFieldPerGapQuestion($gapIndex))->setValue($value);
469 }
470 }
471
473 {
474 foreach ($this->getGapsByIndex() as $gapIndex => $gap) {
475 switch ($gap->getType()) {
477
478 $this->initFbPropsForTextGap($form, $gap, $gapIndex);
479 break;
480
482
483 $this->initFbPropsForSelectGap($form, $gap, $gapIndex);
484 break;
485
487
488 $this->initFbPropsForNumericGap($form, $gapIndex, $gap);
489 break;
490 }
491 }
492 }
493
494 protected function initFbPropsForTextGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
495 {
496 foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $answerIndex => $item) {
497 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, $answerIndex);
498 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, $answerIndex);
499 $form->getItemByPostVar($postVar)->setValue($value);
500 }
501
502 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, self::FB_TEXT_GAP_NOMATCH_INDEX);
503 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_TEXT_GAP_NOMATCH_INDEX);
504 $form->getItemByPostVar($postVar)->setValue($value);
505
506 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, self::FB_TEXT_GAP_EMPTY_INDEX);
507 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_TEXT_GAP_EMPTY_INDEX);
508 $form->getItemByPostVar($postVar)->setValue($value);
509 }
510
511 protected function initFbPropsForSelectGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
512 {
513 foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $optIndex => $item) {
514 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, $optIndex);
515 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, $optIndex);
516 $form->getItemByPostVar($postVar)->setValue($value);
517 }
518
519 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, self::FB_SELECT_GAP_EMPTY_INDEX);
520 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_SELECT_GAP_EMPTY_INDEX);
521 $form->getItemByPostVar($postVar)->setValue($value);
522 }
523
524 protected function initFbPropsForNumericGap(ilPropertyFormGUI $form, $gapIndex, assClozeGap $gap)
525 {
526 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, self::FB_NUMERIC_GAP_VALUE_HIT_INDEX);
527 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_VALUE_HIT_INDEX);
528 $form->getItemByPostVar($postVar)->setValue($value);
529
530 if ($gap->numericRangeExists()) {
531 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, self::FB_NUMERIC_GAP_RANGE_HIT_INDEX);
532 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_RANGE_HIT_INDEX);
533 $form->getItemByPostVar($postVar)->setValue($value);
534 }
535
536 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, self::FB_NUMERIC_GAP_TOO_LOW_INDEX);
537 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_TOO_LOW_INDEX);
538 $form->getItemByPostVar($postVar)->setValue($value);
539
540 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, self::FB_NUMERIC_GAP_TOO_HIGH_INDEX);
541 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_TOO_HIGH_INDEX);
542 $form->getItemByPostVar($postVar)->setValue($value);
543
544 $value = $this->getSpecificAnswerFeedbackFormValue($gapIndex, self::FB_NUMERIC_GAP_EMPTY_INDEX);
545 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_EMPTY_INDEX);
546 $form->getItemByPostVar($postVar)->setValue($value);
547 }
548
550 {
551 if (!$this->questionOBJ->getSelfAssessmentEditingMode()) {
552 $fbMode = $form->getItemByPostVar('feedback_mode')->getValue();
553
554 if ($fbMode != $this->questionOBJ->getFeedbackMode()) {
555 $this->cleanupSpecificAnswerFeedbacks($this->questionOBJ->getFeedbackMode());
556 }
557
558 $this->saveSpecificFeedbackMode($this->questionOBJ->getId(), $fbMode);
559
560 switch ($this->questionOBJ->getFeedbackMode()) {
562
564 break;
565
567
569 break;
570 }
571 }
572 }
573
575 {
576 foreach ($this->getGapsByIndex() as $gapIndex => $gap) {
577 $postVar = $this->buildPostVarForFbFieldPerGapQuestion($gapIndex);
578 $value = $form->getItemByPostVar($postVar)->getValue();
579
581 $this->questionOBJ->getId(),
582 $gapIndex,
583 self::SINGLE_GAP_FB_ANSWER_INDEX,
584 $value
585 );
586 }
587 }
588
590 {
591 foreach ($this->getGapsByIndex() as $gapIndex => $gap) {
592 switch ($gap->getType()) {
594
595 $this->saveFbPropsForTextGap($form, $gap, $gapIndex);
596 break;
597
599
600 $this->saveFbPropsForSelectGap($form, $gap, $gapIndex);
601 break;
602
604
605 $this->saveFbPropsForNumericGap($form, $gapIndex, $gap);
606 break;
607 }
608 }
609 }
610
611 protected function saveFbPropsForTextGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
612 {
613 foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $answerIndex => $item) {
614 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, $answerIndex);
615 $value = $form->getItemByPostVar($postVar)->getValue();
617 $this->questionOBJ->getId(),
618 $gapIndex,
619 $answerIndex,
620 $value
621 );
622 }
623
624 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_TEXT_GAP_NOMATCH_INDEX);
625 $value = $form->getItemByPostVar($postVar)->getValue();
627 $this->questionOBJ->getId(),
628 $gapIndex,
629 self::FB_TEXT_GAP_NOMATCH_INDEX,
630 $value
631 );
632
633 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_TEXT_GAP_EMPTY_INDEX);
634 $value = $form->getItemByPostVar($postVar)->getValue();
636 $this->questionOBJ->getId(),
637 $gapIndex,
638 self::FB_TEXT_GAP_EMPTY_INDEX,
639 $value
640 );
641 }
642
643 protected function saveFbPropsForSelectGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
644 {
645 foreach ($gap->getItems(new ilArrayElementOrderKeeper()) as $optIndex => $item) {
646 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, $optIndex);
647 $value = $form->getItemByPostVar($postVar)->getValue();
649 $this->questionOBJ->getId(),
650 $gapIndex,
651 $optIndex,
652 $value
653 );
654 }
655
656 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_SELECT_GAP_EMPTY_INDEX);
657 $value = $form->getItemByPostVar($postVar)->getValue();
659 $this->questionOBJ->getId(),
660 $gapIndex,
661 self::FB_SELECT_GAP_EMPTY_INDEX,
662 $value
663 );
664 }
665
666 protected function saveFbPropsForNumericGap(ilPropertyFormGUI $form, $gapIndex, assClozeGap $gap)
667 {
668 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_VALUE_HIT_INDEX);
669 $value = $form->getItemByPostVar($postVar)->getValue();
671 $this->questionOBJ->getId(),
672 $gapIndex,
673 self::FB_NUMERIC_GAP_VALUE_HIT_INDEX,
674 $value
675 );
676
677 if ($gap->numericRangeExists()) {
678 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_RANGE_HIT_INDEX);
679 $value = $form->getItemByPostVar($postVar)->getValue();
681 $this->questionOBJ->getId(),
682 $gapIndex,
683 self::FB_NUMERIC_GAP_RANGE_HIT_INDEX,
684 $value
685 );
686 }
687
688 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_TOO_LOW_INDEX);
689 $value = $form->getItemByPostVar($postVar)->getValue();
691 $this->questionOBJ->getId(),
692 $gapIndex,
693 self::FB_NUMERIC_GAP_TOO_LOW_INDEX,
694 $value
695 );
696
697 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_TOO_HIGH_INDEX);
698 $value = $form->getItemByPostVar($postVar)->getValue();
700 $this->questionOBJ->getId(),
701 $gapIndex,
702 self::FB_NUMERIC_GAP_TOO_HIGH_INDEX,
703 $value
704 );
705
706 $postVar = $this->buildPostVarForFbFieldPerGapAnswers($gapIndex, self::FB_NUMERIC_GAP_EMPTY_INDEX);
707 $value = $form->getItemByPostVar($postVar)->getValue();
709 $this->questionOBJ->getId(),
710 $gapIndex,
711 self::FB_NUMERIC_GAP_EMPTY_INDEX,
712 $value
713 );
714 }
715
726 protected function duplicateSpecificFeedback($originalQuestionId, $duplicateQuestionId)
727 {
728 // sync specific feedback setting to duplicated question
729
730 $this->syncSpecificFeedbackSetting($originalQuestionId, $duplicateQuestionId);
731
732 parent::duplicateSpecificFeedback($originalQuestionId, $duplicateQuestionId);
733 }
734
735 private function syncSpecificFeedbackSetting($sourceQuestionId, $targetQuestionId)
736 {
737 $res = $this->db->queryF(
738 "SELECT feedback_mode FROM {$this->questionOBJ->getAdditionalTableName()} WHERE question_fi = %s",
739 array('integer'),
740 array($sourceQuestionId)
741 );
742
743 $row = $this->db->fetchAssoc($res);
744
745 $this->db->update(
746 $this->questionOBJ->getAdditionalTableName(),
747 array( 'feedback_mode' => array('text', $row['feedback_mode']) ),
748 array( 'question_fi' => array('integer', $targetQuestionId) )
749 );
750 }
751
752 protected function syncSpecificFeedback($originalQuestionId, $duplicateQuestionId)
753 {
754 $this->syncSpecificFeedbackSetting($originalQuestionId, $duplicateQuestionId);
755 parent::syncSpecificFeedback($originalQuestionId, $duplicateQuestionId);
756 }
757
764 protected function saveSpecificFeedbackMode($questionId, $feedbackMode)
765 {
766 $this->questionOBJ->setFeedbackMode($feedbackMode);
767
768 $this->db->update(
769 $this->questionOBJ->getAdditionalTableName(),
770 array('feedback_mode' => array('text', $feedbackMode)),
771 array('question_fi' => array('integer', $questionId))
772 );
773 }
774
779 protected function buildPostVarForFbFieldPerGapQuestion($gapIndex)
780 {
781 return "feedback_answer_{$gapIndex}";
782 }
783
789 protected function buildPostVarForFbFieldPerGapAnswers($gapIndex, $answerIndex)
790 {
791 return "feedback_answer_{$gapIndex}_{$answerIndex}";
792 }
793
799 protected function getSpecificAnswerFeedbackFormValue($gapIndex, $answerIndex)
800 {
801 if ($this->questionOBJ->isAdditionalContentEditingModePageObject()) {
802 $pageObjectId = $this->getSpecificAnswerFeedbackPageObjectId(
803 $this->questionOBJ->getId(),
804 $gapIndex,
805 $answerIndex
806 );
807
808 $value = $this->getPageObjectNonEditableValueHTML(
810 $pageObjectId
811 );
812 } else {
813 $value = $this->questionOBJ->prepareTextareaOutput(
814 $this->getSpecificAnswerFeedbackContent($this->questionOBJ->getId(), $gapIndex, $answerIndex)
815 );
816 }
817
818 return $value;
819 }
820
821 protected function cleanupSpecificAnswerFeedbacks($fbMode)
822 {
823 switch ($fbMode) {
825 $feedbackIds = $this->fetchFeedbackIdsForGapQuestionMode();
826 break;
827
829 $feedbackIds = $this->fetchFeedbackIdsForGapAnswersMode();
830 break;
831
832 default: $feedbackIds = array();
833 }
834
835 $this->deleteSpecificAnswerFeedbacksByIds($feedbackIds);
836 }
837
839 {
840 require_once 'Modules/TestQuestionPool/classes/feedback/class.ilAssSpecificFeedbackIdentifierList.php';
841 $feedbackIdentifiers = new ilAssSpecificFeedbackIdentifierList();
842 $feedbackIdentifiers->load($this->questionOBJ->getId());
843
844 $feedbackIds = array();
845
846 foreach ($feedbackIdentifiers as $identifier) {
847 if ($identifier->getAnswerIndex() != self::SINGLE_GAP_FB_ANSWER_INDEX) {
848 continue;
849 }
850
851 $feedbackIds[] = $identifier->getFeedbackId();
852 }
853
854 return $feedbackIds;
855 }
856
858 {
859 require_once 'Modules/TestQuestionPool/classes/feedback/class.ilAssSpecificFeedbackIdentifierList.php';
860 $feedbackIdentifiers = new ilAssSpecificFeedbackIdentifierList();
861 $feedbackIdentifiers->load($this->questionOBJ->getId());
862
863 $feedbackIds = array();
864
865 foreach ($feedbackIdentifiers as $identifier) {
866 if ($identifier->getAnswerIndex() == self::SINGLE_GAP_FB_ANSWER_INDEX) {
867 continue;
868 }
869
870 $feedbackIds[] = $identifier->getFeedbackId();
871 }
872
873 return $feedbackIds;
874 }
875
876 protected function deleteSpecificAnswerFeedbacksByIds($feedbackIds)
877 {
878 if ($this->questionOBJ->isAdditionalContentEditingModePageObject()) {
879 foreach ($feedbackIds as $fbId) {
881 }
882 }
883
884 $IN_feedbackIds = $this->db->in('feedback_id', $feedbackIds, false, 'integer');
885 $this->db->manipulate("DELETE FROM {$this->getSpecificFeedbackTableName()} WHERE {$IN_feedbackIds}");
886 }
887
888 public function determineTestOutputGapFeedback($gapIndex, $answerIndex)
889 {
890 if ($this->questionOBJ->getFeedbackMode() == self::FB_MODE_GAP_QUESTION) {
892 $this->questionOBJ->getId(),
893 $gapIndex,
894 self::SINGLE_GAP_FB_ANSWER_INDEX
895 );
896 }
897
898 return $this->getSpecificAnswerFeedbackTestPresentation($this->questionOBJ->getId(), $gapIndex, $answerIndex);
899 }
900
901 public function determineAnswerIndexForAnswerValue(assClozeGap $gap, $answerValue)
902 {
903 switch ($gap->getType()) {
904 case CLOZE_TEXT:
905
906 if (!strlen($answerValue)) {
908 }
909
910 $items = $gap->getItems(new ilArrayElementOrderKeeper());
911
912 foreach ($items as $answerIndex => $answer) {
913 /* @var assAnswerCloze $answer */
914
915 if ($answer->getAnswertext() == $answerValue) {
916 return $answerIndex;
917 }
918 }
919
921
922 case CLOZE_SELECT:
923
924 if (strlen($answerValue)) {
925 return $answerValue;
926 }
927
929
930 case CLOZE_NUMERIC:
931
932 if (!strlen($answerValue)) {
934 }
935
936 /* @var assAnswerCloze $item */
937
938 $item = current($gap->getItems(new ilArrayElementOrderKeeper()));
939
940 if ($answerValue == $item->getAnswertext()) {
942 }
943
944 require_once 'Services/Math/classes/class.EvalMath.php';
945 $math = new EvalMath();
946
947 $item = $gap->getItem(0);
948 $lowerBound = $math->evaluate($item->getLowerBound());
949 $upperBound = $math->evaluate($item->getUpperBound());
950 $preciseValue = $math->evaluate($item->getAnswertext());
951
952 $solutionValue = $math->evaluate($answerValue);
953
954 if ($solutionValue == $preciseValue) {
956 }
957
958 if ($solutionValue >= $lowerBound && $solutionValue <= $upperBound) {
960 }
961
962 if ($solutionValue < $lowerBound) {
964 }
965
966 if ($solutionValue > $upperBound) {
968 }
969 }
970 }
971}
An exception for terminatinating execution or to throw for unit testing.
Class for cloze question gaps.
getItems(ilArrayElementShuffler $shuffler)
Gets the items of a cloze gap.
getType()
Gets the cloze gap type.
getItem($a_index)
Gets the item with a given index.
buildGapFeedbackLabel($gapIndex, $gap)
builds an answer option label from given (mixed type) index and answer (overwrites parent method from...
saveFbPropsForSelectGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
initFbPropsForNumericGap(ilPropertyFormGUI $form, $gapIndex, assClozeGap $gap)
const FB_MODE_GAP_QUESTION
constants for different feedback modes (per gap or per gap-answers/options)
completeFormPropsForFeedbackModeGapQuestion(ilRadioOption $fbModeOpt)
completeFormPropsForFeedbackModeGapAnswers(ilRadioOption $fbModeOpt)
buildPostVarForFbFieldPerGapAnswers($gapIndex, $answerIndex)
initFbPropsForSelectGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
getSpecificAnswerFeedbackFormValue($gapIndex, $answerIndex)
getGapsByIndex()
returns the answer options mapped by answer index (overwrites parent method from ilAssMultiOptionQues...
saveFbPropsForTextGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
buildTextGapGivenAnswerFeedbackLabel($gapIndex, $item)
saveFbPropsForNumericGap(ilPropertyFormGUI $form, $gapIndex, assClozeGap $gap)
initFbPropsForTextGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
saveSpecificFeedbackMode($questionId, $feedbackMode)
completeFbPropsForNumericGap(ilRadioOption $fbModeOpt, $gapIndex, assClozeGap $gap)
const FB_TEXT_GAP_EMPTY_INDEX
constants for answer indexes in case of FB_MODE_GAP_ANSWERS
initFeedbackFieldsPerGapQuestion(ilPropertyFormGUI $form)
syncSpecificFeedbackSetting($sourceQuestionId, $targetQuestionId)
syncSpecificFeedback($originalQuestionId, $duplicateQuestionId)
syncs the SPECIFIC feedback from a duplicated question back to the original question
initSpecificFormProperties(ilPropertyFormGUI $form)
initialises a given form object's specific form properties relating to this question type
saveFeedbackFieldsPerGapQuestion(ilPropertyFormGUI $form)
completeFbPropsForTextGap(ilRadioOption $fbModeOpt, assClozeGap $gap, $gapIndex)
saveSpecificFormProperties(ilPropertyFormGUI $form)
saves a given form object's specific form properties relating to this question type
buildSelectGapOptionFeedbackLabel($gapIndex, $item)
completeSpecificFormProperties(ilPropertyFormGUI $form)
completes a given form object with the specific form properties required by this question type
determineAnswerIndexForAnswerValue(assClozeGap $gap, $answerValue)
determineTestOutputGapFeedback($gapIndex, $answerIndex)
initFeedbackFieldsPerGapAnswers(ilPropertyFormGUI $form)
completeFbPropsForSelectGap(ilRadioOption $fbModeOpt, assClozeGap $gap, $gapIndex)
saveFeedbackFieldsPerGapAnswers(ilPropertyFormGUI $form)
duplicateSpecificFeedback($originalQuestionId, $duplicateQuestionId)
duplicates the SPECIFIC feedback relating to the given original question id and saves it for the give...
getSpecificAnswerFeedbackContent($questionId, $questionIndex, $answerIndex)
returns the SPECIFIC answer feedback content for a given question id and answer index.
getSpecificAnswerFeedbackTestPresentation($questionId, $questionIndex, $answerIndex)
returns the html of SPECIFIC feedback for the given question id and answer index for test presentatio...
saveSpecificAnswerFeedbackContent($questionId, $questionIndex, $answerIndex, $feedbackContent)
saves SPECIFIC answer feedback content for the given question id and answer index to the database.
getSpecificAnswerFeedbackPageObjectId($questionId, $questionIndex, $answerIndex)
returns a useable page object id for specific answer feedback page objects for the given question id ...
getPageObjectNonEditableValueHTML($pageObjectType, $pageObjectId)
returns html content to be used as value for non editable value form properties in feedback editing f...
getSpecificAnswerFeedbackPageObjectType()
returns the type for specific feedback page objects defined in local constant
ensurePageObjectDeleted($pageObjectType, $pageObjectId)
ensures a no more existing page object for given type and id
buildFeedbackContentFormProperty($label, $postVar, $asNonEditable)
builds and returns a form property gui object with the given label and postvar that is addable to pro...
This class represents a section header in a property form.
This class represents a property form user interface.
This class represents a property in a property form.
This class represents an option in a radio group.
addSubItem($a_item)
Add Subitem.
const CLOZE_NUMERIC
const CLOZE_SELECT
const CLOZE_TEXT
Cloze question constants.
$row
if(isset($_POST['submit'])) $form
global $DIC
Definition: saml.php:7
foreach($_POST as $key=> $value) $res