ILIAS  trunk Revision v11.0_alpha-1723-g8e69f309bab
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
class.assKprimChoiceGUI.php
Go to the documentation of this file.
1 <?php
2 
28 {
29  private bool $rebuild_thumbnails = false;
31 
35  public function __construct($qId = -1)
36  {
38 
39  $this->object = new assKprimChoice();
40 
41  if ($qId > 0) {
42  $this->object->loadFromDb($qId);
43  }
44  }
45 
49  public function hasInlineFeedback(): bool
50  {
51  return $this->object->feedbackOBJ->isSpecificAnswerFeedbackAvailable($this->object->getId());
52  }
53 
54  protected function getAdditionalEditQuestionCommands(): array
55  {
56  return ['uploadImage', 'removeImage'];
57  }
58 
59  public function editQuestion(
60  bool $checkonly = false,
61  ?bool $is_save_cmd = null
62  ): bool {
63  $form = $this->edit_form;
64  if ($form === null) {
65  $form = $this->buildEditForm();
66  }
67 
68  $this->renderEditForm($form);
69  return false;
70  }
71 
72  protected function uploadImage(): void
73  {
75  if ($this->writePostData(true) === 0) {
76  $this->object->saveToDb();
77  $this->editQuestion();
78  }
79  }
80 
81  public function removeImage(): void
82  {
83  $this->object->removeAnswerImage($this->request_data_collector->getCmdIndex('removeImage'));
84  $this->object->saveToDb();
85  $this->editQuestion();
86  }
87 
88  public function downkprimanswers(): void
89  {
90  $index = $this->request_data_collector->getCmdIndex(__FUNCTION__);
91  if (!empty($index)) {
92  $this->object->moveAnswerDown($index);
93  $this->object->saveToDb();
94  }
95 
96  $this->editQuestion();
97  }
98 
99  public function upkprimanswers(): void
100  {
101  $index = $this->request_data_collector->getCmdIndex(__FUNCTION__);
102  if (!empty($index)) {
103  $this->object->moveAnswerUp($index);
104  $this->object->saveToDb();
105  }
106 
107  $this->editQuestion();
108  }
109 
113  protected function writePostData(bool $always = false): int
114  {
115  $form = $this->buildEditForm();
116  $form->setValuesByPost();
117  $answers_input = $form->getItemByPostVar('kprimanswers');
118 
119  if ($always && $answers_input instanceof ilFormPropertyGUI) {
120  $answers_input->setIgnoreMissingUploadsEnabled(true);
121  $answer_input_postvar = $this->request_data_collector->strArray($answers_input->getPostVar(), 2);
122 
123  if (!$answers_input->checkUploads($answer_input_postvar)) {
124  $this->tpl->setOnScreenMessage('failure', $this->lng->txt('form_input_not_valid'));
125  $this->edit_form = $form;
126  $this->editQuestion();
127  return 1;
128  }
129 
130  $answers_input->collectValidFiles();
131  } elseif (!$form->checkInput()) {
132  $this->edit_form = $form;
133  $this->editQuestion();
134  return 1;
135  }
136 
138 
139  $this->writeQuestionSpecificPostData($form);
140  $this->writeAnswerSpecificPostData($form);
141 
142  $this->saveTaxonomyAssignments();
143 
144  return 0;
145  }
146 
150  protected function buildEditForm(): ilPropertyFormGUI
151  {
152  $form = $this->buildBasicEditFormObject();
153 
154  $this->addQuestionFormCommandButtons($form);
155 
156  $this->addBasicQuestionFormProperties($form);
157 
158  $this->populateQuestionSpecificFormPart($form);
159  $this->populateAnswerSpecificFormPart($form);
160 
161  $this->populateTaxonomyFormSection($form);
162 
163  return $form;
164  }
165 
171  {
172  // shuffle answers
173  $shuffleAnswers = new ilCheckboxInputGUI($this->lng->txt("shuffle_answers"), "shuffle_answers_enabled");
174  $shuffleAnswers->setChecked($this->object->isShuffleAnswersEnabled());
175  $form->addItem($shuffleAnswers);
176 
177  if (!$this->object->getSelfAssessmentEditingMode()) {
178  // answer mode (single-/multi-line)
179  $answerType = new ilSelectInputGUI($this->lng->txt('answer_types'), 'answer_type');
180  $answerType->setOptions($this->object->getAnswerTypeSelectOptions($this->lng));
181  $answerType->setValue($this->object->getAnswerType());
182  $form->addItem($answerType);
183  }
184 
185  if (!$this->object->getSelfAssessmentEditingMode() && $this->object->isSingleLineAnswerType($this->object->getAnswerType())) {
186  // thumb size
187  $thumb_size = new ilNumberInputGUI($this->lng->txt('thumb_size'), 'thumb_size');
188  $thumb_size->setSuffix($this->lng->txt('thumb_size_unit_pixel'));
189  $thumb_size->setInfo($this->lng->txt('thumb_size_info'));
190  $thumb_size->setDecimals(false);
191  $thumb_size->setMinValue($this->object->getMinimumThumbSize());
192  $thumb_size->setMaxValue($this->object->getMaximumThumbSize());
193  $thumb_size->setSize(6);
194  $thumb_size->setValue($this->object->getThumbSize());
195  } else {
196  $thumb_size = new ilHiddenInputGUI('thumb_size');
197  $thumb_size->setValue($this->object->getThumbSize());
198  }
199  $form->addItem($thumb_size);
200 
201  // option label
202  $optionLabel = new ilRadioGroupInputGUI($this->lng->txt('option_label'), 'option_label');
203  $optionLabel->setInfo($this->lng->txt('option_label_info'));
204  $optionLabel->setRequired(true);
205  $optionLabel->setValue($this->object->getOptionLabel());
206  foreach ($this->object->getValidOptionLabelsTranslated($this->lng) as $labelValue => $labelText) {
207  $option = new ilRadioOption($labelText, $labelValue);
208  $optionLabel->addOption($option);
209 
210  if ($this->object->isCustomOptionLabel($labelValue)) {
211  $customLabelTrue = new ilTextInputGUI(
212  $this->lng->txt('option_label_custom_true'),
213  'option_label_custom_true'
214  );
215  $customLabelTrue->setValue($this->object->getCustomTrueOptionLabel());
216  $option->addSubItem($customLabelTrue);
217 
218  $customLabelFalse = new ilTextInputGUI(
219  $this->lng->txt('option_label_custom_false'),
220  'option_label_custom_false'
221  );
222  $customLabelFalse->setValue($this->object->getCustomFalseOptionLabel());
223  $option->addSubItem($customLabelFalse);
224  }
225  }
226  $form->addItem($optionLabel);
227 
228  // points
229  $points = new ilNumberInputGUI($this->lng->txt('points'), 'points');
230  $points->setRequired(true);
231  $points->setSize(3);
232  $points->allowDecimals(true);
233  $points->setMinValue(0);
234  $points->setMinvalueShouldBeGreater(true);
235  $points->setValue($this->object->getPoints());
236  $form->addItem($points);
237 
238  // score partial solution
239  $scorePartialSolution = new ilCheckboxInputGUI($this->lng->txt('score_partsol_enabled'), 'score_partsol_enabled');
240  $scorePartialSolution->setInfo($this->lng->txt('score_partsol_enabled_info'));
241  $scorePartialSolution->setChecked($this->object->isScorePartialSolutionEnabled());
242  $form->addItem($scorePartialSolution);
243 
244  return $form;
245  }
246 
251  {
252  $old_answer_type = $this->object->getAnswerType();
253 
254  $this->object->setShuffleAnswersEnabled($form->getItemByPostVar('shuffle_answers_enabled')->getChecked());
255 
256  if (!$this->object->getSelfAssessmentEditingMode()) {
257  $this->object->setAnswerType($form->getItemByPostVar('answer_type')->getValue());
258  }
259 
260  if (!$this->object->getSelfAssessmentEditingMode() && $this->object->isSingleLineAnswerType($old_answer_type)) {
261  $thumbsize = (int) ($form->getItemByPostVar('thumb_size')->getValue() ?? $this->object->getThumbSize());
262  if ($thumbsize !== $this->object->getThumbSize()) {
263  $this->object->setThumbSize($thumbsize);
264  $this->rebuild_thumbnails = true;
265  }
266  }
267 
268  $this->object->setOptionLabel($form->getItemByPostVar('option_label')->getValue());
269 
270  if ($this->object->isCustomOptionLabel($this->object->getOptionLabel())) {
271  $this->object->setCustomTrueOptionLabel(strip_tags(
272  $form->getItemByPostVar('option_label_custom_true')->getValue()
273  ));
274  $this->object->setCustomFalseOptionLabel(strip_tags(
275  $form->getItemByPostVar('option_label_custom_false')->getValue()
276  ));
277  }
278 
279  $this->object->setPoints($form->getItemByPostVar('points')->getValue());
280 
281  $this->object->setScorePartialSolutionEnabled($form->getItemByPostVar('score_partsol_enabled')->getChecked());
282  }
283 
289  {
290  $answers = new ilKprimChoiceWizardInputGUI($this->lng->txt('answers'), 'kprimanswers');
291  $answers->setInfo($this->lng->txt('kprim_answers_info'));
292  $answers->setSize(64);
293  $answers->setRequired(true);
294  $answers->setAllowMove(true);
295  $answers->setQuestionObject($this->object);
296  $answers->setSingleline($this->object->isSingleLineAnswerType($this->object->getAnswerType()));
297  $answers->setValues($this->object->getAnswers());
298  $form->addItem($answers);
299 
300  return $form;
301  }
302 
306  public function writeAnswerSpecificPostData(ilPropertyFormGUI $form): void
307  {
308  $answers = $this->handleAnswerTextsSubmit(
309  $form->getItemByPostVar('kprimanswers')->getValues()
310  );
311  $files = $form->getItemByPostVar('kprimanswers')->getFiles();
312 
313  $this->object->handleFileUploads($answers, $files);
314 
315  if ($this->rebuild_thumbnails) {
316  $answers = $this->object->rebuildThumbnails(
317  $this->object->getAnswerType(),
318  $this->object->getThumbSize(),
319  $this->object->getImagePath(),
320  $answers
321  );
322  }
323 
324  $this->object->setAnswers($answers);
325  }
326 
327  private function handleAnswerTextsSubmit($answers)
328  {
329  if ($this->object->getAnswerType() == assKprimChoice::ANSWER_TYPE_MULTI_LINE) {
330  return $answers;
331  }
332 
333  foreach ($answers as $key => $answer) {
334  $answer->setAnswerText(ilUtil::secureString(htmlspecialchars($answer->getAnswerText())));
335  }
336 
337  return $answers;
338  }
339 
345  public function getSpecificFeedbackOutput(array $userSolution): string
346  {
347  return ''; // question type supports inline answer specific feedback
348  }
349 
359  public function getTestOutput(
360  int $active_id,
361  int $pass,
362  bool $is_question_postponed = false,
363  array|bool $user_post_solutions = false,
364  bool $show_specific_inline_feedback = false
365  ): string {
366  // shuffle output
367  $keys = $this->getParticipantsAnswerKeySequence();
368 
369  // get the solution of the user for the active pass or from the last pass if allowed
370  $user_solution = [];
371  if ($active_id) {
372  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
373  // hey.
374  foreach ($solutions as $idx => $solution_value) {
375  $user_solution[$solution_value["value1"]] = $solution_value["value2"];
376  }
377  }
378 
379  $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output.html", true, true, "components/ILIAS/TestQuestionPool");
380 
381  foreach ($keys as $answer_id) {
382  $answer = $this->object->getAnswer($answer_id);
383  if ($answer->getImageFile() !== null
384  && $answer->getImageFile() !== '') {
385  if ($this->object->getThumbSize()) {
386  $template->setCurrentBlock("preview");
387  $template->setVariable("URL_PREVIEW", $answer->getImageWebPath());
388  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
389  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('media/enlarge.svg'));
390  $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
391  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
392  $alt = $answer->getImageFile();
393  if (strlen($answer->getAnswertext())) {
394  $alt = $answer->getAnswertext();
395  }
396  $alt = preg_replace("/<[^>]*?>/", "", $alt);
397  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
398  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
399  $template->parseCurrentBlock();
400  } else {
401  $template->setCurrentBlock("answer_image");
402  $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
403  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
404  $alt = $answer->getImageFile();
405  if (strlen($answer->getAnswertext())) {
406  $alt = $answer->getAnswertext();
407  }
408  $alt = preg_replace("/<[^>]*?>/", "", $alt);
409  $template->setVariable("ATTR", $attr);
410  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
411  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
412  $template->parseCurrentBlock();
413  }
414  }
415 
416  if ($show_specific_inline_feedback) {
417  $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
418  }
419 
420  $template->setCurrentBlock("answer_row");
421  $template->setVariable("ANSWER_ID", $answer_id);
422  $template->setVariable("ANSWER_TEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true));
423  $template->setVariable('VALUE_TRUE', 1);
424  $template->setVariable('VALUE_FALSE', 0);
425 
426  if (isset($user_solution[$answer->getPosition()])) {
427  $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
428  $template->setVariable($tplVar, " checked=\"checked\"");
429  }
430 
431  $template->parseCurrentBlock();
432  }
433 
434  $template->setVariable("QUESTIONTEXT", $this->object->getQuestionForHTMLOutput());
435  $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
436  $this->lng,
437  $this->object->getOptionLabel()
438  ));
439 
440  $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
441  $this->lng,
442  $this->object->getOptionLabel()
443  ));
444 
445  $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
446  $this->lng,
447  $this->object->getOptionLabel()
448  ));
449 
450  $questionoutput = $template->get();
451  $pageoutput = $this->outQuestionPage("", $is_question_postponed, $active_id, $questionoutput, $show_specific_inline_feedback);
452  return $pageoutput;
453  }
454 
455  public function getPreview(
456  bool $show_question_only = false,
457  bool $show_inline_feedback = false
458  ): string {
459  $user_solution = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : [];
460  // shuffle output
461  $keys = $this->getParticipantsAnswerKeySequence();
462 
463  $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output.html", true, true, "components/ILIAS/TestQuestionPool");
464 
465  foreach ($keys as $answer_id) {
466  $answer = $this->object->getAnswer($answer_id);
467  if ($answer->getImageFile() !== null
468  && $answer->getImageFile() !== '') {
469  if ($this->object->getThumbSize()) {
470  $template->setCurrentBlock("preview");
471  $template->setVariable("URL_PREVIEW", $answer->getImageWebPath());
472  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
473  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('media/enlarge.svg'));
474  $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
475  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
476  $alt = $answer->getImageFile();
477  if (strlen($answer->getAnswertext())) {
478  $alt = $answer->getAnswertext();
479  }
480  $alt = preg_replace("/<[^>]*?>/", "", $alt);
481  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
482  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
483  $template->parseCurrentBlock();
484  } else {
485  $template->setCurrentBlock("answer_image");
486  $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
487  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
488  $alt = $answer->getImageFile();
489  if (strlen($answer->getAnswertext())) {
490  $alt = $answer->getAnswertext();
491  }
492  $alt = preg_replace("/<[^>]*?>/", "", $alt);
493  $template->setVariable("ATTR", $attr);
494  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
495  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
496  $template->parseCurrentBlock();
497  }
498  }
499 
500  if ($show_inline_feedback) {
501  $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
502  }
503 
504  $template->setCurrentBlock("answer_row");
505  $template->setVariable("ANSWER_ID", $answer_id);
506  $template->setVariable("ANSWER_TEXT", ilLegacyFormElementsUtil::prepareTextareaOutput((string) $answer->getAnswertext(), true));
507  $template->setVariable('VALUE_TRUE', 1);
508  $template->setVariable('VALUE_FALSE', 0);
509 
510  if (isset($user_solution[$answer->getPosition()])) {
511  $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
512  $template->setVariable($tplVar, " checked=\"checked\"");
513  }
514 
515  $template->parseCurrentBlock();
516  }
517  $questiontext = $this->object->getQuestionForHTMLOutput();
518  if ($show_inline_feedback && $this->hasInlineFeedback()) {
519  $questiontext .= $this->buildFocusAnchorHtml();
520  }
521  $template->setVariable("QUESTIONTEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($questiontext, true));
522 
523  $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
524  $this->lng,
525  $this->object->getOptionLabel()
526  ));
527 
528  $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
529  $this->lng,
530  $this->object->getOptionLabel()
531  ));
532 
533  $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
534  $this->lng,
535  $this->object->getOptionLabel()
536  ));
537 
538  $questionoutput = $template->get();
539  if (!$show_question_only) {
540  // get page object output
541  $questionoutput = $this->getILIASPage($questionoutput);
542  }
543  return $questionoutput;
544  }
545 
546  public function getSolutionOutput(
547  int $active_id,
548  ?int $pass = null,
549  bool $graphical_output = false,
550  bool $result_output = false,
551  bool $show_question_only = true,
552  bool $show_feedback = false,
553  bool $show_correct_solution = false,
554  bool $show_manual_scoring = false,
555  bool $show_question_text = true,
556  bool $show_inline_feedback = true
557  ): string {
558  $user_solution = [];
559 
560  if (($active_id > 0) && (!$show_correct_solution)) {
561  $solutions = $this->object->getSolutionValues($active_id, $pass);
562  foreach ($solutions as $idx => $solution_value) {
563  //$user_solution[$solution_value['value1']] = $solution_value['value2'];
564  $user_solution[] = [
565  'value1' => $solution_value['value1'],
566  'value2' => $solution_value['value2']
567  ];
568  }
569  } else {
570  // take the correct solution instead of the user solution
571  foreach ($this->object->getAnswers() as $answer) {
572  //$user_solution[$answer->getPosition()] = $answer->getCorrectness();
573  $user_solution[] = [
574  'value1' => $answer->getPosition(),
575  'value2' => $answer->getCorrectness()
576  ];
577  }
578  }
579 
580  return $this->renderSolutionOutput(
581  $user_solution,
582  $active_id,
583  $pass,
584  $graphical_output,
585  $result_output,
586  $show_question_only,
587  $show_feedback,
588  $show_correct_solution,
589  $show_manual_scoring,
590  $show_question_text,
591  false,
592  $show_inline_feedback
593  );
594  }
595 
596  public function renderSolutionOutput(
597  mixed $user_solutions,
598  int $active_id,
599  ?int $pass,
600  bool $graphical_output = false,
601  bool $result_output = false,
602  bool $show_question_only = true,
603  bool $show_feedback = false,
604  bool $show_correct_solution = false,
605  bool $show_manual_scoring = false,
606  bool $show_question_text = true,
607  bool $show_autosave_title = false,
608  bool $show_inline_feedback = false,
609  ): ?string {
610 
611  $user_solution = [];
612  foreach ($user_solutions as $idx => $solution_value) {
613  $user_solution[$solution_value['value1']] = $solution_value['value2'];
614  }
615  $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output_solution.html", true, true, "components/ILIAS/TestQuestionPool");
616  $keys = $this->getParticipantsAnswerKeySequence();
617  foreach ($keys as $answer_id) {
618  $answer = $this->object->getAnswer($answer_id);
619 
620  if (($active_id > 0) &&
621  !$show_correct_solution &&
622  $graphical_output) {
623  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK);
624  if (isset($user_solution[$answer->getPosition()]) && $user_solution[$answer->getPosition()] == $answer->getCorrectness()) {
625  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK);
626  }
627  $template->setCurrentBlock("icon_ok");
628  $template->setVariable("ICON_OK", $correctness_icon);
629  $template->parseCurrentBlock();
630  }
631  if ($answer->getImageFile() !== null
632  && $answer->getImageFile() !== '') {
633  $template->setCurrentBlock("answer_image");
634  if ($this->object->getThumbSize()) {
635  $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
636  } else {
637  $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
638  }
639 
640  $template->setVariable(
641  "ANSWER_IMAGE_ALT",
643  $answer->getImageFile()
644  )
645  );
646  $template->setVariable(
647  "ANSWER_IMAGE_TITLE",
649  $answer->getImageFile()
650  )
651  );
652  $template->parseCurrentBlock();
653  }
654 
655  if ($show_feedback) {
656  $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
657  }
658 
659  $template->setCurrentBlock("answer_row");
660  $template->setVariable("ANSWER_TEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true));
661 
662  if ($this->renderPurposeSupportsFormHtml() || $this->isRenderPurposePrintPdf()) {
663  if (isset($user_solution[$answer->getPosition()])) {
664  if ($user_solution[$answer->getPosition()]) {
665  $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_checked.png")));
666  $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("checked"));
667  $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
668  $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("unchecked"));
669  } else {
670  $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
671  $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("unchecked"));
672  $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_checked.png")));
673  $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("checked"));
674  }
675  } else {
676  $template->setVariable("SOLUTION_IMAGE_TRUE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
677  $template->setVariable("SOLUTION_ALT_TRUE", $this->lng->txt("unchecked"));
678  $template->setVariable("SOLUTION_IMAGE_FALSE", ilUtil::getHtmlPath(ilUtil::getImagePath("object/radiobutton_unchecked.png")));
679  $template->setVariable("SOLUTION_ALT_FALSE", $this->lng->txt("unchecked"));
680  }
681  } else {
682  $template->setVariable('SOL_QID', $this->object->getId());
683  $template->setVariable('SOL_SUFFIX', $show_correct_solution ? 'bestsolution' : 'usersolution');
684  $template->setVariable('SOL_POSITION', $answer->getPosition());
685 
686  $template->setVariable('SOL_TRUE_VALUE', 1);
687  $template->setVariable('SOL_FALSE_VALUE', 0);
688 
689  if (isset($user_solution[$answer->getPosition()])) {
690  if ($user_solution[$answer->getPosition()]) {
691  $template->setVariable('SOL_TRUE_CHECKED', 'checked');
692  } else {
693  $template->setVariable('SOL_FALSE_CHECKED', 'checked');
694  }
695  }
696  }
697 
698  $template->parseCurrentBlock();
699  }
700 
701  if ($show_question_text == true) {
702  $questiontext = $this->object->getQuestionForHTMLOutput();
703  if ($show_feedback && $this->hasInlineFeedback()) {
704  $questiontext .= $this->buildFocusAnchorHtml();
705  }
706  $template->setVariable("QUESTIONTEXT", ilLegacyFormElementsUtil::prepareTextareaOutput($questiontext, true));
707 
708  $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
709  $this->lng,
710  $this->object->getOptionLabel()
711  ));
712  }
713 
714  $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
715  $this->lng,
716  $this->object->getOptionLabel()
717  ));
718 
719  $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
720  $this->lng,
721  $this->object->getOptionLabel()
722  ));
723 
724 
725  $questionoutput = $template->get();
726  $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : "";
727 
728  $solutiontemplate = new ilTemplate("tpl.il_as_tst_solution_output.html", true, true, "components/ILIAS/TestQuestionPool");
729 
730  if (strlen($feedback)) {
731  $cssClass = (
732  $this->hasCorrectSolution($active_id, $pass) ?
734  );
735 
736  $solutiontemplate->setVariable("ILC_FB_CSS_CLASS", $cssClass);
737  $solutiontemplate->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
738  }
739 
740  $solutiontemplate->setVariable("SOLUTION_OUTPUT", $questionoutput);
741 
742  $solutionoutput = $solutiontemplate->get();
743 
744  if (!$show_question_only) {
745  // get page object output
746  $solutionoutput = $this->getILIASPage($solutionoutput);
747  }
748  return $solutionoutput;
749  }
750 
751  protected function getParticipantsAnswerKeySequence()
752  {
753  $choice_keys = array_keys($this->object->getAnswers());
754 
755  if ($this->object->isShuffleAnswersEnabled()) {
756  $choice_keys = $this->object->getShuffler()->transform($choice_keys);
757  }
758 
759  return $choice_keys;
760  }
761 
762  private function populateSpecificFeedbackInline($user_solution, $answer_id, $template): void
763  {
764  if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_CHECKED) {
765  if (isset($user_solution[$answer_id])) {
766  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
767  if (strlen($fb)) {
768  $template->setCurrentBlock("feedback");
769  $template->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($fb, true));
770  $template->parseCurrentBlock();
771  }
772  }
773  }
774 
775  if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_ALL) {
776  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
777  if (strlen($fb)) {
778  $template->setCurrentBlock("feedback");
779  $template->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($fb, true));
780  $template->parseCurrentBlock();
781  }
782  }
783 
784  if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_CORRECT) {
785  $answer = $this->object->getAnswer($answer_id);
786 
787  if ($answer->getCorrectness()) {
788  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
789  if (strlen($fb)) {
790  $template->setCurrentBlock("feedback");
791  $template->setVariable("FEEDBACK", ilLegacyFormElementsUtil::prepareTextareaOutput($fb, true));
792  $template->parseCurrentBlock();
793  }
794  }
795  }
796  }
797 
808  {
809  return [];
810  }
811 
822  {
823  return [];
824  }
825 
826  private function aggregateAnswers($rawSolutionData, $answers): array
827  {
828  $aggregate = [];
829 
830  foreach ($answers as $answer) {
831  $answerAgg = [
832  'answertext' => $answer->getAnswerText(), 'count_true' => 0, 'count_false' => 0
833  ];
834 
835  foreach ($rawSolutionData as $solutionRecord) {
836  if ($solutionRecord['value1'] == $answer->getPosition()) {
837  if ($solutionRecord['value2']) {
838  $answerAgg['count_true']++;
839  } else {
840  $answerAgg['count_false']++;
841  }
842  }
843  }
844 
845  $aggregate[] = $answerAgg;
846  }
847 
848  return $aggregate;
849  }
850 
851  public function getAnswersFrequency($relevantAnswers, $questionIndex): array
852  {
853  $agg = $this->aggregateAnswers($relevantAnswers, $this->object->getAnswers());
854 
855  $answers = [];
856 
857  foreach ($agg as $ans) {
858  $answers[] = [
859  'answer' => $ans['answertext'],
860  'frequency_true' => $ans['count_true'],
861  'frequency_false' => $ans['count_false']
862  ];
863  }
864 
865  return $answers;
866  }
867 
875  public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex): ilAnswerFrequencyStatisticTableGUI
876  {
877  $table = new ilKprimChoiceAnswerFreqStatTableGUI($parentGui, $parentCmd, $this->object);
878  $table->setQuestionIndex($questionIndex);
879  $table->setData($this->getAnswersFrequency($relevantAnswers, $questionIndex));
880  $table->initColumns();
881 
882  return $table;
883  }
884 
886  {
887  // points
888  $points = new ilNumberInputGUI($this->lng->txt('points'), 'points');
889  $points->setRequired(true);
890  $points->setSize(3);
891  $points->allowDecimals(true);
892  $points->setMinValue(0);
893  $points->setMinvalueShouldBeGreater(true);
894  $points->setValue($this->object->getPoints());
895  $form->addItem($points);
896 
897  // score partial solution
898  $scorePartialSolution = new ilCheckboxInputGUI($this->lng->txt('score_partsol_enabled'), 'score_partsol_enabled');
899  $scorePartialSolution->setInfo($this->lng->txt('score_partsol_enabled_info'));
900  $scorePartialSolution->setChecked($this->object->isScorePartialSolutionEnabled());
901  $form->addItem($scorePartialSolution);
902 
903  // answers
904  $kprimAnswers = new ilKprimChoiceCorrectionsInputGUI($this->lng->txt('answers'), 'kprimanswers');
905  $kprimAnswers->setInfo($this->lng->txt('kprim_answers_info'));
906  $kprimAnswers->setSize(64);
907  $kprimAnswers->setMaxLength(1000);
908  $kprimAnswers->setRequired(true);
909  $kprimAnswers->setQuestionObject($this->object);
910  $kprimAnswers->setValues($this->object->getAnswers());
911  $form->addItem($kprimAnswers);
912  }
913 
918  {
919  $this->object->setPoints(
920  (float) str_replace(',', '.', $form->getInput('points'))
921  );
922 
923  $this->object->setScorePartialSolutionEnabled(
924  (bool) $form->getInput('score_partsol_enabled')
925  );
926 
927  $this->object->setAnswers(
928  $form->getItemByPostVar('kprimanswers')->getValues()
929  );
930  }
931 }
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
hasCorrectSolution($activeId, $passIndex)
This class represents an option in a radio group.
getPreview(bool $show_question_only=false, bool $show_inline_feedback=false)
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)
setSuffix(string $a_value)
generateCorrectnessIconsForCorrectness(int $correctness)
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)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static secureString(string $a_str, bool $a_strip_html=true, string $a_allow="")
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
populateAnswerSpecificFormPart(ilPropertyFormGUI $form)
setOptions(array $a_options)
static prepareFormOutput($a_str, bool $a_strip=false)
getSpecificFeedbackOutput(array $userSolution)
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)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
This class represents a hidden form property in a property form.
This class represents a property in a property form.
This class represents a number property in a property form.
editQuestion(bool $checkonly=false, ?bool $is_save_cmd=null)
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
static getHtmlPath(string $relative_path)
get url of path
setRequired(bool $a_required)
ilPropertyFormGUI $edit_form
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
getSolutionOutput(int $active_id, ?int $pass=null, 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_inline_feedback=true)
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)
__construct(Container $dic, ilPlugin $plugin)
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...
populateSpecificFeedbackInline($user_solution, $answer_id, $template)
getAnswersFrequency($relevantAnswers, $questionIndex)
getTestOutput(int $active_id, int $pass, bool $is_question_postponed=false, array|bool $user_post_solutions=false, bool $show_specific_inline_feedback=false)
renderEditForm(ilPropertyFormGUI $form)
populateQuestionSpecificFormPart(ilPropertyFormGUI $form)
getGenericFeedbackOutput(int $active_id, ?int $pass)