ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
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  public 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') . ' ' . $this->lng->txt('latex_edit_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", $this->renderLatex(
423  ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true)
424  ));
425  $template->setVariable('VALUE_TRUE', 1);
426  $template->setVariable('VALUE_FALSE', 0);
427 
428  if (isset($user_solution[$answer->getPosition()])) {
429  $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
430  $template->setVariable($tplVar, " checked=\"checked\"");
431  }
432 
433  $template->parseCurrentBlock();
434  }
435 
436  $template->setVariable("QUESTIONTEXT", $this->renderLatex($this->object->getQuestionForHTMLOutput()));
437  $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
438  $this->lng,
439  $this->object->getOptionLabel()
440  ));
441 
442  $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
443  $this->lng,
444  $this->object->getOptionLabel()
445  ));
446 
447  $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
448  $this->lng,
449  $this->object->getOptionLabel()
450  ));
451 
452  $questionoutput = $template->get();
453  $pageoutput = $this->outQuestionPage("", $is_question_postponed, $active_id, $questionoutput, $show_specific_inline_feedback);
454  return $pageoutput;
455  }
456 
457  public function getPreview(
458  bool $show_question_only = false,
459  bool $show_inline_feedback = false
460  ): string {
461  $user_solution = is_object($this->getPreviewSession()) ? (array) $this->getPreviewSession()->getParticipantsSolution() : [];
462  // shuffle output
463  $keys = $this->getParticipantsAnswerKeySequence();
464 
465  $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output.html", true, true, "components/ILIAS/TestQuestionPool");
466 
467  foreach ($keys as $answer_id) {
468  $answer = $this->object->getAnswer($answer_id);
469  if ($answer->getImageFile() !== null
470  && $answer->getImageFile() !== '') {
471  if ($this->object->getThumbSize()) {
472  $template->setCurrentBlock("preview");
473  $template->setVariable("URL_PREVIEW", $answer->getImageWebPath());
474  $template->setVariable("TEXT_PREVIEW", $this->lng->txt('preview'));
475  $template->setVariable("IMG_PREVIEW", ilUtil::getImagePath('media/enlarge.svg'));
476  $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
477  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
478  $alt = $answer->getImageFile();
479  if (strlen($answer->getAnswertext())) {
480  $alt = $answer->getAnswertext();
481  }
482  $alt = preg_replace("/<[^>]*?>/", "", $alt);
483  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
484  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
485  $template->parseCurrentBlock();
486  } else {
487  $template->setCurrentBlock("answer_image");
488  $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
489  [$width, $height, $type, $attr] = getimagesize($answer->getImageFsPath());
490  $alt = $answer->getImageFile();
491  if (strlen($answer->getAnswertext())) {
492  $alt = $answer->getAnswertext();
493  }
494  $alt = preg_replace("/<[^>]*?>/", "", $alt);
495  $template->setVariable("ATTR", $attr);
496  $template->setVariable("ANSWER_IMAGE_ALT", ilLegacyFormElementsUtil::prepareFormOutput($alt));
497  $template->setVariable("ANSWER_IMAGE_TITLE", ilLegacyFormElementsUtil::prepareFormOutput($alt));
498  $template->parseCurrentBlock();
499  }
500  }
501 
502  if ($show_inline_feedback) {
503  $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
504  }
505 
506  $template->setCurrentBlock("answer_row");
507  $template->setVariable("ANSWER_ID", $answer_id);
508  $template->setVariable("ANSWER_TEXT", $this->renderLatex(
509  ilLegacyFormElementsUtil::prepareTextareaOutput((string) $answer->getAnswertext(), true)
510  ));
511  $template->setVariable('VALUE_TRUE', 1);
512  $template->setVariable('VALUE_FALSE', 0);
513 
514  if (isset($user_solution[$answer->getPosition()])) {
515  $tplVar = $user_solution[$answer->getPosition()] ? 'CHECKED_ANSWER_TRUE' : 'CHECKED_ANSWER_FALSE';
516  $template->setVariable($tplVar, " checked=\"checked\"");
517  }
518 
519  $template->parseCurrentBlock();
520  }
521  $questiontext = $this->object->getQuestionForHTMLOutput();
522  if ($show_inline_feedback && $this->hasInlineFeedback()) {
523  $questiontext .= $this->buildFocusAnchorHtml();
524  }
525  $template->setVariable("QUESTIONTEXT", $this->renderLatex(
527  ));
528 
529  $template->setVariable("INSTRUCTIONTEXT", $this->object->getInstructionTextTranslation(
530  $this->lng,
531  $this->object->getOptionLabel()
532  ));
533 
534  $template->setVariable("OPTION_LABEL_TRUE", $this->object->getTrueOptionLabelTranslation(
535  $this->lng,
536  $this->object->getOptionLabel()
537  ));
538 
539  $template->setVariable("OPTION_LABEL_FALSE", $this->object->getFalseOptionLabelTranslation(
540  $this->lng,
541  $this->object->getOptionLabel()
542  ));
543 
544  $questionoutput = $template->get();
545  if (!$show_question_only) {
546  // get page object output
547  $questionoutput = $this->getILIASPage($questionoutput);
548  }
549  return $questionoutput;
550  }
551 
552  public function getSolutionOutput(
553  int $active_id,
554  ?int $pass = null,
555  bool $graphical_output = false,
556  bool $result_output = false,
557  bool $show_question_only = true,
558  bool $show_feedback = false,
559  bool $show_correct_solution = false,
560  bool $show_manual_scoring = false,
561  bool $show_question_text = true,
562  bool $show_inline_feedback = true
563  ): string {
564  $user_solution = [];
565 
566  if (($active_id > 0) && (!$show_correct_solution)) {
567  $solutions = $this->object->getSolutionValues($active_id, $pass);
568  foreach ($solutions as $idx => $solution_value) {
569  //$user_solution[$solution_value['value1']] = $solution_value['value2'];
570  $user_solution[] = [
571  'value1' => $solution_value['value1'],
572  'value2' => $solution_value['value2']
573  ];
574  }
575  } else {
576  // take the correct solution instead of the user solution
577  foreach ($this->object->getAnswers() as $answer) {
578  //$user_solution[$answer->getPosition()] = $answer->getCorrectness();
579  $user_solution[] = [
580  'value1' => $answer->getPosition(),
581  'value2' => $answer->getCorrectness()
582  ];
583  }
584  }
585 
586  return $this->renderSolutionOutput(
587  $user_solution,
588  $active_id,
589  $pass,
590  $graphical_output,
591  $result_output,
592  $show_question_only,
593  $show_feedback,
594  $show_correct_solution,
595  $show_manual_scoring,
596  $show_question_text,
597  false,
598  $show_inline_feedback
599  );
600  }
601 
602  public function renderSolutionOutput(
603  mixed $user_solutions,
604  int $active_id,
605  ?int $pass,
606  bool $graphical_output = false,
607  bool $result_output = false,
608  bool $show_question_only = true,
609  bool $show_feedback = false,
610  bool $show_correct_solution = false,
611  bool $show_manual_scoring = false,
612  bool $show_question_text = true,
613  bool $show_autosave_title = false,
614  bool $show_inline_feedback = false,
615  ): ?string {
616 
617  $user_solution = [];
618  foreach ($user_solutions as $idx => $solution_value) {
619  $user_solution[$solution_value['value1']] = $solution_value['value2'];
620  }
621  $template = new ilTemplate("tpl.il_as_qpl_mc_kprim_output_solution.html", true, true, "components/ILIAS/TestQuestionPool");
622  $keys = $this->getParticipantsAnswerKeySequence();
623  foreach ($keys as $answer_id) {
624  $answer = $this->object->getAnswer($answer_id);
625 
626  if (($active_id > 0) &&
627  !$show_correct_solution &&
628  $graphical_output) {
629  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_NOT_OK);
630  if (isset($user_solution[$answer->getPosition()]) && $user_solution[$answer->getPosition()] == $answer->getCorrectness()) {
631  $correctness_icon = $this->generateCorrectnessIconsForCorrectness(self::CORRECTNESS_OK);
632  }
633  $template->setCurrentBlock("icon_ok");
634  $template->setVariable("ICON_OK", $correctness_icon);
635  $template->parseCurrentBlock();
636  }
637  if ($answer->getImageFile() !== null
638  && $answer->getImageFile() !== '') {
639  $template->setCurrentBlock("answer_image");
640  if ($this->object->getThumbSize()) {
641  $template->setVariable("ANSWER_IMAGE_URL", $answer->getThumbWebPath());
642  } else {
643  $template->setVariable("ANSWER_IMAGE_URL", $answer->getImageWebPath());
644  }
645 
646  $template->setVariable(
647  "ANSWER_IMAGE_ALT",
649  $answer->getImageFile()
650  )
651  );
652  $template->setVariable(
653  "ANSWER_IMAGE_TITLE",
655  $answer->getImageFile()
656  )
657  );
658  $template->parseCurrentBlock();
659  }
660 
661  if ($show_feedback) {
662  $this->populateSpecificFeedbackInline($user_solution, $answer_id, $template);
663  }
664 
665  $template->setCurrentBlock("answer_row");
666  $template->setVariable("ANSWER_TEXT", $this->renderLatex(
667  ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true)
668  ));
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, "components/ILIAS/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", $this->renderLatex(
779  ));
780  $template->parseCurrentBlock();
781  }
782  }
783  }
784 
785  if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_ALL) {
786  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
787  if (strlen($fb)) {
788  $template->setCurrentBlock("feedback");
789  $template->setVariable("FEEDBACK", $this->renderLatex(
791  ));
792  $template->parseCurrentBlock();
793  }
794  }
795 
796  if ($this->object->getSpecificFeedbackSetting() == ilAssConfigurableMultiOptionQuestionFeedback::FEEDBACK_SETTING_CORRECT) {
797  $answer = $this->object->getAnswer($answer_id);
798 
799  if ($answer->getCorrectness()) {
800  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
801  if (strlen($fb)) {
802  $template->setCurrentBlock("feedback");
803  $template->setVariable("FEEDBACK", $this->renderLatex(
805  ));
806  $template->parseCurrentBlock();
807  }
808  }
809  }
810  }
811 
822  {
823  return [];
824  }
825 
836  {
837  return [];
838  }
839 
840  private function aggregateAnswers($rawSolutionData, $answers): array
841  {
842  $aggregate = [];
843 
844  foreach ($answers as $answer) {
845  $answerAgg = [
846  'answertext' => $answer->getAnswerText(), 'count_true' => 0, 'count_false' => 0
847  ];
848 
849  foreach ($rawSolutionData as $solutionRecord) {
850  if ($solutionRecord['value1'] == $answer->getPosition()) {
851  if ($solutionRecord['value2']) {
852  $answerAgg['count_true']++;
853  } else {
854  $answerAgg['count_false']++;
855  }
856  }
857  }
858 
859  $aggregate[] = $answerAgg;
860  }
861 
862  return $aggregate;
863  }
864 
865  public function getAnswersFrequency($relevantAnswers, $questionIndex): array
866  {
867  $agg = $this->aggregateAnswers($relevantAnswers, $this->object->getAnswers());
868 
869  $answers = [];
870 
871  foreach ($agg as $ans) {
872  $answers[] = [
873  'answer' => $ans['answertext'],
874  'frequency_true' => $ans['count_true'],
875  'frequency_false' => $ans['count_false']
876  ];
877  }
878 
879  return $answers;
880  }
881 
889  public function getAnswerFrequencyTableGUI($parentGui, $parentCmd, $relevantAnswers, $questionIndex): ilAnswerFrequencyStatisticTableGUI
890  {
891  $table = new ilKprimChoiceAnswerFreqStatTableGUI($parentGui, $parentCmd, $this->object);
892  $table->setQuestionIndex($questionIndex);
893  $table->setData($this->getAnswersFrequency($relevantAnswers, $questionIndex));
894  $table->initColumns();
895 
896  return $table;
897  }
898 
900  {
901  // points
902  $points = new ilNumberInputGUI($this->lng->txt('points'), 'points');
903  $points->setRequired(true);
904  $points->setSize(3);
905  $points->allowDecimals(true);
906  $points->setMinValue(0);
907  $points->setMinvalueShouldBeGreater(true);
908  $points->setValue($this->object->getPoints());
909  $form->addItem($points);
910 
911  // score partial solution
912  $scorePartialSolution = new ilCheckboxInputGUI($this->lng->txt('score_partsol_enabled'), 'score_partsol_enabled');
913  $scorePartialSolution->setInfo($this->lng->txt('score_partsol_enabled_info'));
914  $scorePartialSolution->setChecked($this->object->isScorePartialSolutionEnabled());
915  $form->addItem($scorePartialSolution);
916 
917  // answers
918  $kprimAnswers = new ilKprimChoiceCorrectionsInputGUI($this->lng->txt('answers'), 'kprimanswers');
919  $kprimAnswers->setInfo($this->lng->txt('kprim_answers_info'));
920  $kprimAnswers->setSize(64);
921  $kprimAnswers->setMaxLength(1000);
922  $kprimAnswers->setRequired(true);
923  $kprimAnswers->setQuestionObject($this->object);
924  $kprimAnswers->setValues($this->object->getAnswers());
925  $form->addItem($kprimAnswers);
926  }
927 
932  {
933  $this->object->setPoints(
934  (float) str_replace(',', '.', $form->getInput('points'))
935  );
936 
937  $this->object->setScorePartialSolutionEnabled(
938  (bool) $form->getInput('score_partsol_enabled')
939  );
940 
941  $this->object->setAnswers(
942  $form->getItemByPostVar('kprimanswers')->getValues()
943  );
944  }
945 }
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...
renderLatex($content)
Wrap content with latex in a LatexContent UI component and render it to be processed by MathJax in th...
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)