ILIAS  trunk Revision v11.0_alpha-2638-g80c1d007f79
class.assImagemapQuestion.php
Go to the documentation of this file.
1 <?php
2 
19 declare(strict_types=1);
20 
25 
40 {
41  private RequestDataCollector $request; // Hate it.
42 
43  // hey: prevPassSolutions - wtf is imagemap ^^
44  public $currentSolution = [];
45  // hey.
46 
47  public const MODE_SINGLE_CHOICE = 0;
48  public const MODE_MULTIPLE_CHOICE = 1;
49 
50  public const AVAILABLE_SHAPES = [
51  'RECT' => 'rect',
52  'CIRCLE' => 'circle',
53  'POLY' => 'poly'];
54 
56  public $answers;
57 
60 
63 
65  public $coords;
66 
68  protected $is_multiple_choice = false;
69 
83  public function __construct(
84  $title = '',
85  $comment = '',
86  $author = '',
87  $owner = -1,
88  $question = '',
89  $image_filename = ''
90  ) {
92  $this->image_filename = $image_filename;
93  $this->answers = [];
94  $this->coords = [];
95 
96  $local_dic = QuestionPoolDIC::dic();
97  $this->request = $local_dic['request_data_collector'];
98  }
99 
106  {
107  $this->is_multiple_choice = $is_multiple_choice;
108  }
109 
115  public function getIsMultipleChoice(): bool
116  {
118  }
119 
120  public function isComplete(): bool
121  {
122  if ($this->title !== ''
123  && $this->author
124  && $this->question
125  && $this->image_filename
126  && $this->answers !== []
127  && $this->getMaximumPoints() > 0
128  ) {
129  return true;
130  }
131  return false;
132  }
133 
134  public function saveToDb(?int $original_id = null): void
135  {
139  parent::saveToDb($original_id);
140  }
141 
142  public function saveAnswerSpecificDataToDb(): void
143  {
144  $this->db->manipulateF(
145  'DELETE FROM qpl_a_imagemap WHERE question_fi = %s',
146  [ 'integer' ],
147  [ $this->getId() ]
148  );
149 
150  // Anworten wegschreiben
151  foreach ($this->answers as $key => $value) {
152  $answer_obj = $this->answers[$key];
153  $answer_obj->setOrder($key);
154  $next_id = $this->db->nextId('qpl_a_imagemap');
155  $this->db->manipulateF(
156  'INSERT INTO qpl_a_imagemap (answer_id, question_fi, answertext, points, aorder, coords, area, points_unchecked) VALUES (%s, %s, %s, %s, %s, %s, %s, %s)',
157  [ 'integer', 'integer', 'text', 'float', 'integer', 'text', 'text', 'float' ],
158  [ $next_id, $this->id, $answer_obj->getAnswertext(
159  ), $answer_obj->getPoints(), $answer_obj->getOrder(
160  ), $answer_obj->getCoords(), $answer_obj->getArea(
161  ), $answer_obj->getPointsUnchecked() ]
162  );
163  }
164  }
165 
166  public function saveAdditionalQuestionDataToDb(): void
167  {
168  $this->db->manipulateF(
169  'DELETE FROM ' . $this->getAdditionalTableName() . ' WHERE question_fi = %s',
170  [ 'integer' ],
171  [ $this->getId() ]
172  );
173 
174  $this->db->manipulateF(
175  'INSERT INTO ' . $this->getAdditionalTableName(
176  ) . ' (question_fi, image_file, is_multiple_choice) VALUES (%s, %s, %s)',
177  [ 'integer', 'text', 'integer' ],
178  [
179  $this->getId(),
180  $this->image_filename,
181  (int) $this->is_multiple_choice
182  ]
183  );
184  }
185 
187  \assQuestion $target
188  ): \assQuestion {
189  $this->copyImagemapFiles($this->getId(), $this->getObjId(), $target->getId(), $target->getObjId());
190  return $target;
191  }
192 
193  public function copyImagemapFiles(
194  int $source_question_id,
195  int $source_parent_id,
196  int $target_question_id,
197  int $target_parent_id
198  ): void {
199  $image_source_path = $this->getImagePath($source_question_id, $source_parent_id);
200  $image_target_path = $this->getImagePath($target_question_id, $target_parent_id);
201 
202  if (!file_exists($image_target_path)) {
203  ilFileUtils::makeDirParents($image_target_path);
204  } else {
205  $this->removeAllImageFiles($image_target_path);
206  }
207 
208  $src = opendir($image_source_path);
209  while ($src_file = readdir($src)) {
210  if ($src_file === '.' || $src_file === '..') {
211  continue;
212  }
213  copy(
214  $image_source_path . DIRECTORY_SEPARATOR . $src_file,
215  $image_target_path . DIRECTORY_SEPARATOR . $src_file
216  );
217  }
218  }
219 
220  public function loadFromDb(int $question_id): void
221  {
222  $result = $this->db->queryF(
223  'SELECT qpl_questions.*, ' . $this->getAdditionalTableName() . '.* FROM qpl_questions LEFT JOIN ' . $this->getAdditionalTableName() . ' ON ' . $this->getAdditionalTableName() . '.question_fi = qpl_questions.question_id WHERE qpl_questions.question_id = %s',
224  ['integer'],
225  [$question_id]
226  );
227  if ($result->numRows() == 1) {
228  $data = $this->db->fetchAssoc($result);
229  $this->setId($question_id);
230  $this->setObjId($data['obj_fi']);
231  $this->setTitle((string) $data['title']);
232  $this->setComment((string) $data['description']);
233  $this->setOriginalId($data['original_id']);
234  $this->setNrOfTries($data['nr_of_tries']);
235  $this->setAuthor($data['author']);
236  $this->setPoints($data['points']);
237  $this->setOwner($data['owner']);
238  $this->setIsMultipleChoice($data['is_multiple_choice'] == self::MODE_MULTIPLE_CHOICE);
239  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data['question_text'], 1));
240  $this->setImageFilename($data['image_file'] ?? '');
241 
242  try {
243  $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
246  }
247 
248  try {
249  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
250  } catch (ilTestQuestionPoolException $e) {
251  }
252 
253  $result = $this->db->queryF(
254  'SELECT * FROM qpl_a_imagemap WHERE question_fi = %s ORDER BY aorder ASC',
255  ['integer'],
256  [$question_id]
257  );
258  if ($result->numRows() > 0) {
259  while ($data = $this->db->fetchAssoc($result)) {
260  $image_map_question = new ASS_AnswerImagemap($data['answertext'] ?? '', $data['points'], $data['aorder']);
261  $image_map_question->setCoords($data['coords']);
262  $image_map_question->setArea($data['area']);
263  $image_map_question->setPointsUnchecked($data['points_unchecked']);
264  array_push($this->answers, $image_map_question);
265  }
266  }
267  }
268  parent::loadFromDb($question_id);
269  }
270 
271  public function uploadImagemap(array $shapes): int
272  {
273  $added = 0;
274 
275  if (count($shapes) > 0) {
276  foreach ($shapes as $shape) {
277  $this->addAnswer($shape->getAnswertext(), 0.0, count($this->answers), $shape->getCoords(), $shape->getArea());
278  $added++;
279  }
280  }
281 
282  return $added;
283  }
284 
285  public function getImageFilename(): string
286  {
287  return $this->image_filename;
288  }
289 
290  public function setImageFilename(
291  string $image_filename,
292  string $image_tempfilename = ''
293  ): void {
294  if (!empty($image_filename)) {
295  $image_filename = str_replace(' ', '_', $image_filename);
296  $this->image_filename = $image_filename;
297  }
298  if (!empty($image_tempfilename)) {
299  $imagepath = $this->getImagePath();
300  if (!file_exists($imagepath)) {
301  ilFileUtils::makeDirParents($imagepath);
302  }
303  if (!ilFileUtils::moveUploadedFile($image_tempfilename, $image_filename, $imagepath . $image_filename)) {
304  $this->tpl->setOnScreenMessage('failure', 'The image could not be uploaded!');
305  return;
306  }
307  $this->log->write('gespeichert: ' . $imagepath . $image_filename);
308  }
309  }
310 
311  public function get_imagemap_contents(string $href = '#'): string
312  {
313  $imagemap_contents = '<map name=\'' . $this->title . '\'> ';
314  for ($i = 0; $i < count($this->answers); $i++) {
315  $imagemap_contents .= '<area alt=\'' . $this->answers[$i]->getAnswertext() . '\' ';
316  $imagemap_contents .= 'shape=\'' . $this->answers[$i]->getArea() . '\' ';
317  $imagemap_contents .= 'coords=\'' . $this->answers[$i]->getCoords() . '\' ';
318  $imagemap_contents .= "href=\"{$href}&selimage=" . $this->answers[$i]->getOrder() . "\" /> ";
319  }
320  $imagemap_contents .= '</map>';
321  return $imagemap_contents;
322  }
323 
324  public function addAnswer(
325  string $answertext = '',
326  float $points = 0.0,
327  int $order = 0,
328  string $coords = '',
329  string $area = '',
330  float $points_unchecked = 0.0
331  ): void {
332  if (array_key_exists($order, $this->answers)) {
333  // Insert answer
334  $answer = new ASS_AnswerImagemap($answertext, $points, $order, 0, -1);
335  $answer->setCoords($coords);
336  $answer->setArea($area);
337  $answer->setPointsUnchecked($points_unchecked);
338  for ($i = count($this->answers) - 1; $i >= $order; $i--) {
339  $this->answers[$i + 1] = $this->answers[$i];
340  $this->answers[$i + 1]->setOrder($i + 1);
341  }
342  $this->answers[$order] = $answer;
343  } else {
344  // Append answer
345  $answer = new ASS_AnswerImagemap($answertext, $points, count($this->answers), 0, -1);
346  $answer->setCoords($coords);
347  $answer->setArea($area);
348  $answer->setPointsUnchecked($points_unchecked);
349  array_push($this->answers, $answer);
350  }
351  }
352 
353  public function getAnswerCount(): int
354  {
355  return count($this->answers);
356  }
357 
358  public function getAnswer(int $index = 0): ?ASS_AnswerImagemap
359  {
360  if ($index < 0) {
361  return null;
362  }
363  if (count($this->answers) < 1) {
364  return null;
365  }
366  if ($index >= count($this->answers)) {
367  return null;
368  }
369  return $this->answers[$index];
370  }
371 
372  public function &getAnswers(): array
373  {
374  return $this->answers;
375  }
376 
377  public function deleteArea(int $index = 0): void
378  {
379  if ($index < 0) {
380  return;
381  }
382  if (count($this->answers) < 1) {
383  return;
384  }
385  if ($index >= count($this->answers)) {
386  return;
387  }
388  unset($this->answers[$index]);
389  $this->answers = array_values($this->answers);
390  for ($i = 0; $i < count($this->answers); $i++) {
391  if ($this->answers[$i]->getOrder() > $index) {
392  $this->answers[$i]->setOrder($i);
393  }
394  }
395  }
396 
397  public function flushAnswers(): void
398  {
399  $this->answers = [];
400  }
401 
402  public function getMaximumPoints(): float
403  {
404  $points = 0;
405  foreach ($this->answers as $key => $value) {
406  if ($this->is_multiple_choice) {
407  if ($value->getPoints() > $value->getPointsUnchecked()) {
408  $points += $value->getPoints();
409  } else {
410  $points += $value->getPointsUnchecked();
411  }
412  } else {
413  if ($value->getPoints() > $points) {
414  $points = $value->getPoints();
415  }
416  }
417  }
418  return $points;
419  }
420 
421  public function calculateReachedPoints(
422  int $active_id,
423  ?int $pass = null,
424  bool $authorized_solution = true
425  ): float {
426  if ($pass === null) {
427  $pass = $this->getSolutionMaxPass($active_id);
428  }
429  $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorized_solution);
430  $found_values = [];
431  while ($data = $this->db->fetchAssoc($result)) {
432  if ($data['value1'] !== '') {
433  $found_values[] = $data['value1'];
434  }
435  }
436 
437  $points = $this->calculateReachedPointsForSolution($found_values);
438 
439  return $points;
440  }
441 
442  public function calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $preview_session): float
443  {
444  $solution_data = $preview_session->getParticipantsSolution();
445 
446  $reached_points = $this->calculateReachedPointsForSolution(is_array($solution_data) ? array_values($solution_data) : []);
447 
448  return $this->ensureNonNegativePoints($reached_points);
449  }
450 
459  public function saveWorkingData(
460  int $active_id,
461  ?int $pass = null,
462  bool $authorized = true
463  ): bool {
464  if (is_null($pass)) {
465  $pass = ilObjTest::_getPass($active_id);
466  }
467 
468  $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
469  function () use ($active_id, $pass, $authorized) {
470  if ($authorized) {
471  // remove the dummy record of the intermediate solution
472  $this->deleteDummySolutionRecord($active_id, $pass);
473 
474  // delete the authorized solution and make the intermediate solution authorized (keeping timestamps)
475  $this->removeCurrentSolution($active_id, $pass, true);
476  $this->updateCurrentSolutionsAuthorization($active_id, $pass, true, true);
477  return;
478  }
479 
480  $this->forceExistingIntermediateSolution(
481  $active_id,
482  $pass,
483  $this->is_multiple_choice
484  );
485 
486  if ($this->isReuseSolutionSelectionRequest()) {
487  $selection = $this->getReuseSolutionSelectionParameter();
488 
489  foreach ($selection as $selectedIndex) {
490  $this->saveCurrentSolution($active_id, $pass, (int) $selectedIndex, null, $authorized);
491  }
492  return;
493  }
494 
495  if ($this->isRemoveSolutionSelectionRequest()) {
496  $selection = $this->getRemoveSolutionSelectionParameter();
497  $this->deleteSolutionRecordByValues($active_id, $pass, $authorized, [
498  'value1' => (int) $selection
499  ]);
500  return;
501  }
502 
503  if (!$this->isAddSolutionSelectionRequest()) {
504  return;
505  }
506  $selection = $this->getAddSolutionSelectionParameter();
507 
508  if ($this->is_multiple_choice) {
509  $this->deleteSolutionRecordByValues($active_id, $pass, $authorized, [
510  'value1' => (int) $this->request->raw('selImage')
511  ]);
512  } else {
513  $this->removeCurrentSolution($active_id, $pass, $authorized);
514  }
515 
516  $this->saveCurrentSolution($active_id, $pass, $this->request->raw('selImage'), null, $authorized);
517  }
518  );
519 
520  return true;
521  }
522 
523  protected function savePreviewData(ilAssQuestionPreviewSession $previewSession): void
524  {
525  $solution = $previewSession->getParticipantsSolution();
526 
527  if ($this->is_multiple_choice
528  && $this->request->isset('remImage')) {
529  unset($solution[$this->request->int('remImage')]);
530  }
531 
532  if ($this->request->isset('selImage')) {
533  if (!$this->is_multiple_choice) {
534  $solution = [];
535  }
536 
537  $solution[$this->request->int('selImage')] = $this->request->int('selImage');
538  }
539 
540  $previewSession->setParticipantsSolution($solution);
541  }
542 
551  public function getQuestionType(): string
552  {
553  return 'assImagemapQuestion';
554  }
555 
564  public function getAdditionalTableName(): string
565  {
566  return 'qpl_qst_imagemap';
567  }
568 
577  public function getAnswerTableName(): string
578  {
579  return 'qpl_a_imagemap';
580  }
581 
586  public function getRTETextWithMediaObjects(): string
587  {
588  $text = parent::getRTETextWithMediaObjects();
589  foreach ($this->answers as $index => $answer) {
590  $text .= $this->feedbackOBJ->getSpecificAnswerFeedbackContent($this->getId(), 0, $index);
591  }
592  return $text;
593  }
594 
598  public function deleteImage(): void
599  {
600  $file = $this->getImagePath() . $this->getImageFilename();
601  @unlink($file);
602  $this->flushAnswers();
603  $this->image_filename = '';
604  }
605 
609  public function toJSON(): string
610  {
611  $result = [];
612  $result['id'] = $this->getId();
613  $result['type'] = (string) $this->getQuestionType();
614  $result['title'] = $this->getTitleForHTMLOutput();
615  $result['question'] = $this->formatSAQuestion($this->getQuestion());
616  $result['nr_of_tries'] = $this->getNrOfTries();
617  $result['shuffle'] = $this->getShuffle();
618  $result['is_multiple'] = $this->getIsMultipleChoice();
619  $result['feedback'] = [
620  'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
621  'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
622  ];
623  $result['image'] = $this->getImagePathWeb() . $this->getImageFilename();
624 
625  $answers = [];
626  $order = 0;
627  foreach ($this->getAnswers() as $key => $answer_obj) {
628  array_push($answers, [
629  'answertext' => (string) $answer_obj->getAnswertext(),
630  'points' => (float) $answer_obj->getPoints(),
631  'points_unchecked' => (float) $answer_obj->getPointsUnchecked(),
632  'order' => $order,
633  'coords' => $answer_obj->getCoords(),
634  'state' => $answer_obj->getState(),
635  'area' => $answer_obj->getArea(),
636  'feedback' => $this->formatSAQuestion(
637  $this->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation($this->getId(), 0, $key)
638  )
639  ]);
640  $order++;
641  }
642  $result['answers'] = $answers;
643 
644  $mobs = ilObjMediaObject::_getMobsOfObject('qpl:html', $this->getId());
645  $result['mobs'] = $mobs;
646 
647  return json_encode($result);
648  }
649 
650  protected function calculateReachedPointsForSolution(?array $found_values): float
651  {
652  if ($found_values === null) {
653  $found_values = [];
654  }
655  $points = 0;
656  if (count($found_values) > 0) {
657  foreach ($this->answers as $key => $answer) {
658  if (in_array($key, $found_values)) {
659  $points += $answer->getPoints();
660  } elseif ($this->getIsMultipleChoice()) {
661  $points += $answer->getPointsUnchecked();
662  }
663  }
664  return $points;
665  }
666  return $points;
667  }
668 
669  public function getOperators(string $expression): array
670  {
671  return ilOperatorsExpressionMapping::getOperatorsByExpression($expression);
672  }
673 
674  public function getExpressionTypes(): array
675  {
676  return [
677  iQuestionCondition::PercentageResultExpression,
678  iQuestionCondition::NumberOfResultExpression,
679  iQuestionCondition::EmptyAnswerExpression,
680  iQuestionCondition::ExclusiveResultExpression
681  ];
682  }
683 
684  public function getUserQuestionResult(
685  int $active_id,
686  int $pass
687  ): ilUserQuestionResult {
688  $result = new ilUserQuestionResult($this, $active_id, $pass);
689 
690  $maxStep = $this->lookupMaxStep($active_id, $pass);
691  if ($maxStep > 0) {
692  $data = $this->db->queryF(
693  'SELECT value1+1 as value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s',
694  ['integer', 'integer', 'integer', 'integer'],
695  [$active_id, $pass, $this->getId(), $maxStep]
696  );
697  } else {
698  $data = $this->db->queryF(
699  'SELECT value1+1 as value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step IS NULL',
700  ['integer', 'integer', 'integer'],
701  [$active_id, $pass, $this->getId()]
702  );
703  }
704 
705  while ($row = $this->db->fetchAssoc($data)) {
706  $result->addKeyValue($row['value1'], $row['value1']);
707  }
708 
709  $points = $this->calculateReachedPoints($active_id, $pass);
710  $max_points = $this->getMaximumPoints();
711 
712  $result->setReachedPercentage(($points / $max_points) * 100);
713 
714  return $result;
715  }
716 
724  public function getAvailableAnswerOptions($index = null)
725  {
726  if ($index !== null) {
727  return $this->getAnswer($index);
728  } else {
729  return $this->getAnswers();
730  }
731  }
732 
733  public function getTestOutputSolutions($activeId, $pass): array
734  {
735  $solution = parent::getTestOutputSolutions($activeId, $pass);
736 
737  $this->currentSolution = [];
738  foreach ($solution as $record) {
739  $this->currentSolution[] = $record['value1'];
740  }
741 
742  return $solution;
743  }
744  protected function getAddSolutionSelectionParameter()
745  {
746  if (!$this->isAddSolutionSelectionRequest()) {
747  return null;
748  }
749 
750  return $this->request->raw('selImage');
751  }
752  protected function isAddSolutionSelectionRequest(): bool
753  {
754  if (!$this->request->isset('selImage')) {
755  return false;
756  }
757 
758  if (!strlen($this->request->raw('selImage'))) {
759  return false;
760  }
761 
762  return true;
763  }
764  protected function getRemoveSolutionSelectionParameter()
765  {
766  if (!$this->isRemoveSolutionSelectionRequest()) {
767  return null;
768  }
769 
770  return $this->request->raw('remImage');
771  }
772  protected function isRemoveSolutionSelectionRequest(): bool
773  {
774  if (!$this->is_multiple_choice) {
775  return false;
776  }
777 
778  if (!$this->request->isset('remImage')) {
779  return false;
780  }
781 
782  if (!strlen($this->request->raw('remImage'))) {
783  return false;
784  }
785 
786  return true;
787  }
788  protected function getReuseSolutionSelectionParameter(): ?array
789  {
790  if (!$this->isReuseSolutionSelectionRequest()) {
791  return null;
792  }
793 
794  return assQuestion::explodeKeyValues($this->request->raw('reuseSelection'));
795  }
796  protected function isReuseSolutionSelectionRequest(): bool
797  {
798  if (!$this->getTestPresentationConfig()->isPreviousPassSolutionReuseAllowed()) {
799  return false;
800  }
801 
802  if (!$this->request->isset('reuseSelection')) {
803  return false;
804  }
805 
806  if (!strlen($this->request->raw('reuseSelection'))) {
807  return false;
808  }
809 
810  if (!preg_match('/\d(,\d)*/', $this->request->raw('reuseSelection'))) {
811  return false;
812  }
813 
814  return true;
815  }
816 
817  public function toLog(AdditionalInformationGenerator $additional_info): array
818  {
819  $result = [
820  AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->getQuestionType(),
821  AdditionalInformationGenerator::KEY_QUESTION_TITLE => $this->getTitleForHTMLOutput(),
822  AdditionalInformationGenerator::KEY_QUESTION_TEXT => $this->formatSAQuestion($this->getQuestion()),
823  AdditionalInformationGenerator::KEY_QUESTION_SHUFFLE_ANSWER_OPTIONS => $additional_info
824  ->getTrueFalseTagForBool($this->getShuffle()),
825  AdditionalInformationGenerator::KEY_QUESTION_IMAGEMAP_MODE => $this->getIsMultipleChoice()
826  ? $additional_info->getTagForLangVar('tst_imap_qst_mode_mc')
827  : $additional_info->getTagForLangVar('tst_imap_qst_mode_sc'),
828  AdditionalInformationGenerator::KEY_QUESTION_IMAGEMAP_IMAGE => $this->getImagePathWeb() . $this->getImageFilename(),
829  AdditionalInformationGenerator::KEY_FEEDBACK => [
830  AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->formatSAQuestion(
831  $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)
832  ),
833  AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->formatSAQuestion(
834  $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true)
835  )
836  ]
837  ];
838 
839  $answers = [];
840  $order = 0;
841  foreach ($this->getAnswers() as $key => $answer_obj) {
842  array_push($answers, [
843  AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTION => (string) $answer_obj->getAnswertext(),
844  AdditionalInformationGenerator::KEY_QUESTION_POINTS_CHECKED => (float) $answer_obj->getPoints(),
845  AdditionalInformationGenerator::KEY_QUESTION_POINTS_UNCHECKED => (float) $answer_obj->getPointsUnchecked(),
846  AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTION_ORDER => $order,
847  AdditionalInformationGenerator::KEY_QUESTION_IMAGEMAP_ANSWER_OPTION_COORDS => $answer_obj->getCoords(),
848  AdditionalInformationGenerator::KEY_FEEDBACK => $this->formatSAQuestion(
849  $this->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation($this->getId(), 0, $key)
850  )
851  ]);
852  $order++;
853  }
854  $result[AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTIONS] = $answers;
855 
856  return $result;
857  }
858 
859  protected function solutionValuesToLog(
860  AdditionalInformationGenerator $additional_info,
861  array $solution_values
862  ): array {
863  $parsed_solution = [];
864  foreach ($this->getAnswers() as $id => $answer) {
865  $value = $additional_info->getTagForLangVar('unchecked');
866  foreach ($solution_values as $solution) {
867  if ($solution['value1'] == $id) {
868  $value = $additional_info->getTagForLangVar('checked');
869  break;
870  }
871  }
872  $parsed_solution["{$answer->getArea()}: {$answer->getCoords()}"] = $value;
873  }
874  return $parsed_solution;
875  }
876 
877  public function solutionValuesToText(array $solution_values): array
878  {
879  $parsed_solution = [];
880  foreach ($this->getAnswers() as $id => $answer) {
881  $value = $this->lng->txt('unchecked');
882  foreach ($solution_values as $solution) {
883  if ($solution['value1'] == $id) {
884  $value = $this->lng->txt('checked');
885  break;
886  }
887  }
888  $parsed_solution[] = "{$answer->getArea()}: {$answer->getCoords()} ({$value})";
889  }
890  return $parsed_solution;
891  }
892 
893  public function getCorrectSolutionForTextOutput(int $active_id, int $pass): array
894  {
895  return array_map(
896  fn(ASS_AnswerImagemap $v): string => "{$v->getArea()}: {$v->getCoords()}"
897  . "({$this->lng->txt('points')} "
898  . "{$this->lng->txt('checked')}: {$v->getPoints()}, "
899  . "{$this->lng->txt('unchecked')}: {$v->getPointsUnchecked()})",
900  $this->getAnswers()
901  );
902  }
903 }
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
setNrOfTries(int $a_nr_of_tries)
get_imagemap_contents(string $href='#')
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...
removeAllImageFiles(string $image_target_path)
setOwner(int $owner=-1)
addAnswer(string $answertext='', float $points=0.0, int $order=0, string $coords='', string $area='', float $points_unchecked=0.0)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
unchecked()
description: > Example for rendering a Unchecked Glyph.
Definition: unchecked.php:25
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
setComment(string $comment="")
getIsMultipleChoice()
Returns true, if the imagemap question is a multiplechoice question.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
checked()
description: > Example for rendering a Checked Glyph.
Definition: checked.php:25
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class for image map questions.
__construct( $title='', $comment='', $author='', $owner=-1, $question='', $image_filename='')
assImagemapQuestion constructor
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
setPoints(float $points)
setObjId(int $obj_id=0)
saveQuestionDataToDb(?int $original_id=null)
RequestDataCollector $request
saveToDb(?int $original_id=null)
cloneQuestionTypeSpecificProperties(\assQuestion $target)
setIsMultipleChoice($is_multiple_choice)
Set true if the Imagemapquestion is a multiplechoice Question.
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
setImageFilename(string $image_filename, string $image_tempfilename='')
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setId(int $id=-1)
__construct(Container $dic, ilPlugin $plugin)
setOriginalId(?int $original_id)
setTitle(string $title="")
setLifecycle(ilAssQuestionLifecycle $lifecycle)
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
setAuthor(string $author="")
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
copyImagemapFiles(int $source_question_id, int $source_parent_id, int $target_question_id, int $target_parent_id)
setQuestion(string $question="")