ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.assImagemapQuestion.php
Go to the documentation of this file.
1 <?php
2 
19 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
20 
35 {
36  private \ILIAS\TestQuestionPool\InternalRequestService $request; // Hate it.
37 
38  // hey: prevPassSolutions - wtf is imagemap ^^
39  public $currentSolution = array();
40  // hey.
41 
42  public const MODE_SINGLE_CHOICE = 0;
43  public const MODE_MULTIPLE_CHOICE = 1;
44 
45  public const AVAILABLE_SHAPES = [
46  'RECT' => 'rect',
47  'CIRCLE' => 'circle',
48  'POLY' => 'poly'];
49 
51  public $answers;
52 
55 
58 
60  public $coords;
61 
63  protected $is_multiple_choice = false;
64 
78  public function __construct(
79  $title = "",
80  $comment = "",
81  $author = "",
82  $owner = -1,
83  $question = "",
84  $image_filename = ""
85  ) {
87  $this->image_filename = $image_filename;
88  $this->answers = array();
89  $this->coords = array();
90 
91  global $DIC;
92  $this->request = $DIC->testQuestionPool()->internal()->request();
93  }
94 
101  {
102  $this->is_multiple_choice = $is_multiple_choice;
103  }
104 
110  public function getIsMultipleChoice(): bool
111  {
113  }
114 
121  public function isComplete(): bool
122  {
123  if (strlen($this->title)
124  && ($this->author)
125  && ($this->question)
126  && ($this->image_filename)
127  && (count($this->answers))
128  && ($this->getMaximumPoints() > 0)
129  ) {
130  return true;
131  }
132  return false;
133  }
134 
144  public function saveToDb($original_id = ""): void
145  {
146  if ($original_id == '') {
147  $this->saveQuestionDataToDb();
148  } else {
150  }
153  parent::saveToDb($original_id);
154  }
155 
156  public function saveAnswerSpecificDataToDb()
157  {
158  global $DIC;
159  $ilDB = $DIC['ilDB'];
160  $ilDB->manipulateF(
161  "DELETE FROM qpl_a_imagemap WHERE question_fi = %s",
162  array( "integer" ),
163  array( $this->getId() )
164  );
165 
166  // Anworten wegschreiben
167  foreach ($this->answers as $key => $value) {
168  $answer_obj = $this->answers[$key];
169  $answer_obj->setOrder($key);
170  $next_id = $ilDB->nextId('qpl_a_imagemap');
171  $ilDB->manipulateF(
172  "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)",
173  array( "integer", "integer", "text", "float", "integer", "text", "text", "float" ),
174  array( $next_id, $this->id, $answer_obj->getAnswertext(
175  ), $answer_obj->getPoints(), $answer_obj->getOrder(
176  ), $answer_obj->getCoords(), $answer_obj->getArea(
177  ), $answer_obj->getPointsUnchecked() )
178  );
179  }
180  }
181 
183  {
184  global $DIC;
185  $ilDB = $DIC['ilDB'];
186 
187  $ilDB->manipulateF(
188  "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
189  array( "integer" ),
190  array( $this->getId() )
191  );
192 
193  $ilDB->manipulateF(
194  "INSERT INTO " . $this->getAdditionalTableName(
195  ) . " (question_fi, image_file, is_multiple_choice) VALUES (%s, %s, %s)",
196  array( "integer", "text", 'integer' ),
197  array(
198  $this->getId(),
199  $this->image_filename,
200  (int) $this->is_multiple_choice
201  )
202  );
203  }
204 
210  public function duplicate(bool $for_test = true, string $title = "", string $author = "", int $owner = -1, $testObjId = null): int
211  {
212  if ($this->id <= 0) {
213  // The question has not been saved. It cannot be duplicated
214  return -1;
215  }
216  // duplicate the question in database
217  $this_id = $this->getId();
218  $thisObjId = $this->getObjId();
219 
220  $clone = $this;
221  $original_id = $this->questioninfo->getOriginalId($this->id);
222  $clone->id = -1;
223 
224  if ((int) $testObjId > 0) {
225  $clone->setObjId($testObjId);
226  }
227 
228  if ($title) {
229  $clone->setTitle($title);
230  }
231  if ($author) {
232  $clone->setAuthor($author);
233  }
234  if ($owner) {
235  $clone->setOwner($owner);
236  }
237  if ($for_test) {
238  $clone->saveToDb($original_id);
239  } else {
240  $clone->saveToDb();
241  }
242 
243  // copy question page content
244  $clone->copyPageOfQuestion($this_id);
245  // copy XHTML media objects
246  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
247  // duplicate the image
248  $clone->duplicateImage($this_id, $thisObjId);
249 
250  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
251 
252  return $clone->id;
253  }
254 
262  public function copyObject($target_questionpool_id, $title = ""): int
263  {
264  if ($this->getId() <= 0) {
265  throw new RuntimeException('The question has not been saved. It cannot be duplicated');
266  }
267  // duplicate the question in database
268  $clone = $this;
269 
270  $original_id = $this->questioninfo->getOriginalId($this->id);
271  $clone->id = -1;
272  $source_questionpool_id = $this->getObjId();
273  $clone->setObjId($target_questionpool_id);
274  if ($title) {
275  $clone->setTitle($title);
276  }
277  $clone->saveToDb();
278 
279  // copy question page content
280  $clone->copyPageOfQuestion($original_id);
281  // copy XHTML media objects
282  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
283  // duplicate the image
284  $clone->copyImage($original_id, $source_questionpool_id);
285 
286  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
287 
288  return $clone->id;
289  }
290 
291  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = ""): int
292  {
293  if ($this->getId() <= 0) {
294  throw new RuntimeException('The question has not been saved. It cannot be duplicated');
295  }
296 
297  $sourceQuestionId = $this->id;
298  $sourceParentId = $this->getObjId();
299 
300  // duplicate the question in database
301  $clone = $this;
302  $clone->id = -1;
303 
304  $clone->setObjId($targetParentId);
305 
306  if ($targetQuestionTitle) {
307  $clone->setTitle($targetQuestionTitle);
308  }
309 
310  $clone->saveToDb();
311  // copy question page content
312  $clone->copyPageOfQuestion($sourceQuestionId);
313  // copy XHTML media objects
314  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
315  // duplicate the image
316  $clone->copyImage($sourceQuestionId, $sourceParentId);
317 
318  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
319 
320  return $clone->id;
321  }
322 
323  public function duplicateImage($question_id, $objectId = null): void
324  {
325  global $DIC;
326  $ilLog = $DIC['ilLog'];
327 
328  $imagepath = $this->getImagePath();
329  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
330 
331  if ((int) $objectId > 0) {
332  $imagepath_original = str_replace("/$this->obj_id/", "/$objectId/", $imagepath_original);
333  }
334 
335  if (!file_exists($imagepath)) {
336  ilFileUtils::makeDirParents($imagepath);
337  }
338  $filename = $this->getImageFilename();
339 
340  // #18755
341  if (!file_exists($imagepath_original . $filename)) {
342  $ilLog->write("Could not find an image map file when trying to duplicate image: " . $imagepath_original . $filename);
343  $imagepath_original = str_replace("/$this->obj_id/", "/$objectId/", $imagepath_original);
344  $ilLog->write("Using fallback source directory:" . $imagepath_original);
345  }
346 
347  if (!file_exists($imagepath_original . $filename) || !copy($imagepath_original . $filename, $imagepath . $filename)) {
348  $ilLog->write("Could not duplicate image for image map question: " . $imagepath_original . $filename);
349  }
350  }
351 
352  public function copyImage($question_id, $source_questionpool): void
353  {
354  $imagepath = $this->getImagePath();
355  $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
356  $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
357  if (!file_exists($imagepath)) {
358  ilFileUtils::makeDirParents($imagepath);
359  }
360  $filename = $this->getImageFilename();
361  if (!copy($imagepath_original . $filename, $imagepath . $filename)) {
362  print "image could not be copied!!!! ";
363  }
364  }
365 
375  public function loadFromDb($question_id): void
376  {
377  global $DIC;
378  $ilDB = $DIC['ilDB'];
379 
380  $result = $ilDB->queryF(
381  "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",
382  array("integer"),
383  array($question_id)
384  );
385  if ($result->numRows() == 1) {
386  $data = $ilDB->fetchAssoc($result);
387  $this->setId($question_id);
388  $this->setObjId($data["obj_fi"]);
389  $this->setTitle((string) $data["title"]);
390  $this->setComment((string) $data["description"]);
391  $this->setOriginalId($data["original_id"]);
392  $this->setNrOfTries($data['nr_of_tries']);
393  $this->setAuthor($data["author"]);
394  $this->setPoints($data["points"]);
395  $this->setOwner($data["owner"]);
396  $this->setIsMultipleChoice($data["is_multiple_choice"] == self::MODE_MULTIPLE_CHOICE);
397  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data["question_text"], 1));
398  $this->setImageFilename($data["image_file"]);
399 
400  try {
401  $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
404  }
405 
406  try {
407  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
408  } catch (ilTestQuestionPoolException $e) {
409  }
410 
411  $result = $ilDB->queryF(
412  "SELECT * FROM qpl_a_imagemap WHERE question_fi = %s ORDER BY aorder ASC",
413  array("integer"),
414  array($question_id)
415  );
416  if ($result->numRows() > 0) {
417  while ($data = $ilDB->fetchAssoc($result)) {
418  $image_map_question = new ASS_AnswerImagemap($data["answertext"] ?? '', $data["points"], $data["aorder"]);
419  $image_map_question->setCoords($data["coords"]);
420  $image_map_question->setArea($data["area"]);
421  $image_map_question->setPointsUnchecked($data['points_unchecked']);
422  array_push($this->answers, $image_map_question);
423  }
424  }
425  }
426  parent::loadFromDb($question_id);
427  }
428 
435  public function uploadImagemap(array $shapes): int
436  {
437  $added = 0;
438 
439  if (count($shapes) > 0) {
440  foreach ($shapes as $shape) {
441  $this->addAnswer($shape->getAnswertext(), 0.0, count($this->answers), $shape->getCoords(), $shape->getArea());
442  $added++;
443  }
444  }
445 
446  return $added;
447  }
448 
449  public function getImageFilename(): string
450  {
451  return $this->image_filename;
452  }
453 
461  public function setImageFilename($image_filename, $image_tempfilename = ""): void
462  {
463  if (!empty($image_filename)) {
464  $image_filename = str_replace(" ", "_", $image_filename);
465  $this->image_filename = $image_filename;
466  }
467  if (!empty($image_tempfilename)) {
468  $imagepath = $this->getImagePath();
469  if (!file_exists($imagepath)) {
470  ilFileUtils::makeDirParents($imagepath);
471  }
472  if (!ilFileUtils::moveUploadedFile($image_tempfilename, $image_filename, $imagepath . $image_filename)) {
473  $this->tpl->setOnScreenMessage('failure', 'The image could not be uploaded!');
474  return;
475  }
476  global $DIC;
477  $ilLog = $DIC['ilLog'];
478  $ilLog->write("gespeichert: " . $imagepath . $image_filename);
479  }
480  }
481 
491  public function get_imagemap_contents($href = "#"): string
492  {
493  $imagemap_contents = "<map name=\"" . $this->title . "\"> ";
494  for ($i = 0; $i < count($this->answers); $i++) {
495  $imagemap_contents .= "<area alt=\"" . $this->answers[$i]->getAnswertext() . "\" ";
496  $imagemap_contents .= "shape=\"" . $this->answers[$i]->getArea() . "\" ";
497  $imagemap_contents .= "coords=\"" . $this->answers[$i]->getCoords() . "\" ";
498  $imagemap_contents .= "href=\"$href&selimage=" . $this->answers[$i]->getOrder() . "\" /> ";
499  }
500  $imagemap_contents .= "</map>";
501  return $imagemap_contents;
502  }
503 
518  public function addAnswer(
519  $answertext = "",
520  $points = 0.0,
521  $order = 0,
522  $coords = "",
523  $area = "",
524  $points_unchecked = 0.0
525  ): void {
526  if (array_key_exists($order, $this->answers)) {
527  // Insert answer
528  $answer = new ASS_AnswerImagemap($answertext, $points, $order, 0, -1);
529  $answer->setCoords($coords);
530  $answer->setArea($area);
531  $answer->setPointsUnchecked($points_unchecked);
532  for ($i = count($this->answers) - 1; $i >= $order; $i--) {
533  $this->answers[$i + 1] = $this->answers[$i];
534  $this->answers[$i + 1]->setOrder($i + 1);
535  }
536  $this->answers[$order] = $answer;
537  } else {
538  // Append answer
539  $answer = new ASS_AnswerImagemap($answertext, $points, count($this->answers), 0, -1);
540  $answer->setCoords($coords);
541  $answer->setArea($area);
542  $answer->setPointsUnchecked($points_unchecked);
543  array_push($this->answers, $answer);
544  }
545  }
546 
556  public function getAnswerCount(): int
557  {
558  return count($this->answers);
559  }
560 
572  public function getAnswer($index = 0): ?object
573  {
574  if ($index < 0) {
575  return null;
576  }
577  if (count($this->answers) < 1) {
578  return null;
579  }
580  if ($index >= count($this->answers)) {
581  return null;
582  }
583  return $this->answers[$index];
584  }
585 
595  public function &getAnswers(): array
596  {
597  return $this->answers;
598  }
599 
610  public function deleteArea($index = 0): void
611  {
612  if ($index < 0) {
613  return;
614  }
615  if (count($this->answers) < 1) {
616  return;
617  }
618  if ($index >= count($this->answers)) {
619  return;
620  }
621  unset($this->answers[$index]);
622  $this->answers = array_values($this->answers);
623  for ($i = 0; $i < count($this->answers); $i++) {
624  if ($this->answers[$i]->getOrder() > $index) {
625  $this->answers[$i]->setOrder($i);
626  }
627  }
628  }
629 
638  public function flushAnswers(): void
639  {
640  $this->answers = array();
641  }
642 
651  public function getMaximumPoints(): float
652  {
653  $points = 0;
654  foreach ($this->answers as $key => $value) {
655  if ($this->is_multiple_choice) {
656  if ($value->getPoints() > $value->getPointsUnchecked()) {
657  $points += $value->getPoints();
658  } else {
659  $points += $value->getPointsUnchecked();
660  }
661  } else {
662  if ($value->getPoints() > $points) {
663  $points = $value->getPoints();
664  }
665  }
666  }
667  return $points;
668  }
669 
680  public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false): float
681  {
682  if ($returndetails) {
683  throw new ilTestException('return details not implemented for ' . __METHOD__);
684  }
685 
686  global $DIC;
687  $ilDB = $DIC['ilDB'];
688 
689  $found_values = array();
690  if (is_null($pass)) {
691  $pass = $this->getSolutionMaxPass($active_id);
692  }
693  $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
694  while ($data = $ilDB->fetchAssoc($result)) {
695  if (strcmp($data["value1"], "") != 0) {
696  array_push($found_values, $data["value1"]);
697  }
698  }
699 
700  $points = $this->calculateReachedPointsForSolution($found_values);
701 
702  return $points;
703  }
704 
706  {
707  $solutionData = $previewSession->getParticipantsSolution();
708 
709  $reachedPoints = $this->calculateReachedPointsForSolution(is_array($solutionData) ? array_values($solutionData) : array());
710  $reachedPoints = $this->deductHintPointsFromReachedPoints($previewSession, $reachedPoints);
711 
712  return $this->ensureNonNegativePoints($reachedPoints);
713  }
714 
723  public function saveWorkingData($active_id, $pass = null, $authorized = true): bool
724  {
725  global $DIC;
726  $ilDB = $DIC['ilDB'];
727 
728  if (is_null($pass)) {
729  $pass = ilObjTest::_getPass($active_id);
730  }
731 
732  $solutionSelectionChanged = false;
733 
734  $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$solutionSelectionChanged, $ilDB, $active_id, $pass, $authorized) {
735  if ($authorized) {
736  // remove the dummy record of the intermediate solution
737  $this->deleteDummySolutionRecord($active_id, $pass);
738 
739  // delete the authorized solution and make the intermediate solution authorized (keeping timestamps)
740  $this->removeCurrentSolution($active_id, $pass, true);
741  $this->updateCurrentSolutionsAuthorization($active_id, $pass, true, true);
742 
743  $solutionSelectionChanged = true;
744  } else {
746  $active_id,
747  $pass,
748  $this->is_multiple_choice
749  );
750 
751  if ($this->isReuseSolutionSelectionRequest()) {
752  $selection = $this->getReuseSolutionSelectionParameter();
753 
754  foreach ($selection as $selectedIndex) {
755  $this->saveCurrentSolution($active_id, $pass, (int) $selectedIndex, null, $authorized);
756  $solutionSelectionChanged = true;
757  }
758  } elseif ($this->isRemoveSolutionSelectionRequest()) {
759  $selection = $this->getRemoveSolutionSelectionParameter();
760 
761  $this->deleteSolutionRecordByValues($active_id, $pass, $authorized, array(
762  'value1' => (int) $selection
763  ));
764 
765  $solutionSelectionChanged = true;
766  } elseif ($this->isAddSolutionSelectionRequest()) {
767  $selection = $this->getAddSolutionSelectionParameter();
768 
769  if ($this->is_multiple_choice) {
770  $this->deleteSolutionRecordByValues($active_id, $pass, $authorized, array(
771  'value1' => (int) $this->request->raw('selImage')
772  ));
773  } else {
774  $this->removeCurrentSolution($active_id, $pass, $authorized);
775  }
776 
777  $this->saveCurrentSolution($active_id, $pass, $this->request->raw('selImage'), null, $authorized);
778 
779  $solutionSelectionChanged = true;
780  }
781  }
782  });
783 
785  if ($solutionSelectionChanged) {
786  assQuestion::logAction($this->lng->txtlng(
787  "assessment",
788  "log_user_entered_values",
790  ), $active_id, $this->getId());
791  } else {
792  assQuestion::logAction($this->lng->txtlng(
793  "assessment",
794  "log_user_not_entered_values",
796  ), $active_id, $this->getId());
797  }
798  }
799 
800  return true;
801  }
802 
803  protected function savePreviewData(ilAssQuestionPreviewSession $previewSession): void
804  {
805  $solution = $previewSession->getParticipantsSolution();
806 
807  if ($this->is_multiple_choice
808  && $this->request->isset('remImage')) {
809  unset($solution[$this->request->int('remImage')]);
810  }
811 
812  if ($this->request->isset('selImage')) {
813  if (!$this->is_multiple_choice) {
814  $solution = array();
815  }
816 
817  $solution[$this->request->int('selImage')] = $this->request->int('selImage');
818  }
819 
820  $previewSession->setParticipantsSolution($solution);
821  }
822 
823  public function syncWithOriginal(): void
824  {
825  if ($this->questioninfo->getOriginalId($this->getId())) {
826  parent::syncWithOriginal();
827  }
828  }
829 
838  public function getQuestionType(): string
839  {
840  return "assImagemapQuestion";
841  }
842 
851  public function getAdditionalTableName(): string
852  {
853  return "qpl_qst_imagemap";
854  }
855 
864  public function getAnswerTableName(): string
865  {
866  return "qpl_a_imagemap";
867  }
868 
873  public function getRTETextWithMediaObjects(): string
874  {
875  $text = parent::getRTETextWithMediaObjects();
876  foreach ($this->answers as $index => $answer) {
877  $text .= $this->feedbackOBJ->getSpecificAnswerFeedbackContent($this->getId(), 0, $index);
878  }
879  return $text;
880  }
881 
885  public function setExportDetailsXLSX(ilAssExcelFormatHelper $worksheet, int $startrow, int $col, int $active_id, int $pass): int
886  {
887  parent::setExportDetailsXLSX($worksheet, $startrow, $col, $active_id, $pass);
888 
889  $solution = $this->getSolutionValues($active_id, $pass);
890 
891  $i = 1;
892  foreach ($this->getAnswers() as $id => $answer) {
893  $worksheet->setCell($startrow + $i, $col, $answer->getArea() . ": " . $answer->getCoords());
894  $worksheet->setBold($worksheet->getColumnCoord($col) . ($startrow + $i));
895 
896  $cellValue = 0;
897  foreach ($solution as $solIndex => $sol) {
898  if ($sol['value1'] == $id) {
899  $cellValue = 1;
900  break;
901  }
902  }
903 
904  $worksheet->setCell($startrow + $i, $col + 2, $cellValue);
905 
906  $i++;
907  }
908 
909  return $startrow + $i + 1;
910  }
911 
915  public function deleteImage(): void
916  {
917  $file = $this->getImagePath() . $this->getImageFilename();
918  @unlink($file);
919  $this->flushAnswers();
920  $this->image_filename = "";
921  }
922 
926  public function toJSON(): string
927  {
928  $result = array();
929  $result['id'] = $this->getId();
930  $result['type'] = (string) $this->getQuestionType();
931  $result['title'] = $this->getTitleForHTMLOutput();
932  $result['question'] = $this->formatSAQuestion($this->getQuestion());
933  $result['nr_of_tries'] = $this->getNrOfTries();
934  $result['shuffle'] = $this->getShuffle();
935  $result['is_multiple'] = $this->getIsMultipleChoice();
936  $result['feedback'] = array(
937  'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
938  'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
939  );
940  $result['image'] = $this->getImagePathWeb() . $this->getImageFilename();
941 
942  $answers = array();
943  $order = 0;
944  foreach ($this->getAnswers() as $key => $answer_obj) {
945  array_push($answers, array(
946  "answertext" => (string) $answer_obj->getAnswertext(),
947  "points" => (float) $answer_obj->getPoints(),
948  "points_unchecked" => (float) $answer_obj->getPointsUnchecked(),
949  "order" => $order,
950  "coords" => $answer_obj->getCoords(),
951  "state" => $answer_obj->getState(),
952  "area" => $answer_obj->getArea(),
953  "feedback" => $this->formatSAQuestion(
954  $this->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation($this->getId(), 0, $key)
955  )
956  ));
957  $order++;
958  }
959  $result['answers'] = $answers;
960 
961  $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
962  $result['mobs'] = $mobs;
963 
964  return json_encode($result);
965  }
966 
971  protected function calculateReachedPointsForSolution($found_values): float
972  {
973  if ($found_values == null) {
974  $found_values = [];
975  }
976  $points = 0;
977  if (count($found_values) > 0) {
978  foreach ($this->answers as $key => $answer) {
979  if (in_array($key, $found_values)) {
980  $points += $answer->getPoints();
981  } elseif ($this->getIsMultipleChoice()) {
982  $points += $answer->getPointsUnchecked();
983  }
984  }
985  return $points;
986  }
987  return $points;
988  }
989 
998  public function getOperators($expression): array
999  {
1001  }
1002 
1007  public function getExpressionTypes(): array
1008  {
1009  return array(
1014  );
1015  }
1016 
1025  public function getUserQuestionResult($active_id, $pass): ilUserQuestionResult
1026  {
1028  global $DIC;
1029  $ilDB = $DIC['ilDB'];
1030  $result = new ilUserQuestionResult($this, $active_id, $pass);
1031 
1032  $maxStep = $this->lookupMaxStep($active_id, $pass);
1033 
1034  if ($maxStep > 0) {
1035  $data = $ilDB->queryF(
1036  "SELECT value1+1 as value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
1037  array("integer", "integer", "integer", "integer"),
1038  array($active_id, $pass, $this->getId(), $maxStep)
1039  );
1040  } else {
1041  $data = $ilDB->queryF(
1042  "SELECT value1+1 as value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step IS NULL",
1043  array("integer", "integer", "integer"),
1044  array($active_id, $pass, $this->getId())
1045  );
1046  }
1047 
1048  while ($row = $ilDB->fetchAssoc($data)) {
1049  $result->addKeyValue($row["value1"], $row["value1"]);
1050  }
1051 
1052  $points = $this->calculateReachedPoints($active_id, $pass);
1053  $max_points = $this->getMaximumPoints();
1054 
1055  $result->setReachedPercentage(($points / $max_points) * 100);
1056 
1057  return $result;
1058  }
1059 
1067  public function getAvailableAnswerOptions($index = null)
1068  {
1069  if ($index !== null) {
1070  return $this->getAnswer($index);
1071  } else {
1072  return $this->getAnswers();
1073  }
1074  }
1075 
1076  // hey: prevPassSolutions - wtf is imagemap ^^
1077  public function getTestOutputSolutions($activeId, $pass): array
1078  {
1079  $solution = parent::getTestOutputSolutions($activeId, $pass);
1080 
1081  $this->currentSolution = array();
1082  foreach ($solution as $record) {
1083  $this->currentSolution[] = $record['value1'];
1084  }
1085 
1086  return $solution;
1087  }
1089  {
1090  if (!$this->isAddSolutionSelectionRequest()) {
1091  return null;
1092  }
1093 
1094  return $this->request->raw('selImage');
1095  }
1096  protected function isAddSolutionSelectionRequest(): bool
1097  {
1098  if (!$this->request->isset("selImage")) {
1099  return false;
1100  }
1101 
1102  if (!strlen($this->request->raw('selImage'))) {
1103  return false;
1104  }
1105 
1106  return true;
1107  }
1109  {
1110  if (!$this->isRemoveSolutionSelectionRequest()) {
1111  return null;
1112  }
1113 
1114  return $this->request->raw('remImage');
1115  }
1116  protected function isRemoveSolutionSelectionRequest(): bool
1117  {
1118  if (!$this->is_multiple_choice) {
1119  return false;
1120  }
1121 
1122  if (!$this->request->isset("remImage")) {
1123  return false;
1124  }
1125 
1126  if (!strlen($this->request->raw('remImage'))) {
1127  return false;
1128  }
1129 
1130  return true;
1131  }
1132  protected function getReuseSolutionSelectionParameter(): ?array
1133  {
1134  if (!$this->isReuseSolutionSelectionRequest()) {
1135  return null;
1136  }
1137 
1138  return assQuestion::explodeKeyValues($this->request->raw("reuseSelection"));
1139  }
1140  protected function isReuseSolutionSelectionRequest(): bool
1141  {
1142  if (!$this->getTestPresentationConfig()->isPreviousPassSolutionReuseAllowed()) {
1143  return false;
1144  }
1145 
1146  if (!$this->request->isset("reuseSelection")) {
1147  return false;
1148  }
1149 
1150  if (!strlen($this->request->raw("reuseSelection"))) {
1151  return false;
1152  }
1153 
1154  if (!preg_match('/\d(,\d)*/', $this->request->raw("reuseSelection"))) {
1155  return false;
1156  }
1157 
1158  return true;
1159  }
1160  // hey.
1161 }
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...
getSolutionValues($active_id, $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
setNrOfTries(int $a_nr_of_tries)
calculateReachedPointsForSolution($found_values)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
savePreviewData(ilAssQuestionPreviewSession $previewSession)
updateCurrentSolutionsAuthorization(int $activeId, int $pass, bool $authorized, bool $keepTime=false)
duplicate(bool $for_test=true, string $title="", string $author="", int $owner=-1, $testObjId=null)
Duplicates an assImagemapQuestion.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Abstract basic class which is to be extended by the concrete assessment question type classes...
setOwner(int $owner=-1)
ILIAS TestQuestionPool InternalRequestService $request
getOperators($expression)
Get all available operations for a specific question.
getColumnCoord(int $a_col)
Get column "name" from number.
ensureNonNegativePoints($points)
__construct( $title="", $comment="", $author="", $owner=-1, $question="", $image_filename="")
assImagemapQuestion constructor
getImagePathWeb()
Returns the web image path for web accessable images of a question.
setCell($a_row, $a_col, $a_value, $datatype=null)
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
deleteArea($index=0)
Deletes an answer.
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
setComment(string $comment="")
float $points
The maximum available points for the question.
Base Exception for all Exceptions relating to Modules/Test.
getIsMultipleChoice()
Returns true, if the imagemap question is a multiplechoice question.
deleteDummySolutionRecord(int $activeId, int $passIndex)
global $DIC
Definition: feed.php:28
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
getTestOutputSolutions($activeId, $pass)
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
setBold(string $a_coords)
Set cell(s) to bold.
__construct(VocabulariesInterface $vocabularies)
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
getAnswer($index=0)
Returns an answer.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
saveToDb($original_id="")
Saves an assImagemapQuestion object to a database.
uploadImagemap(array $shapes)
Uploads an image map and takes over the areas.
toJSON()
Returns a JSON representation of the question.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static logAction(string $logtext, int $active_id, int $question_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
string $key
Consumer key/client ID value.
Definition: System.php:193
deleteImage()
Deletes the image file.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
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)
string $question
The question text.
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
setExportDetailsXLSX(ilAssExcelFormatHelper $worksheet, int $startrow, int $col, int $active_id, int $pass)
{}
static _getMobsOfObject(string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
isComplete()
Returns true, if a imagemap question is complete for use.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
copyImage($question_id, $source_questionpool)
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
duplicateImage($question_id, $objectId=null)
$filename
Definition: buildRTE.php:78
setIsMultipleChoice($is_multiple_choice)
Set true if the Imagemapquestion is a multiplechoice Question.
getExpressionTypes()
Get all available expression types for a specific question.
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
deductHintPointsFromReachedPoints(ilAssQuestionPreviewSession $previewSession, $reachedPoints)
addAnswer( $answertext="", $points=0.0, $order=0, $coords="", $area="", $points_unchecked=0.0)
Adds a possible answer for a imagemap question.
saveQuestionDataToDb(int $original_id=-1)
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
getSolutionMaxPass(int $active_id)
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
& getAnswers()
Returns the answer array.
copyObject($target_questionpool_id, $title="")
Copies an assImagemapQuestion object.
getAnswerCount()
Returns the number of answers.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setId(int $id=-1)
setOriginalId(?int $original_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setImageFilename($image_filename, $image_tempfilename="")
Sets the image file name.
setTitle(string $title="")
deleteSolutionRecordByValues(int $activeId, int $passIndex, bool $authorized, array $matchValues)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
getAnswerTableName()
Returns the name of the answer table in the database.
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
getQuestionType()
Returns the question type of the question.
flushAnswers()
Deletes all answers.
forceExistingIntermediateSolution(int $activeId, int $passIndex, bool $considerDummyRecordCreation)
ILIAS DI LoggingServices $ilLog
lookupMaxStep(int $active_id, int $pass)
setAuthor(string $author="")
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
loadFromDb($question_id)
Loads a assImagemapQuestion object from a database.
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
get_imagemap_contents($href="#")
Gets the imagemap file contents.
static explodeKeyValues(string $keyValues)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
setQuestion(string $question="")