ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.assKprimChoiceGUI.php
Go to the documentation of this file.
1 <?php
2 
28 {
29  private bool $rebuild_thumbnails = false;
30 
34  public function __construct($qId = -1)
35  {
37 
38  $this->object = new assKprimChoice();
39 
40  if ($qId > 0) {
41  $this->object->loadFromDb($qId);
42  }
43  }
44 
48  public function hasInlineFeedback(): bool
49  {
50  return $this->object->feedbackOBJ->isSpecificAnswerFeedbackAvailable($this->object->getId());
51  }
52 
53  protected function getAdditionalEditQuestionCommands(): array
54  {
55  return ['uploadImage', 'removeImage'];
56  }
57 
58  protected function editQuestion(ilPropertyFormGUI $form = null): void
59  {
60  if ($form === null) {
61  $form = $this->buildEditForm();
62  }
63 
64  $this->getQuestionTemplate();
65 
66  $this->tpl->setVariable("QUESTION_DATA", $this->ctrl->getHTML($form));
67  }
68 
69  protected function uploadImage(): void
70  {
71  $result = $this->writePostData(true);
72 
73  if ($result == 0) {
74  $this->object->saveToDb();
75  $this->editQuestion();
76  }
77  }
78 
79  public function removeImage(): void
80  {
81  $position = key($_POST['cmd']['removeImage']);
82  $this->object->removeAnswerImage($position);
83 
84  $this->object->saveToDb();
85  $this->editQuestion();
86  }
87 
88  public function downkprimanswers(): void
89  {
90  if (isset($_POST['cmd'][__FUNCTION__]) && count($_POST['cmd'][__FUNCTION__])) {
91  $this->object->moveAnswerDown(key($_POST['cmd'][__FUNCTION__]));
92  $this->object->saveToDb();
93  }
94 
95  $this->editQuestion();
96  }
97 
98  public function upkprimanswers(): void
99  {
100  if (isset($_POST['cmd'][__FUNCTION__]) && count($_POST['cmd'][__FUNCTION__])) {
101  $this->object->moveAnswerUp(key($_POST['cmd'][__FUNCTION__]));
102  $this->object->saveToDb();
103  }
104 
105  $this->editQuestion();
106  }
107 
111  protected function writePostData(bool $always = false): int
112  {
113  $form = $this->buildEditForm();
114  $form->setValuesByPost();
115 
116  if ($always) {
117  $answersInput = $form->getItemByPostVar('kprimanswers');
118  $answersInput->setIgnoreMissingUploadsEnabled(true);
119 
120  if (!$answersInput->checkUploads($_POST[$answersInput->getPostVar()])) {
121  $this->tpl->setOnScreenMessage('failure', $this->lng->txt("form_input_not_valid"));
122  $this->editQuestion($form);
123  return 1;
124  }
125 
126  $answersInput->collectValidFiles();
127  } elseif (!$form->checkInput()) {
128  $this->editQuestion($form);
129  return 1;
130  }
131 
133 
134  $this->writeQuestionSpecificPostData($form);
135  $this->writeAnswerSpecificPostData($form);
136 
137  $this->saveTaxonomyAssignments();
138 
139  return 0;
140  }
141 
145  protected function buildEditForm(): ilPropertyFormGUI
146  {
147  $form = $this->buildBasicEditFormObject();
148 
149  $this->addQuestionFormCommandButtons($form);
150 
151  $this->addBasicQuestionFormProperties($form);
152 
153  $this->populateQuestionSpecificFormPart($form);
154  $this->populateAnswerSpecificFormPart($form);
155 
156  $this->populateTaxonomyFormSection($form);
157 
158  return $form;
159  }
160 
166  {
167  // shuffle answers
168  $shuffleAnswers = new ilCheckboxInputGUI($this->lng->txt("shuffle_answers"), "shuffle_answers_enabled");
169  $shuffleAnswers->setChecked($this->object->isShuffleAnswersEnabled());
170  $form->addItem($shuffleAnswers);
171 
172  if (!$this->object->getSelfAssessmentEditingMode()) {
173  // answer mode (single-/multi-line)
174  $answerType = new ilSelectInputGUI($this->lng->txt('answer_types'), 'answer_type');
175  $answerType->setOptions($this->object->getAnswerTypeSelectOptions($this->lng));
176  $answerType->setValue($this->object->getAnswerType());
177  $form->addItem($answerType);
178  }
179 
180  if (!$this->object->getSelfAssessmentEditingMode() && $this->object->isSingleLineAnswerType($this->object->getAnswerType())) {
181  // thumb size
182  $thumb_size = new ilNumberInputGUI($this->lng->txt('thumb_size'), 'thumb_size');
183  $thumb_size->setSuffix($this->lng->txt('thumb_size_unit_pixel'));
184  $thumb_size->setInfo($this->lng->txt('thumb_size_info'));
185  $thumb_size->setDecimals(false);
186  $thumb_size->setMinValue($this->object->getMinimumThumbSize());
187  $thumb_size->setMaxValue($this->object->getMaximumThumbSize());
188  $thumb_size->setSize(6);
189  $thumb_size->setValue($this->object->getThumbSize());
190  } else {
191  $thumb_size = new ilHiddenInputGUI('thumb_size');
192  $thumb_size->setValue($this->object->getThumbSize());
193  }
194  $form->addItem($thumb_size);
195 
196  // option label
197  $optionLabel = new ilRadioGroupInputGUI($this->lng->txt('option_label'), 'option_label');
198  $optionLabel->setInfo($this->lng->txt('option_label_info'));
199  $optionLabel->setRequired(true);
200  $optionLabel->setValue($this->object->getOptionLabel());
201  foreach ($this->object->getValidOptionLabelsTranslated($this->lng) as $labelValue => $labelText) {
202  $option = new ilRadioOption($labelText, $labelValue);
203  $optionLabel->addOption($option);
204 
205  if ($this->object->isCustomOptionLabel($labelValue)) {
206  $customLabelTrue = new ilTextInputGUI(
207  $this->lng->txt('option_label_custom_true'),
208  'option_label_custom_true'
209  );
210  $customLabelTrue->setValue($this->object->getCustomTrueOptionLabel());
211  $option->addSubItem($customLabelTrue);
212 
213  $customLabelFalse = new ilTextInputGUI(
214  $this->lng->txt('option_label_custom_false'),
215  'option_label_custom_false'
216  );
217  $customLabelFalse->setValue($this->object->getCustomFalseOptionLabel());
218  $option->addSubItem($customLabelFalse);
219  }
220  }
221  $form->addItem($optionLabel);
222 
223  // points
224  $points = new ilNumberInputGUI($this->lng->txt('points'), 'points');
225  $points->setRequired(true);
226  $points->setSize(3);
227  $points->allowDecimals(true);
228  $points->setMinValue(0);
229  $points->setMinvalueShouldBeGreater(true);
230  $points->setValue($this->object->getPoints());
231  $form->addItem($points);
232 
233  // score partial solution
234  $scorePartialSolution = new ilCheckboxInputGUI($this->lng->txt('score_partsol_enabled'), 'score_partsol_enabled');
235  $scorePartialSolution->setInfo($this->lng->txt('score_partsol_enabled_info'));
236  $scorePartialSolution->setChecked($this->object->isScorePartialSolutionEnabled());
237  $form->addItem($scorePartialSolution);
238 
239  return $form;
240  }
241 
246  {
247  $old_answer_type = $this->object->getAnswerType();
248 
249  $this->object->setShuffleAnswersEnabled($form->getItemByPostVar('shuffle_answers_enabled')->getChecked());
250 
251  if (!$this->object->getSelfAssessmentEditingMode()) {
252  $this->object->setAnswerType($form->getItemByPostVar('answer_type')->getValue());
253  }
254 
255  if (!$this->object->getSelfAssessmentEditingMode() && $this->object->isSingleLineAnswerType($old_answer_type)) {
256  $thumbsize = (int) ($form->getItemByPostVar('thumb_size')->getValue() ?? $this->object->getThumbSize());
257  if ($thumbsize !== $this->object->getThumbSize()) {
258  $this->object->setThumbSize($thumbsize);
259  $this->rebuild_thumbnails = true;
260  }
261  }
262 
263  $this->object->setOptionLabel($form->getItemByPostVar('option_label')->getValue());
264 
265  if ($this->object->isCustomOptionLabel($this->object->getOptionLabel())) {
266  $this->object->setCustomTrueOptionLabel(strip_tags(
267  $form->getItemByPostVar('option_label_custom_true')->getValue()
268  ));
269  $this->object->setCustomFalseOptionLabel(strip_tags(
270  $form->getItemByPostVar('option_label_custom_false')->getValue()
271  ));
272  }
273 
274  $this->object->setPoints($form->getItemByPostVar('points')->getValue());
275 
276  $this->object->setScorePartialSolutionEnabled($form->getItemByPostVar('score_partsol_enabled')->getChecked());
277  }
278 
284  {
285  $answers = new ilKprimChoiceWizardInputGUI($this->lng->txt('answers'), 'kprimanswers');
286  $answers->setInfo($this->lng->txt('kprim_answers_info'));
287  $answers->setSize(64);
288  $answers->setRequired(true);
289  $answers->setAllowMove(true);
290  $answers->setQuestionObject($this->object);
291  $answers->setSingleline($this->object->isSingleLineAnswerType($this->object->getAnswerType()));
292  $answers->setValues($this->object->getAnswers());
293  $form->addItem($answers);
294 
295  return $form;
296  }
297 
301  public function writeAnswerSpecificPostData(ilPropertyFormGUI $form): void
302  {
303  $answers = $this->handleAnswerTextsSubmit(
304  $form->getItemByPostVar('kprimanswers')->getValues()
305  );
306  $files = $form->getItemByPostVar('kprimanswers')->getFiles();
307 
308  $this->object->handleFileUploads($answers, $files);
309 
310  if ($this->rebuild_thumbnails) {
311  $answers = $this->object->rebuildThumbnails(
312  $this->object->getAnswerType(),
313  $this->object->getThumbSize(),
314  $this->object->getImagePath(),
315  $answers
316  );
317  }
318 
319  $this->object->setAnswers($answers);
320  }
321 
322  private function handleAnswerTextsSubmit($answers)
323  {
324  if ($this->object->getAnswerType() == assKprimChoice::ANSWER_TYPE_MULTI_LINE) {
325  return $answers;
326  }
327 
328  foreach ($answers as $key => $answer) {
329  $answer->setAnswerText(ilUtil::secureString(htmlspecialchars($answer->getAnswerText())));
330  }
331 
332  return $answers;
333  }
334 
340  public function getSpecificFeedbackOutput(array $userSolution): string
341  {
342  return ''; // question type supports inline answer specific feedback
343  }
344 
354  public function getTestOutput(
355  $active_id,
356  // hey: prevPassSolutions - will be always available from now on
357  $pass,
358  // hey.
359  $is_postponed = false,
360  $use_post_solutions = false,
361  $showInlineFeedback = false
362  ): string {
363  // shuffle output
364  $keys = $this->getParticipantsAnswerKeySequence();
365 
366  // get the solution of the user for the active pass or from the last pass if allowed
367  $user_solution = [];
368  if ($active_id) {
369  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
370  // hey.
371  foreach ($solutions as $idx => $solution_value) {
372  $user_solution[$solution_value["value1"]] = $solution_value["value2"];
373  }
374  }
375 
376  $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output.html", true, true, "Modules/TestQuestionPool");
377 
378  foreach ($keys as $answer_id) {
379  $answer = $this->object->getAnswer($answer_id);
380  if ($answer->getImageFile() !== null
381  && $answer->getImageFile() !== '') {
382  if ($this->object->getThumbSize()) {
383  $template->setCurrentBlock("preview");
384  $template->setVariable("URL_PREVIEW", $answer->getImageWebPath());
385  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
386  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('media/enlarge.svg'));
387  $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
388  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
389  $alt = $answer->getImageFile();
390  if (strlen($answer->getAnswertext())) {
391  $alt = $answer->getAnswertext();
392  }
393  $alt = preg_replace("/<[^>]*?>/", "", $alt);
394  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
395  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
396  $template->parseCurrentBlock();
397  } else {
398  $template->setCurrentBlock("answer_image");
399  $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
400  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
401  $alt = $answer->getImageFile();
402  if (strlen($answer->getAnswertext())) {
403  $alt = $answer->getAnswertext();
404  }
405  $alt = preg_replace("/<[^>]*?>/", "", $alt);
406  $template->setVariable("ATTR", $attr);
407  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
408  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
409  $template->parseCurrentBlock();
410  }
411  }
412 
413  if ($showInlineFeedback) {
414  $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
415  }
416 
417  $template->setCurrentBlock("answer_row");
418  $template->setVariable("ANSWER_ID", $answer_id);
419  $template->setVariable("ANSWER_TEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true));
420  $template->setVariable('VALUE_TRUE', 1);
421  $template->setVariable('VALUE_FALSE', 0);
422 
423  if (isset($user_solution[$answer->getPosition()])) {
424  $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
425  $template->setVariable($tplVar, " checked=\"checked\"");
426  }
427 
428  $template->parseCurrentBlock();
429  }
430 
431  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
432  $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
433  $this->lng,
434  $this->object->getOptionLabel()
435  ));
436 
437  $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
438  $this->lng,
439  $this->object->getOptionLabel()
440  ));
441 
442  $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
443  $this->lng,
444  $this->object->getOptionLabel()
445  ));
446 
447  $questionoutput = $template->get();
448  $pageoutput = $this->outQuestionPage("", $is_postponed, $active_id, $questionoutput, $showInlineFeedback);
449  return $pageoutput;
450  }
451 
456  public function getPreview($show_question_only = false, $showInlineFeedback = false): string
457  {
458  $user_solution = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : [];
459  // shuffle output
460  $keys = $this->getParticipantsAnswerKeySequence();
461 
462  $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output.html", true, true, "Modules/TestQuestionPool");
463 
464  foreach ($keys as $answer_id) {
465  $answer = $this->object->getAnswer($answer_id);
466  if ($answer->getImageFile() !== null
467  && $answer->getImageFile() !== '') {
468  if ($this->object->getThumbSize()) {
469  $template->setCurrentBlock("preview");
470  $template->setVariable("URL_PREVIEW", $answer->getImageWebPath());
471  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
472  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('media/enlarge.svg'));
473  $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
474  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
475  $alt = $answer->getImageFile();
476  if (strlen($answer->getAnswertext())) {
477  $alt = $answer->getAnswertext();
478  }
479  $alt = preg_replace("/<[^>]*?>/", "", $alt);
480  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
481  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
482  $template->parseCurrentBlock();
483  } else {
484  $template->setCurrentBlock("answer_image");
485  $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
486  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
487  $alt = $answer->getImageFile();
488  if (strlen($answer->getAnswertext())) {
489  $alt = $answer->getAnswertext();
490  }
491  $alt = preg_replace("/<[^>]*?>/", "", $alt);
492  $template->setVariable("ATTR", $attr);
493  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
494  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
495  $template->parseCurrentBlock();
496  }
497  }
498 
499  if ($showInlineFeedback) {
500  $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
501  }
502 
503  $template->setCurrentBlock("answer_row");
504  $template->setVariable("ANSWER_ID", $answer_id);
505  $template->setVariable("ANSWER_TEXT", ilLegacyFormElementsUtil::prepareTextareaOutput((string) $answer->getAnswertext(), true));
506  $template->setVariable('VALUE_TRUE', 1);
507  $template->setVariable('VALUE_FALSE', 0);
508 
509  if (isset($user_solution[$answer->getPosition()])) {
510  $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
511  $template->setVariable($tplVar, " checked=\"checked\"");
512  }
513 
514  $template->parseCurrentBlock();
515  }
516  $questiontext = $this->object->getQuestionForHTMLOutput();
517  if ($showInlineFeedback && $this->hasInlineFeedback()) {
518  $questiontext .= $this->buildFocusAnchorHtml();
519  }
520  $template->setVariable("QUESTIONTEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($questiontext, true));
521 
522  $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
523  $this->lng,
524  $this->object->getOptionLabel()
525  ));
526 
527  $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
528  $this->lng,
529  $this->object->getOptionLabel()
530  ));
531 
532  $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
533  $this->lng,
534  $this->object->getOptionLabel()
535  ));
536 
537  $questionoutput = $template->get();
538  if (!$show_question_only) {
539  // get page object output
540  $questionoutput = $this->getILIASPage($questionoutput);
541  }
542  return $questionoutput;
543  }
544 
556  public function getSolutionOutput(
557  $active_id,
558  $pass = null,
559  $graphicalOutput = false,
560  $result_output = false,
561  $show_question_only = true,
562  $show_feedback = false,
563  $show_correct_solution = false,
564  $show_manual_scoring = false,
565  $show_question_text = true
566  ): string {
567  $user_solution = [];
568 
569  if (($active_id > 0) && (!$show_correct_solution)) {
570  $solutions = $this->object->getSolutionValues($active_id, $pass);
571  foreach ($solutions as $idx => $solution_value) {
572  $user_solution[] = [
573  'value1' => $solution_value['value1'],
574  'value2' => $solution_value['value2']
575  ];
576  }
577  } else {
578  // take the correct solution instead of the user solution
579  foreach ($this->object->getAnswers() as $answer) {
580  $user_solution[] = [
581  'value1' => $answer->getPosition(),
582  'value2' => $answer->getCorrectness()
583  ];
584  }
585  }
586 
587  return $this->renderSolutionOutput(
588  $user_solution,
589  $active_id,
590  $pass,
591  $graphicalOutput,
592  $result_output,
593  $show_question_only,
594  $show_feedback,
595  $show_correct_solution,
596  $show_manual_scoring,
597  $show_question_text,
598  false,
599  false
600  );
601  }
602 
603  public function renderSolutionOutput(
604  mixed $user_solutions,
605  int $active_id,
606  ?int $pass,
607  bool $graphical_output = false,
608  bool $result_output = false,
609  bool $show_question_only = true,
610  bool $show_feedback = false,
611  bool $show_correct_solution = false,
612  bool $show_manual_scoring = false,
613  bool $show_question_text = true,
614  bool $show_autosave_title = false,
615  bool $show_inline_feedback = false,
616  ): ?string {
617 
618  $user_solution = [];
619  foreach ($user_solutions as $idx => $solution_value) {
620  $user_solution[$solution_value['value1']] = $solution_value['value2'];
621  }
622 
623  $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output_solution.html", true, true, "Modules/TestQuestionPool");
624  $keys = $this->getParticipantsAnswerKeySequence();
625  foreach ($keys as $answer_id) {
626  $answer = $this->object->getAnswer($answer_id);
627 
628  if (($active_id > 0) &&
629  !$show_correct_solution &&
630  $graphical_output) {
631  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK);
632  if (isset($user_solution[$answer->getPosition()]) && $user_solution[$answer->getPosition()] == $answer->getCorrectness()) {
633  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK);
634  }
635  $template->setCurrentBlock("icon_ok");
636  $template->setVariable("ICON_OK", $correctness_icon);
637  $template->parseCurrentBlock();
638  }
639  if ($answer->getImageFile() !== null
640  && $answer->getImageFile() !== '') {
641  $template->setCurrentBlock("answer_image");
642  if ($this->object->getThumbSize()) {
643  $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
644  } else {
645  $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
646  }
647 
648  $template->setVariable(
649  "ANSWER_IMAGE_ALT",
651  $answer->getImageFile()
652  )
653  );
654  $template->setVariable(
655  "ANSWER_IMAGE_TITLE",
657  $answer->getImageFile()
658  )
659  );
660  $template->parseCurrentBlock();
661  }
662 
663  if ($show_feedback) {
664  $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
665  }
666 
667  $template->setCurrentBlock("answer_row");
668  $template->setVariable("ANSWER_TEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true));
669 
670  if ($this->renderPurposeSupportsFormHtml() || $this->isRenderPurposePrintPdf()) {
671  if (isset($user_solution[$answer->getPosition()])) {
672  if ($user_solution[$answer->getPosition()]) {
673  $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_checked.png")));
674  $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("checked"));
675  $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
676  $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("unchecked"));
677  } else {
678  $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
679  $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("unchecked"));
680  $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_checked.png")));
681  $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("checked"));
682  }
683  } else {
684  $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
685  $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("unchecked"));
686  $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
687  $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("unchecked"));
688  }
689  } else {
690  $template->setVariable('SOL_QID', $this->object->getId());
691  $template->setVariable('SOL_SUFFIX', $show_correct_solution ? 'bestsolution' : 'usersolution');
692  $template->setVariable('SOL_POSITION', $answer->getPosition());
693 
694  $template->setVariable('SOL_TRUE_VALUE', 1);
695  $template->setVariable('SOL_FALSE_VALUE', 0);
696 
697  if (isset($user_solution[$answer->getPosition()])) {
698  if ($user_solution[$answer->getPosition()]) {
699  $template->setVariable('SOL_TRUE_CHECKED', 'checked');
700  } else {
701  $template->setVariable('SOL_FALSE_CHECKED', 'checked');
702  }
703  }
704  }
705 
706  $template->parseCurrentBlock();
707  }
708 
709  if ($show_question_text == true) {
710  $questiontext = $this->object->getQuestionForHTMLOutput();
711  if ($show_feedback && $this->hasInlineFeedback()) {
712  $questiontext .= $this->buildFocusAnchorHtml();
713  }
714  $template->setVariable("QUESTIONTEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($questiontext, true));
715 
716  $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
717  $this->lng,
718  $this->object->getOptionLabel()
719  ));
720  }
721 
722  $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
723  $this->lng,
724  $this->object->getOptionLabel()
725  ));
726 
727  $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
728  $this->lng,
729  $this->object->getOptionLabel()
730  ));
731 
732 
733  $questionoutput = $template->get();
734  $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
735 
736  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "Modules/TestQuestionPool");
737 
738  if (strlen($feedback)) {
739  $cssClass = (
740  $this->hasCorrectSolution($active_id, $pass) ?
742  );
743 
744  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
745  $solutiontemplate->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
746  }
747 
748  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
749 
750  $solutionoutput = $solutiontemplate->get();
751 
752  if (!$show_question_only) {
753  // get page object output
754  $solutionoutput = $this->getILIASPage($solutionoutput);
755  }
756  return $solutionoutput;
757  }
758 
759  protected function getParticipantsAnswerKeySequence()
760  {
761  $choice_keys = array_keys($this->object->getAnswers());
762 
763  if ($this->object->isShuffleAnswersEnabled()) {
764  $choice_keys = $this->object->getShuffler()->transform($choice_keys);
765  }
766 
767  return $choice_keys;
768  }
769 
770  private function populateSpecificFeedbackInline($user_solution, $answer_id, $template): void
771  {
772  if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_CHECKED) {
773  if (isset($user_solution[$answer_id])) {
774  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
775  if (strlen($fb)) {
776  $template->setCurrentBlock("feedback");
777  $template->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($fb, true));
778  $template->parseCurrentBlock();
779  }
780  }
781  }
782 
783  if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_ALL) {
784  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
785  if (strlen($fb)) {
786  $template->setCurrentBlock("feedback");
787  $template->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($fb, true));
788  $template->parseCurrentBlock();
789  }
790  }
791 
792  if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_CORRECT) {
793  $answer = $this->object->getAnswer($answer_id);
794 
795  if ($answer->getCorrectness()) {
796  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
797  if (strlen($fb)) {
798  $template->setCurrentBlock("feedback");
799  $template->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($fb, true));
800  $template->parseCurrentBlock();
801  }
802  }
803  }
804  }
805 
816  {
817  return [];
818  }
819 
830  {
831  return [];
832  }
833 
840  public function getAggregatedAnswersView(array $relevant_answers): string
841  {
842  return $this->renderAggregateView(
843  $this->aggregateAnswers($relevant_answers, $this->object->getAnswers())
844  )->get();
845 
846  return '<pre>' . print_r($relevant_answers, 1) . '</pre>';
847  }
848 
849  public function renderAggregateView($aggregate): ilTemplate
850  {
851  $trueOptionLabel = $this->object->getTrueOptionLabelTranslation($this->lng, $this->object->getOptionLabel());
852  $falseOptionLabel = $this->object->getFalseOptionLabelTranslation($this->lng, $this->object->getOptionLabel());
853 
854  $tpl = new ilTemplate('tpl.il_as_aggregated_kprim_answers_table.html', true, true, "Modules/TestQuestionPool");
855 
856  foreach ($aggregate as $lineData) {
857  $tpl->setCurrentBlock('aggregaterow');
858  $tpl->setVariable('OPTION', $lineData['answertext']);
859  $tpl->setVariable('COUNT_TRUE', $lineData['count_true']);
860  $tpl->setVariable('COUNT_FALSE', $lineData['count_false']);
862  }
863 
864  $tpl->setVariable('OPTION_HEAD', $this->lng->txt('answers'));
865  $tpl->setVariable('COUNT_TRUE_HEAD', $trueOptionLabel);
866  $tpl->setVariable('COUNT_FALSE_HEAD', $falseOptionLabel);
867 
868  return $tpl;
869  }
870 
871  public function aggregateAnswers($rawSolutionData, $answers): array
872  {
873  $aggregate = [];
874 
875  foreach ($answers as $answer) {
876  $answerAgg = [
877  'answertext' => $answer->getAnswerText(), 'count_true' => 0, 'count_false' => 0
878  ];
879 
880  foreach ($rawSolutionData as $solutionRecord) {
881  if ($solutionRecord['value1'] == $answer->getPosition()) {
882  if ($solutionRecord['value2']) {
883  $answerAgg['count_true']++;
884  } else {
885  $answerAgg['count_false']++;
886  }
887  }
888  }
889 
890  $aggregate[] = $answerAgg;
891  }
892 
893  return $aggregate;
894  }
895 
896  public function getAnswersFrequency($relevantAnswers, $questionIndex): array
897  {
898  $agg = $this->aggregateAnswers($relevantAnswers, $this->object->getAnswers());
899 
900  $answers = [];
901 
902  foreach ($agg as $ans) {
903  $answers[] = [
904  'answer' => $ans['answertext'],
905  'frequency_true' => $ans['count_true'],
906  'frequency_false' => $ans['count_false']
907  ];
908  }
909 
910  return $answers;
911  }
912 
920  public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex): ilAnswerFrequencyStatisticTableGUI
921  {
922  $table = new ilKprimChoiceAnswerFreqStatTableGUI($parentGui, $parentCmd, $this->object);
923  $table->setQuestionIndex($questionIndex);
924  $table->setData($this->getAnswersFrequency($relevantAnswers, $questionIndex));
925  $table->initColumns();
926 
927  return $table;
928  }
929 
931  {
932  // points
933  $points = new ilNumberInputGUI($this->lng->txt('points'), 'points');
934  $points->setRequired(true);
935  $points->setSize(3);
936  $points->allowDecimals(true);
937  $points->setMinValue(0);
938  $points->setMinvalueShouldBeGreater(true);
939  $points->setValue($this->object->getPoints());
940  $form->addItem($points);
941 
942  // score partial solution
943  $scorePartialSolution = new ilCheckboxInputGUI($this->lng->txt('score_partsol_enabled'), 'score_partsol_enabled');
944  $scorePartialSolution->setInfo($this->lng->txt('score_partsol_enabled_info'));
945  $scorePartialSolution->setChecked($this->object->isScorePartialSolutionEnabled());
946  $form->addItem($scorePartialSolution);
947 
948  // answers
949  $kprimAnswers = new ilKprimChoiceCorrectionsInputGUI($this->lng->txt('answers'), 'kprimanswers');
950  $kprimAnswers->setInfo($this->lng->txt('kprim_answers_info'));
951  $kprimAnswers->setSize(64);
952  $kprimAnswers->setMaxLength(1000);
953  $kprimAnswers->setRequired(true);
954  $kprimAnswers->setQuestionObject($this->object);
955  $kprimAnswers->setValues($this->object->getAnswers());
956  $form->addItem($kprimAnswers);
957  }
958 
963  {
964  $this->object->setPoints(
965  (float) str_replace(',', '.', $form->getInput('points'))
966  );
967 
968  $this->object->setScorePartialSolutionEnabled(
969  (bool) $form->getInput('score_partsol_enabled')
970  );
971 
972  $this->object->setAnswers(
973  $form->getItemByPostVar('kprimanswers')->getValues()
974  );
975  }
976 }
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
hasCorrectSolution($activeId, $passIndex)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex)
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
generateCorrectnessIconsForCorrectness(int $correctness)
setCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Sets the template to the given block.
This class represents a selection list property in a property form.
renderSolutionOutput(mixed $user_solutions, int $active_id, ?int $pass, bool $graphical_output=false, bool $result_output=false, bool $show_question_only=true, bool $show_feedback=false, bool $show_correct_solution=false, bool $show_manual_scoring=false, bool $show_question_text=true, bool $show_autosave_title=false, bool $show_inline_feedback=false,)
getItemByPostVar(string $a_post_var)
getAggregatedAnswersView(array $relevant_answers)
Returns an html string containing a question specific representation of the answers so far given in t...
static secureString(string $a_str, bool $a_strip_html=true, string $a_allow="")
static getImagePath(string $img, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
parseCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Parses the given block.
populateAnswerSpecificFormPart(ilPropertyFormGUI $form)
setOptions(array $a_options)
ilGlobalPageTemplate $tpl
static prepareFormOutput($a_str, bool $a_strip=false)
getSpecificFeedbackOutput(array $userSolution)
getPreview($show_question_only=false, $showInlineFeedback=false)
populateTaxonomyFormSection(ilPropertyFormGUI $form)
getInput(string $a_post_var, bool $ensureValidation=true)
Returns the input of an item, if item provides getInput method and as fallback the value of the HTTP-...
addQuestionFormCommandButtons(ilPropertyFormGUI $form)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This class represents a property in a property form.
__construct(VocabulariesInterface $vocabularies)
getTestOutput( $active_id, $pass, $is_postponed=false, $use_post_solutions=false, $showInlineFeedback=false)
string $key
Consumer key/client ID value.
Definition: System.php:193
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
static getHtmlPath(string $relative_path)
get url of path
Basic GUI class for assessment questions.
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
writePostData(bool $always=false)
{}
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
editQuestion(ilPropertyFormGUI $form=null)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
aggregateAnswers($rawSolutionData, $answers)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static prepareTextareaOutput(string $txt_output, bool $prepare_for_latex_output=false, bool $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output where latex code may be in it If the text is HTML-free...
getSolutionOutput( $active_id, $pass=null, $graphicalOutput=false, $result_output=false, $show_question_only=true, $show_feedback=false, $show_correct_solution=false, $show_manual_scoring=false, $show_question_text=true)
setVariable(string $variable, $value='')
Sets the given variable to the given value.
populateSpecificFeedbackInline($user_solution, $answer_id, $template)
getAnswersFrequency($relevantAnswers, $questionIndex)
populateQuestionSpecificFormPart(ilPropertyFormGUI $form)
getGenericFeedbackOutput(int $active_id, ?int $pass)