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 
4 require_once 'Modules/TestQuestionPool/classes/feedback/class.ilAssMultiOptionQuestionFeedback.php';
5 require_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 
248  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
293  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
307  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
320  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
342  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
356  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
377  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
391  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
405  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
418  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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 
431  $fbModeOpt->addSubItem($this->buildFeedbackContentFormProperty(
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()) {
446  $this->initFeedbackFieldsPerGapQuestion($form);
447  $this->initFeedbackFieldsPerGapAnswers($form);
448  } else {
449  switch ($this->questionOBJ->getFeedbackMode()) {
450  case self::FB_MODE_GAP_QUESTION:
451 
452  $this->initFeedbackFieldsPerGapQuestion($form);
453  break;
454 
455  case self::FB_MODE_GAP_ANSWERS:
456 
457  $this->initFeedbackFieldsPerGapAnswers($form);
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()) {
561  case self::FB_MODE_GAP_QUESTION:
562 
563  $this->saveFeedbackFieldsPerGapQuestion($form);
564  break;
565 
566  case self::FB_MODE_GAP_ANSWERS:
567 
568  $this->saveFeedbackFieldsPerGapAnswers($form);
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) {
824  case self::FB_MODE_GAP_QUESTION:
825  $feedbackIds = $this->fetchFeedbackIdsForGapQuestionMode();
826  break;
827 
828  case self::FB_MODE_GAP_ANSWERS:
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)) {
907  return self::FB_TEXT_GAP_EMPTY_INDEX;
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 
920  return self::FB_TEXT_GAP_NOMATCH_INDEX;
921 
922  case CLOZE_SELECT:
923 
924  if (strlen($answerValue)) {
925  return $answerValue;
926  }
927 
928  return self::FB_SELECT_GAP_EMPTY_INDEX;
929 
930  case CLOZE_NUMERIC:
931 
932  if (!strlen($answerValue)) {
933  return self::FB_NUMERIC_GAP_EMPTY_INDEX;
934  }
935 
936  /* @var assAnswerCloze $item */
937 
938  $item = current($gap->getItems(new ilArrayElementOrderKeeper()));
939 
940  if ($answerValue == $item->getAnswertext()) {
941  return self::FB_NUMERIC_GAP_VALUE_HIT_INDEX;
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) {
955  return self::FB_NUMERIC_GAP_VALUE_HIT_INDEX;
956  }
957 
958  if ($solutionValue >= $lowerBound && $solutionValue <= $upperBound) {
959  return self::FB_NUMERIC_GAP_RANGE_HIT_INDEX;
960  }
961 
962  if ($solutionValue < $lowerBound) {
963  return self::FB_NUMERIC_GAP_TOO_LOW_INDEX;
964  }
965 
966  if ($solutionValue > $upperBound) {
967  return self::FB_NUMERIC_GAP_TOO_HIGH_INDEX;
968  }
969  }
970  }
971 }
determineTestOutputGapFeedback($gapIndex, $answerIndex)
This class represents an option in a radio group.
initFeedbackFieldsPerGapAnswers(ilPropertyFormGUI $form)
getSpecificAnswerFeedbackPageObjectId($questionId, $questionIndex, $answerIndex)
returns a useable page object id for specific answer feedback page objects for the given question id ...
getItemByPostVar($a_post_var)
Get Item by POST variable.
initFeedbackFieldsPerGapQuestion(ilPropertyFormGUI $form)
completeFormPropsForFeedbackModeGapQuestion(ilRadioOption $fbModeOpt)
getPageObjectNonEditableValueHTML($pageObjectType, $pageObjectId)
returns html content to be used as value for non editable value form properties in feedback editing f...
This class represents a property form user interface.
global $DIC
Definition: saml.php:7
getSpecificAnswerFeedbackPageObjectType()
returns the type for specific feedback page objects defined in local constant
const CLOZE_TEXT
Cloze question constants.
This class represents a section header in a property form.
completeFormPropsForFeedbackModeGapAnswers(ilRadioOption $fbModeOpt)
determineAnswerIndexForAnswerValue(assClozeGap $gap, $answerValue)
saveSpecificAnswerFeedbackContent($questionId, $questionIndex, $answerIndex, $feedbackContent)
saves SPECIFIC answer feedback content for the given question id and answer index to the database...
saveFbPropsForNumericGap(ilPropertyFormGUI $form, $gapIndex, assClozeGap $gap)
initFbPropsForNumericGap(ilPropertyFormGUI $form, $gapIndex, assClozeGap $gap)
completeFbPropsForTextGap(ilRadioOption $fbModeOpt, assClozeGap $gap, $gapIndex)
addItem($a_item)
Add Item (Property, SectionHeader).
Class for cloze question gaps.
saveFbPropsForSelectGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
buildPostVarForFbFieldPerGapAnswers($gapIndex, $answerIndex)
buildSelectGapOptionFeedbackLabel($gapIndex, $item)
saveSpecificFormProperties(ilPropertyFormGUI $form)
initSpecificFormProperties(ilPropertyFormGUI $form)
syncSpecificFeedbackSetting($sourceQuestionId, $targetQuestionId)
getSpecificAnswerFeedbackFormValue($gapIndex, $answerIndex)
const CLOZE_SELECT
This class represents a property in a property form.
getSpecificAnswerFeedbackTestPresentation($questionId, $questionIndex, $answerIndex)
returns the html of SPECIFIC feedback for the given question id and answer index for test presentatio...
foreach($_POST as $key=> $value) $res
buildTextGapGivenAnswerFeedbackLabel($gapIndex, $item)
if(isset($_POST['submit'])) $form
addSubItem($a_item)
Add Subitem.
completeSpecificFormProperties(ilPropertyFormGUI $form)
completeFbPropsForNumericGap(ilRadioOption $fbModeOpt, $gapIndex, assClozeGap $gap)
syncSpecificFeedback($originalQuestionId, $duplicateQuestionId)
saveSpecificFeedbackMode($questionId, $feedbackMode)
saves the given specific feedback mode for the given question id to the db.
getItems(ilArrayElementShuffler $shuffler)
Gets the items of a cloze gap.
initFbPropsForSelectGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
$row
const FB_TEXT_GAP_EMPTY_INDEX
constants for answer indexes in case of FB_MODE_GAP_ANSWERS
ensurePageObjectDeleted($pageObjectType, $pageObjectId)
ensures a no more existing page object for given type and id
initFbPropsForTextGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
getGapsByIndex()
returns the answer options mapped by answer index (overwrites parent method from ilAssMultiOptionQues...
saveFeedbackFieldsPerGapQuestion(ilPropertyFormGUI $form)
getSpecificAnswerFeedbackContent($questionId, $questionIndex, $answerIndex)
returns the SPECIFIC answer feedback content for a given question id and answer index.
getType()
Gets the cloze gap type.
buildGapFeedbackLabel($gapIndex, $gap)
builds an answer option label from given (mixed type) index and answer (overwrites parent method from...
buildFeedbackContentFormProperty($label, $postVar, $asNonEditable)
builds and returns a form property gui object with the given label and postvar that is addable to pro...
const CLOZE_NUMERIC
getItem($a_index)
Gets the item with a given index.
saveFbPropsForTextGap(ilPropertyFormGUI $form, assClozeGap $gap, $gapIndex)
saveFeedbackFieldsPerGapAnswers(ilPropertyFormGUI $form)
const FB_MODE_GAP_QUESTION
constants for different feedback modes (per gap or per gap-answers/options)
setRequired($a_required)
Set Required.
completeFbPropsForSelectGap(ilRadioOption $fbModeOpt, assClozeGap $gap, $gapIndex)
duplicateSpecificFeedback($originalQuestionId, $duplicateQuestionId)
duplicates the SPECIFIC feedback relating to the given original question id and saves it for the give...