ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.assSingleChoiceGUI.php
Go to the documentation of this file.
1 <?php
2 
34 {
35  private bool $rebuild_thumbnails = false;
43  public function __construct(int $id = -1)
44  {
46  $this->object = new assSingleChoice();
47  if ($id >= 0) {
48  $this->object->loadFromDb($id);
49  }
50  }
51 
55  public function hasInlineFeedback(): bool
56  {
57  return $this->object->feedbackOBJ->isSpecificAnswerFeedbackAvailable($this->object->getId());
58  }
59 
63  protected function writePostData(bool $always = false): int
64  {
65  if ($always || !$this->editQuestion(true)) {
69  $this->saveTaxonomyAssignments();
70  return 0;
71  }
72  return 1;
73  }
74 
82  protected function getEditAnswersSingleLine(bool $checkonly = false): bool
83  {
84  if ($this->object->getSelfAssessmentEditingMode()) {
85  return $this->object->isSingleline();
86  }
87 
88  if ($checkonly) {
89  return $this->request_data_collector->int('types') === 0;
90  }
91 
92  if (empty($this->object->getLastChange())
93  && !$this->request_data_collector->isset('types')) {
94  // a new question is edited
95  return $this->object->getMultilineAnswerSetting() === 0;
96  }
97  // a saved question is edited
98  return $this->object->isSingleline();
99  }
100 
101  public function editQuestion(
102  bool $checkonly = false,
103  ?bool $is_save_cmd = null
104  ): bool {
105  $save = $is_save_cmd ?? $this->isSaveCommand();
106 
107  $form = new ilPropertyFormGUI();
108  $this->editForm = $form;
109 
110  $form->setFormAction($this->ctrl->getFormAction($this));
111  $form->setTitle($this->outQuestionType());
112  $is_singleline = $this->getEditAnswersSingleLine($checkonly);
113  if ($is_singleline) {
114  $form->setMultipart(true);
115  } else {
116  $form->setMultipart(false);
117  }
118  $form->setTableWidth('100%');
119  $form->setId('asssinglechoice');
120 
121  $this->addBasicQuestionFormProperties($form);
122  $this->populateQuestionSpecificFormPart($form, $is_singleline);
123  $this->populateAnswerSpecificFormPart($form, $is_singleline);
124 
125  $this->populateTaxonomyFormSection($form);
126 
127  $this->addQuestionFormCommandButtons($form);
128 
129  $errors = false;
130 
131  if ($save) {
132  foreach ($this->request_data_collector->getParsedBody() as $key => $value) {
133  $item = $form->getItemByPostVar($key);
134  if ($item === null) {
135  continue;
136  }
137  switch (get_class($item)) {
138  case 'ilDurationInputGUI':
139  $item->setHours($value['hh']);
140  $item->setMinutes($value['mm']);
141  $item->setSeconds($value['ss']);
142  break;
143  default:
144  $item->setValue($value);
145  }
146  }
147 
148  $errors = !$form->checkInput();
149  if ($errors) {
150  $checkonly = false;
151  }
152  }
153 
154  if (!$checkonly) {
155  $this->renderEditForm($form);
156  }
157  return $errors;
158  }
159 
160  public function uploadchoice(): void
161  {
163  $this->writePostData(true);
164  $this->editQuestion();
165  }
166 
167  public function removeimagechoice(): void
168  {
170  $this->writePostData(true);
171  $position = key($this->request_data_collector->raw('cmd')['removeimagechoice']);
172  $this->object->removeAnswerImage($position);
173  $this->editQuestion();
174  }
175 
176  public function addchoice(): void
177  {
178  $this->writePostData(true);
179  $position = key($this->request_data_collector->raw('cmd')['addchoice']);
180  $this->object->addAnswer('', 0, $position + 1);
181  $this->editQuestion();
182  }
183 
184  public function removechoice(): void
185  {
186  $this->writePostData(true);
187  $position = key($this->request_data_collector->raw('cmd')['removechoice']);
188  $this->object->deleteAnswer($position);
189  $this->editQuestion();
190  }
191 
192  public function getSolutionOutput(
193  int $active_id,
194  ?int $pass = null,
195  bool $graphical_output = false,
196  bool $result_output = false,
197  bool $show_question_only = true,
198  bool $show_feedback = false,
199  bool $show_correct_solution = false,
200  bool $show_manual_scoring = false,
201  bool $show_question_text = true,
202  bool $show_inline_feedback = true
203  ): string {
204 
205  if (($active_id > 0) && (!$show_correct_solution)) {
206  $user_solutions = $this->object->getSolutionValues($active_id, $pass);
207 
208  } else {
209  $found_index = -1;
210  $max_points = 0;
211  foreach ($this->object->answers as $index => $answer) {
212  if ($answer->getPoints() > $max_points) {
213  $max_points = $answer->getPoints();
214  $found_index = $index;
215  }
216  }
217  $user_solutions = [['value1' => $found_index]];
218  }
219 
220  return $this->renderSolutionOutput(
221  $user_solutions,
222  $active_id,
223  $pass,
224  $graphical_output,
225  $result_output,
226  $show_question_only,
227  $show_feedback,
228  $show_correct_solution,
229  $show_manual_scoring,
230  $show_question_text,
231  false,
232  $show_inline_feedback,
233  );
234  }
235 
236  public function renderSolutionOutput(
237  mixed $user_solutions,
238  int $active_id,
239  ?int $pass,
240  bool $graphical_output = false,
241  bool $result_output = false,
242  bool $show_question_only = true,
243  bool $show_feedback = false,
244  bool $show_correct_solution = false,
245  bool $show_manual_scoring = false,
246  bool $show_question_text = true,
247  bool $show_autosave_title = false,
248  bool $show_inline_feedback = false,
249  ): ?string {
250  $user_solution = '';
251  foreach ($user_solutions as $idx => $solution_value) {
252  $user_solution = $solution_value['value1'];
253  }
254 
255  $template = new ilTemplate('tpl.il_as_qpl_mc_sr_output_solution.html', true, true, 'components/ILIAS/TestQuestionPool');
256  $solutiontemplate = new ilTemplate('tpl.il_as_tst_solution_output.html', true, true, 'components/ILIAS/TestQuestionPool');
257 
258  $keys = $this->getChoiceKeys();
259  foreach ($keys as $answer_id) {
260  $answer = $this->object->answers[$answer_id];
261  if ($active_id > 0 && !$show_correct_solution && $graphical_output) {
262  $correctness = $this->generateCorrectness(
263  (string) $user_solution,
264  (string) $answer_id,
265  $answer->getPoints(),
266  $this->object->getMaximumPoints()
267  );
268  $template->setCurrentBlock('icon_ok');
269  $template->setVariable('ICON_OK', $this->generateCorrectnessIconsForCorrectness($correctness));
270  $template->parseCurrentBlock();
271  }
272  if ($answer->hasImage()) {
273  $template->setCurrentBlock('answer_image');
274  if ($this->object->getThumbSize()) {
275  $template->setVariable('ANSWER_IMAGE_URL', $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $answer->getImage());
276  } else {
277  $template->setVariable('ANSWER_IMAGE_URL', $this->object->getImagePathWeb() . $answer->getImage());
278  }
279  $alt = $answer->getImage();
280  if (strlen($answer->getAnswertext())) {
281  $alt = $answer->getAnswertext();
282  }
283  $alt = preg_replace('/<[^>]*?>/', '', $alt);
284  $template->setVariable('ANSWER_IMAGE_ALT', ilLegacyFormElementsUtil::prepareFormOutput($alt));
285  $template->setVariable('ANSWER_IMAGE_TITLE', ilLegacyFormElementsUtil::prepareFormOutput($alt));
286  $template->parseCurrentBlock();
287  }
288 
289  if (($show_feedback || !$this->isTestPresentationContext()) && $show_inline_feedback) {
290  $this->populateInlineFeedback($template, $answer_id, $user_solution);
291  }
292  $template->setCurrentBlock('answer_row');
293  $template->setVariable('ANSWER_TEXT', $this->renderLatex(
294  ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true)
295  ));
296 
297  if ($this->renderPurposeSupportsFormHtml() || $this->isRenderPurposePrintPdf()) {
298  if ((string) $user_solution === (string) $answer_id) {
299  $template->setVariable('SOLUTION_IMAGE', ilUtil::getHtmlPath(ilUtil::getImagePath('object/radiobutton_checked.png')));
300  $template->setVariable('SOLUTION_ALT', $this->lng->txt('checked'));
301  } else {
302  $template->setVariable('SOLUTION_IMAGE', ilUtil::getHtmlPath(ilUtil::getImagePath('object/radiobutton_unchecked.png')));
303  $template->setVariable('SOLUTION_ALT', $this->lng->txt('unchecked'));
304  }
305  } else {
306  $template->setVariable('QID', $this->object->getId());
307  $template->setVariable('SUFFIX', $show_correct_solution ? 'bestsolution' : 'usersolution');
308  $template->setVariable('SOLUTION_VALUE', $answer_id);
309  if ((string) $user_solution === (string) $answer_id) {
310  $template->setVariable('SOLUTION_CHECKED', 'checked');
311  }
312  }
313 
314  if ($result_output) {
315  $points = $this->object->answers[$answer_id]->getPoints();
316  $resulttext = ($points == 1) ? "(%s {$this->lng->txt('point')})" : "(%s {$this->lng->txt('points')})";
317  $template->setVariable('RESULT_OUTPUT', sprintf($resulttext, $points));
318  }
319  $template->parseCurrentBlock();
320  }
321 
322  $questiontext = $this->object->getQuestionForHTMLOutput();
323  if ($show_inline_feedback && $this->hasInlineFeedback()) {
324  $questiontext .= $this->buildFocusAnchorHtml();
325  }
326  if ($show_question_text === true) {
327  $template->setVariable('QUESTIONTEXT', $this->renderLatex(
329  ));
330  }
331  $questionoutput = $template->get();
332  $feedback = ($show_feedback && !$this->isTestPresentationContext()) ? $this->getGenericFeedbackOutput((int) $active_id, $pass) : '';
333  if ($feedback !== '') {
334  $cssClass = (
335  $this->hasCorrectSolution($active_id, $pass) ?
337  );
338 
339  $solutiontemplate->setVariable('ILC_FB_CSS_CLASS', $cssClass);
340  $solutiontemplate->setVariable('FEEDBACK', ilLegacyFormElementsUtil::prepareTextareaOutput($feedback, true));
341  }
342  $solutiontemplate->setVariable('SOLUTION_OUTPUT', $questionoutput);
343 
344  $solutionoutput = $solutiontemplate->get();
345 
346  if (!$show_question_only) {
347  // get page object output
348  $solutionoutput = $this->getILIASPage($solutionoutput);
349  }
350  return $solutionoutput;
351  }
352 
353  private function generateCorrectness(
354  string $user_solution,
355  string $answer_id,
356  float $answer_points,
357  float $maximum_points
358  ): int {
359  if ($user_solution === $answer_id
360  && $answer_points === $maximum_points
361  || $user_solution !== $answer_id
362  && $answer_points === 0.0
363  ) {
364  return self::CORRECTNESS_OK;
365  }
366 
367  if ($user_solution === $answer_id
368  && $answer_points > 0.0) {
369  return self::CORRECTNESS_MOSTLY_OK;
370  }
371 
372  return self::CORRECTNESS_NOT_OK;
373  }
374 
375  public function getPreview(
376  bool $show_question_only = false,
377  bool $show_inline_feedback = false
378  ): string {
379  $keys = $this->getChoiceKeys();
380 
381  $template = new ilTemplate('tpl.il_as_qpl_mc_sr_output.html', true, true, 'components/ILIAS/TestQuestionPool');
382  foreach ($keys as $answer_id) {
383  $answer = $this->object->answers[$answer_id];
384  if ($answer->hasImage()) {
385  if ($this->object->getThumbSize()) {
386  $template->setCurrentBlock('preview');
387  $template->setVariable('URL_PREVIEW', $this->object->getImagePathWeb() . $answer->getImage());
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', $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $answer->getImage());
391  list($width, $height, $type, $attr) = getimagesize($this->object->getImagePath() . $answer->getImage());
392  $alt = $answer->getImage();
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', $this->object->getImagePathWeb() . $answer->getImage());
403  list($width, $height, $type, $attr) = getimagesize($this->object->getImagePath() . $answer->getImage());
404  $alt = $answer->getImage();
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  if ($show_inline_feedback && is_object($this->getPreviewSession())) {
416  $this->populateInlineFeedback($template, $answer_id, $this->getPreviewSession()->getParticipantsSolution());
417  }
418  $template->setCurrentBlock('answer_row');
419  $template->setVariable('QID', $this->object->getId() . 'ID');
420  $template->setVariable('ANSWER_ID', $answer_id);
421  $template->setVariable('ANSWER_TEXT', $this->renderLatex(
422  ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true)
423  ));
424 
425  if (is_object($this->getPreviewSession())) {
426  $user_solution = $this->getPreviewSession()->getParticipantsSolution();
427  if ((string) $user_solution === (string) $answer_id) {
428  $template->setVariable('CHECKED_ANSWER', ' checked="checked"');
429  }
430  }
431 
432  $template->parseCurrentBlock();
433  }
434  $questiontext = $this->object->getQuestionForHTMLOutput();
435  if ($show_inline_feedback && $this->hasInlineFeedback()) {
436  $questiontext .= $this->buildFocusAnchorHtml();
437  }
438  $template->setVariable('QUESTIONTEXT', $this->renderLatex(
440  ));
441  $questionoutput = $template->get();
442  if (!$show_question_only) {
443  // get page object output
444  $questionoutput = $this->getILIASPage($questionoutput);
445  }
446  return $questionoutput;
447  }
448 
449  public function getTestOutput(
450  int $active_id,
451  int $pass,
452  bool $is_question_postponed = false,
453  array|bool $user_post_solutions = false,
454  bool $show_specific_inline_feedback = false
455  ): string {
456  $keys = $this->getChoiceKeys();
457 
458  $user_solution = '';
459  if ($active_id !== 0) {
460  $solutions = $this->object->getTestOutputSolutions($active_id, $pass);
461  foreach ($solutions as $solution_value) {
462  $user_solution = $solution_value['value1'];
463  }
464  }
465 
466  $template = new ilTemplate('tpl.il_as_qpl_mc_sr_output.html', true, true, 'components/ILIAS/TestQuestionPool');
467  foreach ($keys as $answer_id) {
468  $answer = $this->object->answers[$answer_id];
469  if ($answer->hasImage()) {
470  if ($this->object->getThumbSize()) {
471  $template->setCurrentBlock('preview');
472  $template->setVariable('URL_PREVIEW', $this->object->getImagePathWeb() . $answer->getImage());
473  $template->setVariable('TEXT_PREVIEW', $this->lng->txt('preview'));
474  $template->setVariable('IMG_PREVIEW', ilUtil::getImagePath('media/enlarge.svg'));
475  $template->setVariable('ANSWER_IMAGE_URL', $this->object->getImagePathWeb() . $this->object->getThumbPrefix() . $answer->getImage());
476  list($width, $height, $type, $attr) = getimagesize($this->object->getImagePath() . $answer->getImage());
477  $alt = $answer->getImage();
478  if (strlen($answer->getAnswertext())) {
479  $alt = $answer->getAnswertext();
480  }
481  $alt = preg_replace('/<[^>]*?>/', '', $alt);
482  $template->setVariable('ANSWER_IMAGE_ALT', ilLegacyFormElementsUtil::prepareFormOutput($alt));
483  $template->setVariable('ANSWER_IMAGE_TITLE', ilLegacyFormElementsUtil::prepareFormOutput($alt));
484  $template->parseCurrentBlock();
485  } else {
486  $template->setCurrentBlock('answer_image');
487  $template->setVariable('ANSWER_IMAGE_URL', $this->object->getImagePathWeb() . $answer->getImage());
488  list($width, $height, $type, $attr) = getimagesize($this->object->getImagePath() . $answer->getImage());
489  $alt = $answer->getImage();
490  if (strlen($answer->getAnswertext())) {
491  $alt = $answer->getAnswertext();
492  }
493  $alt = preg_replace('/<[^>]*?>/', '', $alt);
494  $template->setVariable('ATTR', $attr);
495  $template->setVariable('ANSWER_IMAGE_ALT', ilLegacyFormElementsUtil::prepareFormOutput($alt));
496  $template->setVariable('ANSWER_IMAGE_TITLE', ilLegacyFormElementsUtil::prepareFormOutput($alt));
497  $template->parseCurrentBlock();
498  }
499  }
500 
501  if ($show_specific_inline_feedback) {
502  $this->populateInlineFeedback($template, $answer_id, $user_solution);
503  }
504  $template->setCurrentBlock('answer_row');
505  $template->setVariable('ANSWER_ID', $answer_id);
506  $template->setVariable('ANSWER_TEXT', $this->renderLatex(
507  ilLegacyFormElementsUtil::prepareTextareaOutput($answer->getAnswertext(), true)
508  ));
509  if ($user_solution === (string) $answer_id) {
510  $template->setVariable('CHECKED_ANSWER', ' checked="checked"');
511  }
512  $template->parseCurrentBlock();
513  }
514  $template->setVariable('QUESTIONTEXT', $this->renderLatex(
515  $this->object->getQuestionForHTMLOutput()
516  ));
517  $questionoutput = $template->get();
518  $pageoutput = $this->outQuestionPage('', $is_question_postponed, $active_id, $questionoutput, $show_specific_inline_feedback);
519  return $pageoutput;
520  }
521 
522  /*
523  * Create the key index numbers for the array of choices
524  *
525  * @return array
526  */
527  public function getChoiceKeys()
528  {
529  $choice_keys = array_keys($this->object->answers);
530 
531  if ($this->object->getShuffle()) {
532  $choice_keys = $this->object->getShuffler()->transform($choice_keys);
533  }
534 
535  return $choice_keys;
536  }
537 
538  public function getSpecificFeedbackOutput(array $user_solution): string
539  {
540  // No return value, this question type supports inline specific feedback.
541  $output = '';
543  }
544 
546  {
547  $is_multi_line = $this->request_data_collector->string('types');
548  if ($is_multi_line === '') {
549  $is_multi_line = '0';
550  }
551  $this->object->setMultilineAnswerSetting($is_multi_line);
552  $this->object->setShuffle($this->request_data_collector->bool('shuffle') ?? false);
553 
554  $choice = $this->request_data_collector->raw('choice');
555  if (isset($choice['imagename']) && is_array($choice['imagename']) && $is_multi_line === '1') {
556  $this->object->setIsSingleline(true);
557  $this->tpl->setOnScreenMessage('info', $this->lng->txt('info_answer_type_change'), true);
558  } else {
559  $this->object->setIsSingleline($is_multi_line === '0');
560  }
561 
562  $object_thumb_size = $this->object->getThumbSize();
563  $thumb_size = $this->request_data_collector->int('thumb_size') ?? $object_thumb_size;
564  if ($thumb_size !== $object_thumb_size) {
565  $this->object->setThumbSize($thumb_size);
566  $this->rebuild_thumbnails = true;
567  }
568  }
569 
570  public function populateQuestionSpecificFormPart(\ilPropertyFormGUI $form, bool $is_singleline = false): ilPropertyFormGUI
571  {
572  // shuffle
573  $shuffle = new ilCheckboxInputGUI($this->lng->txt('shuffle_answers'), 'shuffle');
574  $shuffle->setValue(1);
575  $shuffle->setChecked($this->object->getShuffle());
576  $shuffle->setRequired(false);
577  $form->addItem($shuffle);
578 
579  if (!$this->object->getSelfAssessmentEditingMode()) {
580  // Answer types
581  $types = new ilSelectInputGUI($this->lng->txt('answer_types'), 'types');
582  $types->setRequired(false);
583  $types->setOptions(
584  [
585  0 => $this->lng->txt('answers_singleline'),
586  1 => $this->lng->txt('answers_multiline'),
587  ]
588  );
589  $types->setValue($is_singleline ? 0 : 1);
590  $form->addItem($types);
591  }
592 
593  if ($is_singleline) {
594  // thumb size
595  $thumb_size = new ilNumberInputGUI($this->lng->txt('thumb_size'), 'thumb_size');
596  $thumb_size->setSuffix($this->lng->txt('thumb_size_unit_pixel'));
597  $thumb_size->setMinValue($this->object->getMinimumThumbSize());
598  $thumb_size->setMaxValue($this->object->getMaximumThumbSize());
599  $thumb_size->setDecimals(0);
600  $thumb_size->setSize(6);
601  $thumb_size->setInfo($this->lng->txt('thumb_size_info'));
602  $thumb_size->setValue($this->object->getThumbSize());
603  $thumb_size->setRequired(true);
604  } else {
605  $thumb_size = new ilHiddenInputGUI('thumb_size');
606  $thumb_size->setValue($this->object->getThumbSize());
607  }
608  $form->addItem($thumb_size);
609 
610  return $form;
611  }
612 
623  {
624  return [];
625  }
626 
627  public function writeAnswerSpecificPostData(ilPropertyFormGUI $form): void
628  {
629  // Delete all existing answers and create new answers from the form data
630  $this->object->flushAnswers();
631  $choice = $this->cleanupAnswerText(
632  $this->request_data_collector->raw('choice') ?? [],
633  $this->object->isSingleline() === false
634  );
635 
636  if ($choice === []) {
637  return;
638  }
639 
640  if (!$this->object->isSingleline()) {
641  foreach ($choice['answer'] as $index => $answer) {
642  $answertext = $answer;
643  $this->object->addAnswer(
644  $answertext,
645  $this->refinery->kindlyTo()->float()->transform($choice['points'][$index]),
646  $index,
647  null,
648  $choice['answer_id'][$index]
649  );
650  }
651 
652  return;
653  }
654 
655  foreach ($choice['answer'] as $index => $answertext) {
656  $answertext = htmlentities($answertext);
657  $picturefile = $choice['imagename'][$index] ?? null;
658  $file_org_name = $_FILES['choice']['name']['image'][$index] ?? '';
659  $file_temp_name = $_FILES['choice']['tmp_name']['image'][$index] ?? '';
660 
661  if ($file_temp_name !== '') {
662  // check suffix
663  $file_name_parts = explode('.', $file_org_name);
664  $suffix = strtolower(array_pop($file_name_parts));
665  if (in_array($suffix, ['jpg', 'jpeg', 'png', 'gif'])) {
666  // upload image
667  $filename = $this->object->buildHashedImageFilename($file_org_name);
668  if ($this->object->setImageFile($filename, $file_temp_name) == 0) {
669  $picturefile = $filename;
670  }
671  }
672  }
673 
674  $points = (float) str_replace(',', '.', $choice['points'][$index]);
675  $this->object->addAnswer(
676  $answertext,
677  $points,
678  $index,
679  $picturefile,
680  $choice['answer_id'][$index]
681  );
682  }
683 
684  if ($this->rebuild_thumbnails) {
685  $this->object->setAnswers(
686  $this->object->rebuildThumbnails(
687  $this->object->isSingleline(),
688  $this->object->getThumbSize(),
689  $this->object->getImagePath(),
690  $this->object->getAnswers()
691  )
692  );
693  }
694  }
695 
696  public function populateAnswerSpecificFormPart(\ilPropertyFormGUI $form, bool $is_singleline = false): ilPropertyFormGUI
697  {
698  $choices = new ilSingleChoiceWizardInputGUI($this->lng->txt('answers'), 'choice');
699  $choices->setRequired(true);
700  $choices->setQuestionObject($this->object);
701  $choices->setSingleline($is_singleline);
702  $choices->setAllowMove(false);
703  if ($this->object->getSelfAssessmentEditingMode()) {
704  $choices->setSize(40);
705  }
706  if ($this->object->getAnswerCount() == 0) {
707  $this->object->addAnswer('', 0, 0);
708  }
709  $choices->setValues(array_map(
710  function (ASS_AnswerBinaryStateImage $value) {
711  $value->setAnswerText(html_entity_decode($value->getAnswerText()));
712  return $value;
713  },
714  $this->object->getAnswers()
715  ));
716  $choices->setInfo($choices->getInfo() . ' ' . $this->lng->txt('latex_edit_info'));
717  $form->addItem($choices);
718  return $form;
719  }
720 
731  {
732  return [];
733  }
734 
735  private function aggregateAnswers($relevant_answers_chosen, $answers_defined_on_question): array
736  {
737  $aggregate = [];
738  foreach ($answers_defined_on_question as $answer) {
739  $aggregated_info_for_answer = [];
740  $aggregated_info_for_answer['answertext'] = $answer->getAnswerText();
741  $aggregated_info_for_answer['count_checked'] = 0;
742 
743  foreach ($relevant_answers_chosen as $relevant_answer) {
744  if ($relevant_answer['value1'] == $answer->getOrder()) {
745  $aggregated_info_for_answer['count_checked']++;
746  }
747  }
748  $aggregated_info_for_answer['count_unchecked'] =
749  ceil(count($relevant_answers_chosen) / count($answers_defined_on_question))
750  - $aggregated_info_for_answer['count_checked'];
751 
752  $aggregate[] = $aggregated_info_for_answer;
753  }
754  return $aggregate;
755  }
756 
762  public function renderAggregateView($aggregate): ilTemplate
763  {
764  $tpl = new ilTemplate('tpl.il_as_aggregated_answers_table.html', true, true, 'components/ILIAS/TestQuestionPool');
765 
766  $tpl->setCurrentBlock('headercell');
767  $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_answer_header'));
769 
770  $tpl->setCurrentBlock('headercell');
771  $tpl->setVariable('HEADER', $this->lng->txt('tst_answer_aggr_frequency_header'));
773 
774  foreach ($aggregate as $line_data) {
775  $tpl->setCurrentBlock('aggregaterow');
776  $tpl->setVariable('OPTION', $line_data['answertext']);
777  $tpl->setVariable('COUNT', $line_data['count_checked']);
779  }
780  return $tpl;
781  }
782 
783  private function populateInlineFeedback($template, $answer_id, $user_solution): void
784  {
785  $feedbackOutputRequired = false;
786 
787  switch ($this->object->getSpecificFeedbackSetting()) {
788  case 1:
789  $feedbackOutputRequired = true;
790  break;
791 
792  case 2:
793  if ((string) $user_solution === (string) $answer_id) {
794  $feedbackOutputRequired = true;
795  }
796  break;
797 
798  case 3:
799  if ($this->object->getAnswer($answer_id)->getPoints() > 0) {
800  $feedbackOutputRequired = true;
801  }
802  break;
803  }
804 
805  if ($feedbackOutputRequired) {
806  $fb = $this->object->feedbackOBJ->getSpecificAnswerFeedbackTestPresentation($this->object->getId(), 0, $answer_id);
807  if (strlen($fb)) {
808  $template->setCurrentBlock('feedback');
809  $template->setVariable('FEEDBACK', $this->renderLatex(
811  ));
812  $template->parseCurrentBlock();
813  }
814  }
815  }
816 
817  public function getAnswersFrequency($relevantAnswers, $questionIndex): array
818  {
819  $agg = $this->aggregateAnswers($relevantAnswers, $this->object->getAnswers());
820 
821  $answers = [];
822 
823  foreach ($agg as $ans) {
824  $answers[] = [
825  'answer' => $ans['answertext'],
826  'frequency' => $ans['count_checked']
827  ];
828  }
829 
830  return $answers;
831  }
832 
834  {
835  $choices = new ilAssSingleChoiceCorrectionsInputGUI($this->lng->txt('answers'), 'choice');
836  $choices->setRequired(true);
837  $choices->setQuestionObject($this->object);
838  $choices->setValues($this->object->getAnswers());
839  $form->addItem($choices);
840  }
841 
846  {
847  $input = $form->getItemByPostVar('choice');
848  $values = $input->getValues();
849 
850  foreach ($this->object->getAnswers() as $index => $answer) {
851  /* @var ASS_AnswerMultipleResponseImage $answer */
852  $points = (float) str_replace(',', '.', $values[$index]->getPoints());
853  $answer->setPoints($points);
854  }
855  }
856 }
hasCorrectSolution($activeId, $passIndex)
__construct(int $id=-1)
assSingleChoiceGUI constructor
populateQuestionSpecificFormPart(\ilPropertyFormGUI $form, bool $is_singleline=false)
setSuffix(string $a_value)
generateCorrectnessIconsForCorrectness(int $correctness)
aggregateAnswers($relevant_answers_chosen, $answers_defined_on_question)
setCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Sets the template to the given block.
This class represents a selection list property in a property form.
editQuestion(bool $checkonly=false, ?bool $is_save_cmd=null)
getItemByPostVar(string $a_post_var)
writeAnswerSpecificPostData(ilPropertyFormGUI $form)
Extracts the answer specific values from the request and applies them to the data object...
Class for answers with a binary state indicator.
renderLatex($content)
Wrap content with latex in a LatexContent UI component and render it to be processed by MathJax in th...
getTestOutput(int $active_id, int $pass, bool $is_question_postponed=false, array|bool $user_post_solutions=false, bool $show_specific_inline_feedback=false)
populateInlineFeedback($template, $answer_id, $user_solution)
addBasicQuestionFormProperties(ilPropertyFormGUI $form)
parseCurrentBlock(string $blockname=self::DEFAULT_BLOCK)
Parses the given block.
ilGlobalPageTemplate $tpl
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)
static prepareFormOutput($a_str, bool $a_strip=false)
getSpecificFeedbackOutput(array $user_solution)
getAnswersFrequency($relevantAnswers, $questionIndex)
populateTaxonomyFormSection(ilPropertyFormGUI $form)
generateCorrectness(string $user_solution, string $answer_id, float $answer_points, float $maximum_points)
addQuestionFormCommandButtons(ilPropertyFormGUI $form)
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
This class represents a hidden form property in a property form.
getAfterParticipationSuppressionAnswerPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
This class represents a number property in a property form.
Class for single choice questions.
writePostData(bool $always=false)
{}
static getImagePath(string $image_name, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
getAfterParticipationSuppressionQuestionPostVars()
Returns a list of postvars which will be suppressed in the form output when used in scoring adjustmen...
populateAnswerSpecificFormPart(\ilPropertyFormGUI $form, bool $is_singleline=false)
static getHtmlPath(string $relative_path)
get url of path
setRequired(bool $a_required)
getEditAnswersSingleLine(bool $checkonly=false)
Get the single/multiline editing of answers.
$filename
Definition: buildRTE.php:78
populateCorrectionsFormProperties(ilPropertyFormGUI $form)
This class represents a single choice wizard property in a property form.
getILIASPage(string $html="")
Returns the ILIAS Page around a question.
saveCorrectionsFormProperties(ilPropertyFormGUI $form)
outQuestionPage($a_temp_var, $a_postponed=false, $active_id="", $html="", $inlineFeedbackEnabled=false)
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Definition: plugin.php:23
__construct(Container $dic, ilPlugin $plugin)
cleanupAnswerText(array $answer_text, bool $is_rte)
sk - 12.05.2023: This is one more of those that we need, but don&#39;t want.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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...
setVariable(string $variable, $value='')
Sets the given variable to the given value.
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,)
getPreview(bool $show_question_only=false, bool $show_inline_feedback=false)
renderEditForm(ilPropertyFormGUI $form)
writeQuestionSpecificPostData(ilPropertyFormGUI $form)
Extracts the question specific values from the request and applies them to the data object...
getGenericFeedbackOutput(int $active_id, ?int $pass)