ILIAS  trunk Revision v12.0_alpha-1227-g7ff6d300864
class.assImagemapQuestion.php
Go to the documentation of this file.
1<?php
2
19declare(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 = '',
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 if (!file_exists($image_source_path) || !is_readable($image_source_path)) {
209 $this->log->root()->alert(
210 "Could not copy imagemap question files: Source path '{$image_source_path}' does not exist or is not readable.",
211 [
212 'source_question_id' => $source_question_id,
213 'source_parent_id' => $source_parent_id,
214 'target_question_id' => $target_question_id,
215 'target_parent_id' => $target_parent_id,
216 'image_source_path' => $image_source_path,
217 'image_target_path' => $image_target_path
218 ]
219 );
220 return;
221 }
222
223 $src = opendir($image_source_path);
224 while ($src_file = readdir($src)) {
225 if ($src_file === '.' || $src_file === '..') {
226 continue;
227 }
228 copy(
229 $image_source_path . DIRECTORY_SEPARATOR . $src_file,
230 $image_target_path . DIRECTORY_SEPARATOR . $src_file
231 );
232 }
233 }
234
235 public function loadFromDb(int $question_id): void
236 {
237 $result = $this->db->queryF(
238 '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',
239 ['integer'],
240 [$question_id]
241 );
242 if ($result->numRows() == 1) {
243 $data = $this->db->fetchAssoc($result);
244 $this->setId($question_id);
245 $this->setObjId($data['obj_fi']);
246 $this->setTitle((string) $data['title']);
247 $this->setComment((string) $data['description']);
248 $this->setOriginalId($data['original_id']);
249 $this->setNrOfTries($data['nr_of_tries']);
250 $this->setAuthor($data['author']);
251 $this->setPoints($data['points']);
252 $this->setOwner($data['owner']);
253 $this->setIsMultipleChoice($data['is_multiple_choice'] == self::MODE_MULTIPLE_CHOICE);
254 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data['question_text'], 1));
255 $this->setImageFilename($data['image_file'] ?? '');
256
257 try {
258 $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
260 $this->setLifecycle(ilAssQuestionLifecycle::getDraftInstance());
261 }
262
263 try {
264 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
266 }
267
268 $result = $this->db->queryF(
269 'SELECT * FROM qpl_a_imagemap WHERE question_fi = %s ORDER BY aorder ASC',
270 ['integer'],
271 [$question_id]
272 );
273 if ($result->numRows() > 0) {
274 while ($data = $this->db->fetchAssoc($result)) {
275 $image_map_question = new ASS_AnswerImagemap($data['answertext'] ?? '', $data['points'], $data['aorder']);
276 $image_map_question->setCoords($data['coords']);
277 $image_map_question->setArea($data['area']);
278 $image_map_question->setPointsUnchecked($data['points_unchecked']);
279 array_push($this->answers, $image_map_question);
280 }
281 }
282 }
283 parent::loadFromDb($question_id);
284 }
285
286 public function uploadImagemap(array $shapes): int
287 {
288 $added = 0;
289
290 if (count($shapes) > 0) {
291 foreach ($shapes as $shape) {
292 $this->addAnswer($shape->getAnswertext(), 0.0, count($this->answers), $shape->getCoords(), $shape->getArea());
293 $added++;
294 }
295 }
296
297 return $added;
298 }
299
300 public function getImageFilename(): string
301 {
302 return $this->image_filename;
303 }
304
305 public function setImageFilename(
306 string $image_filename,
307 string $image_tempfilename = ''
308 ): void {
309 if (!empty($image_filename)) {
310 $image_filename = str_replace(' ', '_', $image_filename);
311 $this->image_filename = $image_filename;
312 }
313 if (!empty($image_tempfilename)) {
314 $imagepath = $this->getImagePath();
315 if (!file_exists($imagepath)) {
316 ilFileUtils::makeDirParents($imagepath);
317 }
318 if (!ilFileUtils::moveUploadedFile($image_tempfilename, $image_filename, $imagepath . $image_filename)) {
319 $this->tpl->setOnScreenMessage('failure', 'The image could not be uploaded!');
320 return;
321 }
322 $this->log->write('gespeichert: ' . $imagepath . $image_filename);
323 }
324 }
325
326 public function get_imagemap_contents(string $href = '#'): string
327 {
328 $imagemap_contents = '<map name=\'' . $this->title . '\'> ';
329 for ($i = 0; $i < count($this->answers); $i++) {
330 $imagemap_contents .= '<area alt=\'' . $this->answers[$i]->getAnswertext() . '\' ';
331 $imagemap_contents .= 'shape=\'' . $this->answers[$i]->getArea() . '\' ';
332 $imagemap_contents .= 'coords=\'' . $this->answers[$i]->getCoords() . '\' ';
333 $imagemap_contents .= "href=\"{$href}&selimage=" . $this->answers[$i]->getOrder() . "\" /> ";
334 }
335 $imagemap_contents .= '</map>';
336 return $imagemap_contents;
337 }
338
339 public function addAnswer(
340 string $answertext = '',
341 float $points = 0.0,
342 int $order = 0,
343 string $coords = '',
344 string $area = '',
345 float $points_unchecked = 0.0
346 ): void {
347 if (array_key_exists($order, $this->answers)) {
348 // Insert answer
349 $answer = new ASS_AnswerImagemap($answertext, $points, $order, 0, -1);
350 $answer->setCoords($coords);
351 $answer->setArea($area);
352 $answer->setPointsUnchecked($points_unchecked);
353 for ($i = count($this->answers) - 1; $i >= $order; $i--) {
354 $this->answers[$i + 1] = $this->answers[$i];
355 $this->answers[$i + 1]->setOrder($i + 1);
356 }
357 $this->answers[$order] = $answer;
358 } else {
359 // Append answer
360 $answer = new ASS_AnswerImagemap($answertext, $points, count($this->answers), 0, -1);
361 $answer->setCoords($coords);
362 $answer->setArea($area);
363 $answer->setPointsUnchecked($points_unchecked);
364 array_push($this->answers, $answer);
365 }
366 }
367
368 public function getAnswerCount(): int
369 {
370 return count($this->answers);
371 }
372
373 public function getAnswer(int $index = 0): ?ASS_AnswerImagemap
374 {
375 if ($index < 0) {
376 return null;
377 }
378 if (count($this->answers) < 1) {
379 return null;
380 }
381 if ($index >= count($this->answers)) {
382 return null;
383 }
384 return $this->answers[$index];
385 }
386
387 public function &getAnswers(): array
388 {
389 return $this->answers;
390 }
391
392 public function deleteArea(int $index = 0): void
393 {
394 if ($index < 0) {
395 return;
396 }
397 if (count($this->answers) < 1) {
398 return;
399 }
400 if ($index >= count($this->answers)) {
401 return;
402 }
403 unset($this->answers[$index]);
404 $this->answers = array_values($this->answers);
405 for ($i = 0; $i < count($this->answers); $i++) {
406 if ($this->answers[$i]->getOrder() > $index) {
407 $this->answers[$i]->setOrder($i);
408 }
409 }
410 }
411
412 public function flushAnswers(): void
413 {
414 $this->answers = [];
415 }
416
417 public function getMaximumPoints(): float
418 {
419 $points = 0;
420 foreach ($this->answers as $key => $value) {
421 if ($this->is_multiple_choice) {
422 if ($value->getPoints() > $value->getPointsUnchecked()) {
423 $points += $value->getPoints();
424 } else {
425 $points += $value->getPointsUnchecked();
426 }
427 } else {
428 if ($value->getPoints() > $points) {
429 $points = $value->getPoints();
430 }
431 }
432 }
433 return $points;
434 }
435
436 public function calculateReachedPoints(
437 int $active_id,
438 ?int $pass = null,
439 bool $authorized_solution = true
440 ): float {
441 if ($pass === null) {
442 $pass = $this->getSolutionMaxPass($active_id);
443 }
444 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorized_solution);
445 $found_values = [];
446 while ($data = $this->db->fetchAssoc($result)) {
447 if ($data['value1'] !== '') {
448 $found_values[] = $data['value1'];
449 }
450 }
451
452 $points = $this->calculateReachedPointsForSolution($found_values);
453
454 return $points;
455 }
456
457 public function calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $preview_session): float
458 {
459 $solution_data = $preview_session->getParticipantsSolution();
460
461 $reached_points = $this->calculateReachedPointsForSolution(is_array($solution_data) ? array_values($solution_data) : []);
462
463 return $this->ensureNonNegativePoints($reached_points);
464 }
465
474 public function saveWorkingData(
475 int $active_id,
476 ?int $pass = null,
477 bool $authorized = true
478 ): bool {
479 if (is_null($pass)) {
480 $pass = ilObjTest::_getPass($active_id);
481 }
482
483 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
484 function () use ($active_id, $pass, $authorized) {
485 if ($authorized) {
486 // remove the dummy record of the intermediate solution
487 $this->deleteDummySolutionRecord($active_id, $pass);
488
489 // delete the authorized solution and make the intermediate solution authorized (keeping timestamps)
490 $this->removeCurrentSolution($active_id, $pass, true);
491 $this->updateCurrentSolutionsAuthorization($active_id, $pass, true, true);
492 return;
493 }
494
495 $this->forceExistingIntermediateSolution(
496 $active_id,
497 $pass,
498 $this->is_multiple_choice
499 );
500
501 if ($this->isReuseSolutionSelectionRequest()) {
502 $selection = $this->getReuseSolutionSelectionParameter();
503
504 foreach ($selection as $selectedIndex) {
505 $this->saveCurrentSolution($active_id, $pass, (int) $selectedIndex, null, $authorized);
506 }
507 return;
508 }
509
510 if ($this->isRemoveSolutionSelectionRequest()) {
511 $selection = $this->getRemoveSolutionSelectionParameter();
512 $this->deleteSolutionRecordByValues($active_id, $pass, $authorized, [
513 'value1' => (int) $selection
514 ]);
515 return;
516 }
517
518 if (!$this->isAddSolutionSelectionRequest()) {
519 return;
520 }
521 $selection = $this->getAddSolutionSelectionParameter();
522
523 if ($this->is_multiple_choice) {
524 $this->deleteSolutionRecordByValues($active_id, $pass, $authorized, [
525 'value1' => (int) $this->request->raw('selImage')
526 ]);
527 } else {
528 $this->removeCurrentSolution($active_id, $pass, $authorized);
529 }
530
531 $this->saveCurrentSolution($active_id, $pass, $this->request->raw('selImage'), null, $authorized);
532 }
533 );
534
535 return true;
536 }
537
538 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession): void
539 {
540 $solution = $previewSession->getParticipantsSolution();
541
542 if ($this->is_multiple_choice
543 && $this->request->isset('remImage')) {
544 unset($solution[$this->request->int('remImage')]);
545 }
546
547 if ($this->request->isset('selImage')) {
548 if (!$this->is_multiple_choice) {
549 $solution = [];
550 }
551
552 $solution[$this->request->int('selImage')] = $this->request->int('selImage');
553 }
554
555 $previewSession->setParticipantsSolution($solution);
556 }
557
566 public function getQuestionType(): string
567 {
568 return 'assImagemapQuestion';
569 }
570
579 public function getAdditionalTableName(): string
580 {
581 return 'qpl_qst_imagemap';
582 }
583
592 public function getAnswerTableName(): string
593 {
594 return 'qpl_a_imagemap';
595 }
596
601 public function getRTETextWithMediaObjects(): string
602 {
603 $text = parent::getRTETextWithMediaObjects();
604 foreach ($this->answers as $index => $answer) {
605 $text .= $this->feedbackOBJ->getSpecificAnswerFeedbackContent($this->getId(), 0, $index);
606 }
607 return $text;
608 }
609
613 public function deleteImage(): void
614 {
615 $file = $this->getImagePath() . $this->getImageFilename();
616 @unlink($file);
617 $this->flushAnswers();
618 $this->image_filename = '';
619 }
620
624 public function toJSON(): string
625 {
626 $result = [];
627 $result['id'] = $this->getId();
628 $result['type'] = (string) $this->getQuestionType();
629 $result['title'] = $this->getTitleForHTMLOutput();
630 $result['question'] = $this->formatSAQuestion($this->getQuestion());
631 $result['nr_of_tries'] = $this->getNrOfTries();
632 $result['shuffle'] = $this->getShuffle();
633 $result['is_multiple'] = $this->getIsMultipleChoice();
634 $result['feedback'] = [
635 'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
636 'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
637 ];
638 $result['image'] = $this->getImagePathWeb() . $this->getImageFilename();
639
640 $answers = [];
641 $order = 0;
642 foreach ($this->getAnswers() as $key => $answer_obj) {
643 array_push($answers, [
644 'answertext' => (string) $answer_obj->getAnswertext(),
645 'points' => (float) $answer_obj->getPoints(),
646 'points_unchecked' => (float) $answer_obj->getPointsUnchecked(),
647 'order' => $order,
648 'coords' => $answer_obj->getCoords(),
649 'state' => $answer_obj->getState(),
650 'area' => $answer_obj->getArea(),
651 'feedback' => $this->formatSAQuestion(
652 $this->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation($this->getId(), 0, $key)
653 )
654 ]);
655 $order++;
656 }
657 $result['answers'] = $answers;
658
659 $mobs = ilObjMediaObject::_getMobsOfObject('qpl:html', $this->getId());
660 $result['mobs'] = $mobs;
661
662 return json_encode($result);
663 }
664
665 protected function calculateReachedPointsForSolution(?array $found_values): float
666 {
667 if ($found_values === null) {
668 $found_values = [];
669 }
670 $points = 0;
671 if (count($found_values) > 0) {
672 foreach ($this->answers as $key => $answer) {
673 if (in_array($key, $found_values)) {
674 $points += $answer->getPoints();
675 } elseif ($this->getIsMultipleChoice()) {
676 $points += $answer->getPointsUnchecked();
677 }
678 }
679 return $points;
680 }
681 return $points;
682 }
683
684 public function getOperators(string $expression): array
685 {
686 return ilOperatorsExpressionMapping::getOperatorsByExpression($expression);
687 }
688
689 public function getExpressionTypes(): array
690 {
691 return [
692 iQuestionCondition::PercentageResultExpression,
693 iQuestionCondition::NumberOfResultExpression,
694 iQuestionCondition::EmptyAnswerExpression,
695 iQuestionCondition::ExclusiveResultExpression
696 ];
697 }
698
699 public function getUserQuestionResult(
700 int $active_id,
701 int $pass
702 ): ilUserQuestionResult {
703 $result = new ilUserQuestionResult($this, $active_id, $pass);
704
705 $maxStep = $this->lookupMaxStep($active_id, $pass);
706 if ($maxStep > 0) {
707 $data = $this->db->queryF(
708 'SELECT value1+1 as value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s',
709 ['integer', 'integer', 'integer', 'integer'],
710 [$active_id, $pass, $this->getId(), $maxStep]
711 );
712 } else {
713 $data = $this->db->queryF(
714 'SELECT value1+1 as value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step IS NULL',
715 ['integer', 'integer', 'integer'],
716 [$active_id, $pass, $this->getId()]
717 );
718 }
719
720 while ($row = $this->db->fetchAssoc($data)) {
721 $result->addKeyValue($row['value1'], $row['value1']);
722 }
723
724 $points = $this->calculateReachedPoints($active_id, $pass);
725 $max_points = $this->getMaximumPoints();
726
727 $result->setReachedPercentage(($points / $max_points) * 100);
728
729 return $result;
730 }
731
739 public function getAvailableAnswerOptions($index = null)
740 {
741 if ($index !== null) {
742 return $this->getAnswer($index);
743 } else {
744 return $this->getAnswers();
745 }
746 }
747
748 public function getTestOutputSolutions($activeId, $pass): array
749 {
750 $solution = parent::getTestOutputSolutions($activeId, $pass);
751
752 $this->currentSolution = [];
753 foreach ($solution as $record) {
754 $this->currentSolution[] = $record['value1'];
755 }
756
757 return $solution;
758 }
759 protected function getAddSolutionSelectionParameter()
760 {
761 if (!$this->isAddSolutionSelectionRequest()) {
762 return null;
763 }
764
765 return $this->request->raw('selImage');
766 }
767 protected function isAddSolutionSelectionRequest(): bool
768 {
769 if (!$this->request->isset('selImage')) {
770 return false;
771 }
772
773 if (!strlen($this->request->raw('selImage'))) {
774 return false;
775 }
776
777 return true;
778 }
779 protected function getRemoveSolutionSelectionParameter()
780 {
781 if (!$this->isRemoveSolutionSelectionRequest()) {
782 return null;
783 }
784
785 return $this->request->raw('remImage');
786 }
787 protected function isRemoveSolutionSelectionRequest(): bool
788 {
789 if (!$this->is_multiple_choice) {
790 return false;
791 }
792
793 if (!$this->request->isset('remImage')) {
794 return false;
795 }
796
797 if (!strlen($this->request->raw('remImage'))) {
798 return false;
799 }
800
801 return true;
802 }
803 protected function getReuseSolutionSelectionParameter(): ?array
804 {
805 if (!$this->isReuseSolutionSelectionRequest()) {
806 return null;
807 }
808
809 return assQuestion::explodeKeyValues($this->request->raw('reuseSelection'));
810 }
811 protected function isReuseSolutionSelectionRequest(): bool
812 {
813 if (!$this->getTestPresentationConfig()->isPreviousPassSolutionReuseAllowed()) {
814 return false;
815 }
816
817 if (!$this->request->isset('reuseSelection')) {
818 return false;
819 }
820
821 if (!strlen($this->request->raw('reuseSelection'))) {
822 return false;
823 }
824
825 if (!preg_match('/\d(,\d)*/', $this->request->raw('reuseSelection'))) {
826 return false;
827 }
828
829 return true;
830 }
831
832 public function toLog(AdditionalInformationGenerator $additional_info): array
833 {
834 $result = [
835 AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->getQuestionType(),
836 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $this->getTitleForHTMLOutput(),
837 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $this->formatSAQuestion($this->getQuestion()),
838 AdditionalInformationGenerator::KEY_QUESTION_SHUFFLE_ANSWER_OPTIONS => $additional_info
839 ->getTrueFalseTagForBool($this->getShuffle()),
840 AdditionalInformationGenerator::KEY_QUESTION_IMAGEMAP_MODE => $this->getIsMultipleChoice()
841 ? $additional_info->getTagForLangVar('tst_imap_qst_mode_mc')
842 : $additional_info->getTagForLangVar('tst_imap_qst_mode_sc'),
843 AdditionalInformationGenerator::KEY_QUESTION_IMAGEMAP_IMAGE => $this->getImagePathWeb() . $this->getImageFilename(),
844 AdditionalInformationGenerator::KEY_FEEDBACK => [
845 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->formatSAQuestion(
846 $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)
847 ),
848 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->formatSAQuestion(
849 $this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true)
850 )
851 ]
852 ];
853
854 $answers = [];
855 $order = 0;
856 foreach ($this->getAnswers() as $key => $answer_obj) {
857 array_push($answers, [
858 AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTION => (string) $answer_obj->getAnswertext(),
859 AdditionalInformationGenerator::KEY_QUESTION_POINTS_CHECKED => (float) $answer_obj->getPoints(),
860 AdditionalInformationGenerator::KEY_QUESTION_POINTS_UNCHECKED => (float) $answer_obj->getPointsUnchecked(),
861 AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTION_ORDER => $order,
862 AdditionalInformationGenerator::KEY_QUESTION_IMAGEMAP_ANSWER_OPTION_COORDS => $answer_obj->getCoords(),
863 AdditionalInformationGenerator::KEY_FEEDBACK => $this->formatSAQuestion(
864 $this->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation($this->getId(), 0, $key)
865 )
866 ]);
867 $order++;
868 }
869 $result[AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTIONS] = $answers;
870
871 return $result;
872 }
873
874 protected function solutionValuesToLog(
875 AdditionalInformationGenerator $additional_info,
876 array $solution_values
877 ): array {
878 $parsed_solution = [];
879 foreach ($this->getAnswers() as $id => $answer) {
880 $value = $additional_info->getTagForLangVar('unchecked');
881 foreach ($solution_values as $solution) {
882 if ($solution['value1'] == $id) {
883 $value = $additional_info->getTagForLangVar('checked');
884 break;
885 }
886 }
887 $parsed_solution["{$answer->getArea()}: {$answer->getCoords()}"] = $value;
888 }
889 return $parsed_solution;
890 }
891
892 public function solutionValuesToText(array $solution_values): array
893 {
894 $parsed_solution = [];
895 foreach ($this->getAnswers() as $id => $answer) {
896 $value = $this->lng->txt('unchecked');
897 foreach ($solution_values as $solution) {
898 if ($solution['value1'] == $id) {
899 $value = $this->lng->txt('checked');
900 break;
901 }
902 }
903 $parsed_solution[] = "{$answer->getArea()}: {$answer->getCoords()} ({$value})";
904 }
905 return $parsed_solution;
906 }
907
908 public function getCorrectSolutionForTextOutput(int $active_id, int $pass): array
909 {
910 return array_map(
911 fn(ASS_AnswerImagemap $v): string => "{$v->getArea()}: {$v->getCoords()}"
912 . "({$this->lng->txt('points')} "
913 . "{$this->lng->txt('checked')}: {$v->getPoints()}, "
914 . "{$this->lng->txt('unchecked')}: {$v->getPointsUnchecked()})",
915 $this->getAnswers()
916 );
917 }
918}
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Class for image map questions.
setIsMultipleChoice($is_multiple_choice)
Set true if the Imagemapquestion is a multiplechoice Question.
__construct( $title='', $comment='', $author='', $owner=-1, $question='', $image_filename='')
assImagemapQuestion constructor
RequestDataCollector $request
copyImagemapFiles(int $source_question_id, int $source_parent_id, int $target_question_id, int $target_parent_id)
setImageFilename(string $image_filename, string $image_tempfilename='')
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
saveToDb(?int $original_id=null)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
cloneQuestionTypeSpecificProperties(\assQuestion $target)
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
get_imagemap_contents(string $href='#')
getIsMultipleChoice()
Returns true, if the imagemap question is a multiplechoice question.
saveQuestionDataToDb(?int $original_id=null)
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
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...
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...
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
if(!file_exists('../ilias.ini.php'))