ILIAS  release_8 Revision v8.24
class.assMatchingQuestion.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
21use ILIAS\Refinery\Random\Group as RandomGroup;
23
24require_once './Modules/Test/classes/inc.AssessmentConstants.php';
25
40{
41 private int $shufflemode = 0;
42
60
66 protected array $terms = [];
67
68 protected $definitions;
74 public $thumb_geometry = 100;
75
82
83 public const MATCHING_MODE_1_ON_1 = '1:1';
84 public const MATCHING_MODE_N_ON_N = 'n:n';
85
87
88 private RandomGroup $randomGroup;
89
102 public function __construct(
103 $title = "",
104 $comment = "",
105 $author = "",
106 $owner = -1,
107 $question = "",
109 ) {
110 global $DIC;
111
113 $this->matchingpairs = array();
114 $this->matching_type = $matching_type;
115 $this->terms = array();
116 $this->definitions = array();
117 $this->randomGroup = $DIC->refinery()->random();
118 }
119
120 public function getShuffleMode(): int
121 {
122 return $this->shufflemode;
123 }
124
125 public function setShuffleMode(int $shuffle)
126 {
127 $this->shufflemode = $shuffle;
128 }
129
135 public function isComplete(): bool
136 {
137 if (strlen($this->title)
138 && $this->author
139 && $this->question
140 && count($this->matchingpairs)
141 && $this->getMaximumPoints() > 0
142 ) {
143 return true;
144 }
145 return false;
146 }
147
154 public function saveToDb($original_id = ""): void
155 {
156 if ($original_id == "") {
157 $this->saveQuestionDataToDb();
158 } else {
160 }
161
164
165 parent::saveToDb();
166 }
167
169 {
170 global $DIC;
171 $ilDB = $DIC['ilDB'];
172 // delete old terms
173 $ilDB->manipulateF(
174 "DELETE FROM qpl_a_mterm WHERE question_fi = %s",
175 array( 'integer' ),
176 array( $this->getId() )
177 );
178
179 // delete old definitions
180 $ilDB->manipulateF(
181 "DELETE FROM qpl_a_mdef WHERE question_fi = %s",
182 array( 'integer' ),
183 array( $this->getId() )
184 );
185
186 $termids = array();
187 // write terms
188 foreach ($this->terms as $key => $term) {
189 $next_id = $ilDB->nextId('qpl_a_mterm');
190 $ilDB->insert('qpl_a_mterm', array(
191 'term_id' => array('integer', $next_id),
192 'question_fi' => array('integer', $this->getId()),
193 'picture' => array('text', $term->getPicture()),
194 'term' => array('text', $term->getText()),
195 'ident' => array('integer', $term->getIdentifier())
196 ));
197 $termids[$term->getIdentifier()] = $next_id;
198 }
199
200 $definitionids = array();
201 // write definitions
202 foreach ($this->definitions as $key => $definition) {
203 $next_id = $ilDB->nextId('qpl_a_mdef');
204 $ilDB->insert('qpl_a_mdef', array(
205 'def_id' => array('integer', $next_id),
206 'question_fi' => array('integer', $this->getId()),
207 'picture' => array('text', $definition->getPicture()),
208 'definition' => array('text', $definition->getText()),
209 'ident' => array('integer', $definition->getIdentifier())
210 ));
211 $definitionids[$definition->getIdentifier()] = $next_id;
212 }
213
214 $ilDB->manipulateF(
215 "DELETE FROM qpl_a_matching WHERE question_fi = %s",
216 array( 'integer' ),
217 array( $this->getId() )
218 );
220 foreach ($matchingpairs as $key => $pair) {
221 $next_id = $ilDB->nextId('qpl_a_matching');
222 $ilDB->manipulateF(
223 "INSERT INTO qpl_a_matching (answer_id, question_fi, points, term_fi, definition_fi) VALUES (%s, %s, %s, %s, %s)",
224 array( 'integer', 'integer', 'float', 'integer', 'integer' ),
225 array(
226 $next_id,
227 $this->getId(),
228 $pair->getPoints(),
229 $termids[$pair->getTerm()->getIdentifier()],
230 $definitionids[$pair->getDefinition()->getIdentifier()]
231 )
232 );
233 }
234
235 $this->rebuildThumbnails();
236 }
237
239 {
240 global $DIC;
241 $ilDB = $DIC['ilDB'];
242
243 // save additional data
244
245 $ilDB->manipulateF(
246 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
247 array( "integer" ),
248 array( $this->getId() )
249 );
250
251 $ilDB->insert($this->getAdditionalTableName(), array(
252 'question_fi' => array('integer', $this->getId()),
253 'shuffle' => array('text', $this->getShuffleMode()),
254 'matching_type' => array('text', $this->matching_type),
255 'thumb_geometry' => array('integer', $this->getThumbGeometry()),
256 'matching_mode' => array('text', $this->getMatchingMode())
257 ));
258 }
259
266 public function loadFromDb($question_id): void
267 {
268 global $DIC;
269 $ilDB = $DIC['ilDB'];
270
271 $query = "
272 SELECT qpl_questions.*,
273 {$this->getAdditionalTableName()}.*
274 FROM qpl_questions
275 LEFT JOIN {$this->getAdditionalTableName()}
276 ON {$this->getAdditionalTableName()}.question_fi = qpl_questions.question_id
277 WHERE qpl_questions.question_id = %s
278 ";
279
280 $result = $ilDB->queryF(
281 $query,
282 array('integer'),
283 array($question_id)
284 );
285
286 if ($result->numRows() == 1) {
287 $data = $ilDB->fetchAssoc($result);
288 $this->setId((int) $question_id);
289 $this->setObjId((int) $data["obj_fi"]);
290 $this->setTitle((string) $data["title"]);
291 $this->setComment((string) $data["description"]);
292 $this->setOriginalId((int) $data["original_id"]);
293 $this->setNrOfTries((int) $data['nr_of_tries']);
294 $this->setAuthor($data["author"]);
295 $this->setPoints((float) $data["points"]);
296 $this->setOwner((int) $data["owner"]);
297 include_once("./Services/RTE/classes/class.ilRTE.php");
298 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data["question_text"], 1));
299 $this->setThumbGeometry((int) $data["thumb_geometry"]);
300 $this->setShuffle($data["shuffle"] != '0');
301 $this->setShuffleMode((int) $data['shuffle']);
302 $this->setMatchingMode($data['matching_mode'] === null ? self::MATCHING_MODE_1_ON_1 : $data['matching_mode']);
303
304 try {
305 $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
308 }
309
310 try {
311 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
313 }
314 }
315
316 $termids = array();
317 $result = $ilDB->queryF(
318 "SELECT * FROM qpl_a_mterm WHERE question_fi = %s ORDER BY term_id ASC",
319 array('integer'),
320 array($question_id)
321 );
322 $this->terms = [];
323 if ($result->numRows() > 0) {
324 while ($data = $ilDB->fetchAssoc($result)) {
325 $term = $this->createMatchingTerm($data['term'] ?? '', $data['picture'] ?? '', (int) $data['ident']);
326 $this->terms[] = $term;
327 $termids[$data['term_id']] = $term;
328 }
329 }
330
331 $definitionids = array();
332 $result = $ilDB->queryF(
333 "SELECT * FROM qpl_a_mdef WHERE question_fi = %s ORDER BY def_id ASC",
334 array('integer'),
335 array($question_id)
336 );
337
338 $this->definitions = array();
339 if ($result->numRows() > 0) {
340 while ($data = $ilDB->fetchAssoc($result)) {
341 $definition = $this->createMatchingDefinition($data['definition'] ?? '', $data['picture'] ?? '', (int) $data['ident']);
342 array_push($this->definitions, $definition);
343 $definitionids[$data['def_id']] = $definition;
344 }
345 }
346
347 $this->matchingpairs = array();
348 $result = $ilDB->queryF(
349 "SELECT * FROM qpl_a_matching WHERE question_fi = %s ORDER BY answer_id",
350 array('integer'),
351 array($question_id)
352 );
353 if ($result->numRows() > 0) {
354 while ($data = $ilDB->fetchAssoc($result)) {
355 $pair = $this->createMatchingPair(
356 $termids[$data['term_fi']],
357 $definitionids[$data['definition_fi']],
358 (float) $data['points']
359 );
360 array_push($this->matchingpairs, $pair);
361 }
362 }
363 parent::loadFromDb((int) $question_id);
364 }
365
366
370 public function duplicate(bool $for_test = true, string $title = "", string $author = "", string $owner = "", $testObjId = null): int
371 {
372 if ($this->id <= 0) {
373 // The question has not been saved. It cannot be duplicated
374 return -1;
375 }
376 // duplicate the question in database
377 $this_id = $this->getId();
378 $thisObjId = $this->getObjId();
379
380 $clone = $this;
381 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
383 $clone->id = -1;
384
385 if ((int) $testObjId > 0) {
386 $clone->setObjId($testObjId);
387 }
388
389 if ($title) {
390 $clone->setTitle($title);
391 }
392 if ($author) {
393 $clone->setAuthor($author);
394 }
395 if ($owner) {
396 $clone->setOwner((int) $owner);
397 }
398 if ($for_test) {
399 $clone->saveToDb($original_id);
400 } else {
401 $clone->saveToDb();
402 }
403
404 // copy question page content
405 $clone->copyPageOfQuestion($this_id);
406 // copy XHTML media objects
407 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
408 // duplicate the image
409 $clone->duplicateImages($this_id, $thisObjId, $clone->getId(), $testObjId);
410
411 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
412
413 return $clone->id;
414 }
415
419 public function copyObject($target_questionpool_id, $title = ""): int
420 {
421 if ($this->getId() <= 0) {
422 throw new RuntimeException('The question has not been saved. It cannot be duplicated');
423 }
424 // duplicate the question in database
425 $clone = $this;
426 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
428 $clone->id = -1;
429 $source_questionpool_id = $this->getObjId();
430 $clone->setObjId($target_questionpool_id);
431 if ($title) {
432 $clone->setTitle($title);
433 }
434 $clone->saveToDb();
435 // copy question page content
436 $clone->copyPageOfQuestion($original_id);
437 // copy XHTML media objects
438 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
439 // duplicate the image
440 $clone->copyImages($original_id, $source_questionpool_id);
441
442 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
443
444 return $clone->id;
445 }
446
447 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = ""): int
448 {
449 if ($this->getId() <= 0) {
450 throw new RuntimeException('The question has not been saved. It cannot be duplicated');
451 }
452
453 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
454
455 $sourceQuestionId = $this->id;
456 $sourceParentId = $this->getObjId();
457
458 // duplicate the question in database
459 $clone = $this;
460 $clone->id = -1;
461
462 $clone->setObjId($targetParentId);
463
464 if ($targetQuestionTitle) {
465 $clone->setTitle($targetQuestionTitle);
466 }
467
468 $clone->saveToDb();
469 // copy question page content
470 $clone->copyPageOfQuestion($sourceQuestionId);
471 // copy XHTML media objects
472 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
473 // duplicate the image
474 $clone->copyImages($sourceQuestionId, $sourceParentId);
475
476 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
477
478 return $clone->id;
479 }
480
481 public function duplicateImages($question_id, $objectId = null): void
482 {
483 global $DIC;
484 $ilLog = $DIC['ilLog'];
485 $imagepath = $this->getImagePath();
486 $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
487
488 if ((int) $objectId > 0) {
489 $imagepath_original = str_replace("/$this->obj_id/", "/$objectId/", $imagepath_original);
490 }
491
492 foreach ($this->terms as $term) {
493 if (strlen($term->getPicture())) {
494 $filename = $term->getPicture();
495 if (!file_exists($imagepath)) {
496 ilFileUtils::makeDirParents($imagepath);
497 }
498 if (!@copy($imagepath_original . $filename, $imagepath . $filename)) {
499 $ilLog->write("matching question image could not be duplicated: $imagepath_original$filename");
500 }
501 if (@file_exists($imagepath_original . $this->getThumbPrefix() . $filename)) {
502 if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
503 $ilLog->write("matching question image thumbnail could not be duplicated: $imagepath_original" . $this->getThumbPrefix() . $filename);
504 }
505 }
506 }
507 }
508 foreach ($this->definitions as $definition) {
509 if (strlen($definition->getPicture())) {
510 $filename = $definition->getPicture();
511 if (!file_exists($imagepath)) {
512 ilFileUtils::makeDirParents($imagepath);
513 }
514 if (!@copy($imagepath_original . $filename, $imagepath . $filename)) {
515 $ilLog->write("matching question image could not be duplicated: $imagepath_original$filename");
516 }
517 if (@file_exists($imagepath_original . $this->getThumbPrefix() . $filename)) {
518 if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
519 $ilLog->write("matching question image thumbnail could not be duplicated: $imagepath_original" . $this->getThumbPrefix() . $filename);
520 }
521 }
522 }
523 }
524 }
525
526 public function copyImages($question_id, $source_questionpool): void
527 {
528 global $DIC;
529 $ilLog = $DIC['ilLog'];
530
531 $imagepath = $this->getImagePath();
532 $imagepath_original = str_replace("/$this->id/images", "/$question_id/images", $imagepath);
533 $imagepath_original = str_replace("/$this->obj_id/", "/$source_questionpool/", $imagepath_original);
534 foreach ($this->terms as $term) {
535 if (strlen($term->getPicture())) {
536 if (!file_exists($imagepath)) {
537 ilFileUtils::makeDirParents($imagepath);
538 }
539 $filename = $term->getPicture();
540 if (!@copy($imagepath_original . $filename, $imagepath . $filename)) {
541 $ilLog->write("matching question image could not be copied: $imagepath_original$filename");
542 }
543 if (!@copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename)) {
544 $ilLog->write("matching question image thumbnail could not be copied: $imagepath_original" . $this->getThumbPrefix() . $filename);
545 }
546 }
547 }
548 foreach ($this->definitions as $definition) {
549 if (strlen($definition->getPicture())) {
550 $filename = $definition->getPicture();
551 if (!file_exists($imagepath)) {
552 ilFileUtils::makeDirParents($imagepath);
553 }
554
555 if (assQuestion::isFileAvailable($imagepath_original . $filename)) {
556 copy($imagepath_original . $filename, $imagepath . $filename);
557 } else {
558 $ilLog->write("matching question image could not be copied: $imagepath_original$filename");
559 }
560
561 if (assQuestion::isFileAvailable($imagepath_original . $this->getThumbPrefix() . $filename)) {
562 copy($imagepath_original . $this->getThumbPrefix() . $filename, $imagepath . $this->getThumbPrefix() . $filename);
563 } else {
564 $ilLog->write("matching question image thumbnail could not be copied: $imagepath_original" . $this->getThumbPrefix() . $filename);
565 }
566 }
567 }
568 }
569
580 public function insertMatchingPair($position, $term = null, $definition = null, $points = 0.0): void
581 {
582 $pair = $this->createMatchingPair($term, $definition, $points);
583
584 if ($position < count($this->matchingpairs)) {
585 $part1 = array_slice($this->matchingpairs, 0, $position);
586 $part2 = array_slice($this->matchingpairs, $position);
587 $this->matchingpairs = array_merge($part1, array($pair), $part2);
588 } else {
589 array_push($this->matchingpairs, $pair);
590 }
591 }
592
604 public function addMatchingPair(assAnswerMatchingTerm $term = null, assAnswerMatchingDefinition $definition = null, $points = 0.0): void
605 {
606 $pair = $this->createMatchingPair($term, $definition, $points);
607 array_push($this->matchingpairs, $pair);
608 }
609
613 public function getTermWithIdentifier($a_identifier)
614 {
615 foreach ($this->terms as $term) {
616 if ($term->getIdentifier() == $a_identifier) {
617 return $term;
618 }
619 }
620 return null;
621 }
622
626 public function getDefinitionWithIdentifier($a_identifier)
627 {
628 foreach ($this->definitions as $definition) {
629 if ($definition->getIdentifier() == $a_identifier) {
630 return $definition;
631 }
632 }
633 return null;
634 }
635
644 public function getMatchingPair($index = 0): ?object
645 {
646 if ($index < 0) {
647 return null;
648 }
649 if (count($this->matchingpairs) < 1) {
650 return null;
651 }
652 if ($index >= count($this->matchingpairs)) {
653 return null;
654 }
655 return $this->matchingpairs[$index];
656 }
657
665 public function deleteMatchingPair($index = 0): void
666 {
667 if ($index < 0) {
668 return;
669 }
670 if (count($this->matchingpairs) < 1) {
671 return;
672 }
673 if ($index >= count($this->matchingpairs)) {
674 return;
675 }
676 unset($this->matchingpairs[$index]);
677 $this->matchingpairs = array_values($this->matchingpairs);
678 }
679
684 public function flushMatchingPairs(): void
685 {
686 $this->matchingpairs = array();
687 }
688
692 public function withMatchingPairs(array $pairs): self
693 {
694 $clone = clone $this;
695 $clone->matchingpairs = $pairs;
696 return $clone;
697 }
698
699
706 public function getMatchingPairCount(): int
707 {
708 return count($this->matchingpairs);
709 }
710
717 public function getTerms(): array
718 {
719 return $this->terms;
720 }
721
728 public function getDefinitions(): array
729 {
730 return $this->definitions;
731 }
732
739 public function getTermCount(): int
740 {
741 return count($this->terms);
742 }
743
750 public function getDefinitionCount(): int
751 {
752 return count($this->definitions);
753 }
754
755 public function addTerm(assAnswerMatchingTerm $term): void
756 {
757 $this->terms[] = $term;
758 }
759
766 public function addDefinition($definition): void
767 {
768 array_push($this->definitions, $definition);
769 }
770
777 public function insertTerm($position, assAnswerMatchingTerm $term = null): void
778 {
779 if (is_null($term)) {
780 $term = $this->createMatchingTerm();
781 }
782 if ($position < count($this->terms)) {
783 $part1 = array_slice($this->terms, 0, $position);
784 $part2 = array_slice($this->terms, $position);
785 $this->terms = array_merge($part1, array($term), $part2);
786 } else {
787 array_push($this->terms, $term);
788 }
789 }
790
797 public function insertDefinition($position, assAnswerMatchingDefinition $definition = null): void
798 {
799 if (is_null($definition)) {
800 $definition = $this->createMatchingDefinition();
801 }
802 if ($position < count($this->definitions)) {
803 $part1 = array_slice($this->definitions, 0, $position);
804 $part2 = array_slice($this->definitions, $position);
805 $this->definitions = array_merge($part1, array($definition), $part2);
806 } else {
807 array_push($this->definitions, $definition);
808 }
809 }
810
815 public function flushTerms(): void
816 {
817 $this->terms = array();
818 }
819
824 public function flushDefinitions(): void
825 {
826 $this->definitions = array();
827 }
828
835 public function deleteTerm($position): void
836 {
837 unset($this->terms[$position]);
838 $this->terms = array_values($this->terms);
839 }
840
847 public function deleteDefinition($position): void
848 {
849 unset($this->definitions[$position]);
850 $this->definitions = array_values($this->definitions);
851 }
852
860 public function setTerm($term, $index): void
861 {
862 $this->terms[$index] = $term;
863 }
864
875 public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false): float
876 {
877 if ($returndetails) {
878 throw new ilTestException('return details not implemented for ' . __METHOD__);
879 }
880
881 global $DIC;
882 $ilDB = $DIC['ilDB'];
883
884 $found_values = [];
885 if (is_null($pass)) {
886 $pass = $this->getSolutionMaxPass($active_id);
887 }
888 $result = $this->getCurrentSolutionResultSet($active_id, (int) $pass, $authorizedSolution);
889 while ($data = $ilDB->fetchAssoc($result)) {
890 if (strcmp($data["value1"], "") != 0) {
891 if (!isset($found_values[$data['value2']])) {
892 $found_values[$data['value2']] = array();
893 }
894
895 $found_values[$data['value2']][] = $data['value1'];
896 }
897 }
898
899 $points = $this->calculateReachedPointsForSolution($found_values);
900
901 return $points;
902 }
903
907 public function getMaximumPoints(): float
908 {
909 $points = 0;
910
911 foreach ($this->getMaximumScoringMatchingPairs() as $pair) {
912 $points += $pair->getPoints();
913 }
914
915 return $points;
916 }
917
918 public function getMaximumScoringMatchingPairs(): array
919 {
920 if ($this->getMatchingMode() == self::MATCHING_MODE_N_ON_N) {
921 return $this->getPositiveScoredMatchingPairs();
922 } elseif ($this->getMatchingMode() == self::MATCHING_MODE_1_ON_1) {
924 }
925
926 return array();
927 }
928
929 private function getPositiveScoredMatchingPairs(): array
930 {
931 $matchingPairs = array();
932
933 foreach ($this->matchingpairs as $pair) {
934 if ($pair->getPoints() <= 0) {
935 continue;
936 }
937
938 $matchingPairs[] = $pair;
939 }
940
941 return $matchingPairs;
942 }
943
945 {
946 $matchingPairsByDefinition = array();
947
948 foreach ($this->matchingpairs as $pair) {
949 if ($pair->getPoints() <= 0) {
950 continue;
951 }
952
953 $defId = $pair->getDefinition()->getIdentifier();
954
955 if (!isset($matchingPairsByDefinition[$defId])) {
956 $matchingPairsByDefinition[$defId] = $pair;
957 } elseif ($pair->getPoints() > $matchingPairsByDefinition[$defId]->getPoints()) {
958 $matchingPairsByDefinition[$defId] = $pair;
959 }
960 }
961
962 return $matchingPairsByDefinition;
963 }
964
969 public function fetchIndexedValuesFromValuePairs(array $valuePairs): array
970 {
971 $indexedValues = array();
972
973 foreach ($valuePairs as $valuePair) {
974 if (!isset($indexedValues[$valuePair['value2']])) {
975 $indexedValues[$valuePair['value2']] = array();
976 }
977
978 $indexedValues[$valuePair['value2']][] = $valuePair['value1'];
979 }
980
981 return $indexedValues;
982 }
983
992 public function getEncryptedFilename($filename): string
993 {
994 $extension = "";
995 if (preg_match("/.*\\.(\\w+)$/", $filename, $matches)) {
996 $extension = $matches[1];
997 }
998 return md5($filename) . "." . $extension;
999 }
1000
1001 public function removeTermImage($index): void
1002 {
1003 $term = $this->terms[$index] ?? null;
1004 if (is_object($term)) {
1005 $this->deleteImagefile($term->getPicture());
1006 $term = $term->withPicture('');
1007 }
1008 }
1009
1010 public function removeDefinitionImage($index): void
1011 {
1012 $definition = $this->definitions[$index] ?? null;
1013 if (is_object($definition)) {
1014 $this->deleteImagefile($definition->getPicture());
1015 $definition = $definition->withPicture('');
1016 }
1017 }
1018
1019
1026 public function deleteImagefile(string $filename): bool
1027 {
1028 $deletename = $filename;
1029 try {
1030 $result = unlink($this->getImagePath() . $deletename)
1031 && unlink($this->getImagePath() . $this->getThumbPrefix() . $deletename);
1032 } catch (Throwable $e) {
1033 $result = false;
1034 }
1035 return $result;
1036 }
1037
1046 public function setImageFile($image_tempfilename, $image_filename, $previous_filename = '')
1047 {
1048 $result = true;
1049 if (strlen($image_tempfilename)) {
1050 $image_filename = str_replace(" ", "_", $image_filename);
1051 $imagepath = $this->getImagePath();
1052 if (!file_exists($imagepath)) {
1053 ilFileUtils::makeDirParents($imagepath);
1054 }
1055 $savename = $image_filename;
1056 if (!ilFileUtils::moveUploadedFile($image_tempfilename, $savename, $imagepath . $savename)) {
1057 $result = false;
1058 } else {
1059 // create thumbnail file
1060 $thumbpath = $imagepath . $this->getThumbPrefix() . $savename;
1061 ilShellUtil::convertImage($imagepath . $savename, $thumbpath, "JPEG", (string) $this->getThumbGeometry());
1062 }
1063 if ($result && (strcmp($image_filename, $previous_filename) != 0) && (strlen($previous_filename))) {
1064 $this->deleteImagefile($previous_filename);
1065 }
1066 }
1067 return $result;
1068 }
1069
1070 private function fetchSubmittedMatchingsFromPost(): array
1071 {
1072 $request = $this->dic->testQuestionPool()->internal()->request();
1073 $post = $request->getParsedBody();
1074
1075 $matchings = array();
1076 if (array_key_exists('matching', $post)) {
1077 $postData = $post['matching'][$this->getId()];
1078 foreach ($this->getDefinitions() as $definition) {
1079 if (isset($postData[$definition->getIdentifier()])) {
1080 foreach ($this->getTerms() as $term) {
1081 if (isset($postData[$definition->getIdentifier()][$term->getIdentifier()])) {
1082 if (!is_array($postData[$definition->getIdentifier()])) {
1083 $postData[$definition->getIdentifier()] = array();
1084 }
1085 $matchings[$definition->getIdentifier()][] = $term->getIdentifier();
1086 }
1087 }
1088 }
1089 }
1090 }
1091
1092 return $matchings;
1093 }
1094
1095 private function checkSubmittedMatchings($submittedMatchings): bool
1096 {
1097 if ($this->getMatchingMode() == self::MATCHING_MODE_N_ON_N) {
1098 return true;
1099 }
1100
1101 $handledTerms = array();
1102
1103 foreach ($submittedMatchings as $definition => $terms) {
1104 if (count($terms) > 1) {
1105 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("multiple_matching_values_selected"), true);
1106 return false;
1107 }
1108
1109 foreach ($terms as $i => $term) {
1110 if (isset($handledTerms[$term])) {
1111 $this->tpl->setOnScreenMessage('failure', $this->lng->txt("duplicate_matching_values_selected"), true);
1112 return false;
1113 }
1114
1115 $handledTerms[$term] = $term;
1116 }
1117 }
1118
1119 return true;
1120 }
1121
1130 public function saveWorkingData($active_id, $pass = null, $authorized = true): bool
1131 {
1132 $submittedMatchings = $this->fetchSubmittedMatchingsFromPost();
1133 $submittedMatchingsValid = $this->checkSubmittedMatchings($submittedMatchings);
1134
1135 $matchingsExist = false;
1136
1137 if ($submittedMatchingsValid) {
1138 if (is_null($pass)) {
1139 include_once "./Modules/Test/classes/class.ilObjTest.php";
1140 $pass = ilObjTest::_getPass($active_id);
1141 }
1142
1143 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$matchingsExist, $submittedMatchings, $active_id, $pass, $authorized) {
1144 $this->removeCurrentSolution($active_id, $pass, $authorized);
1145
1146 foreach ($submittedMatchings as $definition => $terms) {
1147 foreach ($terms as $i => $term) {
1148 $this->saveCurrentSolution($active_id, $pass, $term, $definition, $authorized);
1149 $matchingsExist = true;
1150 }
1151 }
1152 });
1153
1154 $saveWorkingDataResult = true;
1155 } else {
1156 $saveWorkingDataResult = false;
1157 }
1158
1159 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
1161 if ($matchingsExist) {
1162 assQuestion::logAction($this->lng->txtlng(
1163 "assessment",
1164 "log_user_entered_values",
1166 ), $active_id, $this->getId());
1167 } else {
1168 assQuestion::logAction($this->lng->txtlng(
1169 "assessment",
1170 "log_user_not_entered_values",
1172 ), $active_id, $this->getId());
1173 }
1174 }
1175
1176 return $saveWorkingDataResult;
1177 }
1178
1179 protected function savePreviewData(ilAssQuestionPreviewSession $previewSession): void
1180 {
1181 $submittedMatchings = $this->fetchSubmittedMatchingsFromPost();
1182
1183 if ($this->checkSubmittedMatchings($submittedMatchings)) {
1184 $previewSession->setParticipantsSolution($submittedMatchings);
1185 }
1186 }
1187
1188 public function getRandomId(): int
1189 {
1190 mt_srand((float) microtime() * 1000000);
1191 $random_number = mt_rand(1, 100000);
1192 $found = false;
1193 while ($found) {
1194 $found = false;
1195 foreach ($this->matchingpairs as $key => $pair) {
1196 if (($pair->getTerm()->getIdentifier() == $random_number) || ($pair->getDefinition()->getIdentifier() == $random_number)) {
1197 $found = true;
1198 $random_number++;
1199 }
1200 }
1201 }
1202 return $random_number;
1203 }
1204
1205 public function setShuffle($shuffle = true): void
1206 {
1207 $this->shuffle = (bool) $shuffle;
1208 }
1209
1215 public function getQuestionType(): string
1216 {
1217 return "assMatchingQuestion";
1218 }
1219
1220 public function getAdditionalTableName(): string
1221 {
1222 return "qpl_qst_matching";
1223 }
1224
1225 public function getAnswerTableName(): array
1226 {
1227 return array("qpl_a_matching", "qpl_a_mterm");
1228 }
1229
1234 public function getRTETextWithMediaObjects(): string
1235 {
1236 return parent::getRTETextWithMediaObjects();
1237 }
1238
1242 public function &getMatchingPairs(): array
1243 {
1244 return $this->matchingpairs;
1245 }
1246
1250 public function setExportDetailsXLS(ilAssExcelFormatHelper $worksheet, int $startrow, int $active_id, int $pass): int
1251 {
1252 parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
1253
1254 $solutions = $this->getSolutionValues($active_id, $pass);
1255
1256 $imagepath = $this->getImagePath();
1257 $i = 1;
1258 foreach ($solutions as $solution) {
1259 $matches_written = false;
1260 foreach ($this->getMatchingPairs() as $idx => $pair) {
1261 if (!$matches_written) {
1262 $worksheet->setCell($startrow + $i, 1, $this->lng->txt("matches"));
1263 }
1264 $matches_written = true;
1265 if ($pair->getDefinition()->getIdentifier() == $solution["value2"]) {
1266 if (strlen($pair->getDefinition()->getText())) {
1267 $worksheet->setCell($startrow + $i, 0, $pair->getDefinition()->getText());
1268 } else {
1269 $worksheet->setCell($startrow + $i, 0, $pair->getDefinition()->getPicture());
1270 }
1271 }
1272 if ($pair->getTerm()->getIdentifier() == $solution["value1"]) {
1273 if (strlen($pair->getTerm()->getText())) {
1274 $worksheet->setCell($startrow + $i, 2, $pair->getTerm()->getText());
1275 } else {
1276 $worksheet->setCell($startrow + $i, 2, $pair->getTerm()->getPicture());
1277 }
1278 }
1279 }
1280 $i++;
1281 }
1282
1283 return $startrow + $i + 1;
1284 }
1285
1291 public function getThumbGeometry(): int
1292 {
1293 return $this->thumb_geometry;
1294 }
1295
1301 public function getThumbSize(): int
1302 {
1303 return $this->getThumbGeometry();
1304 }
1305
1311 public function setThumbGeometry(int $a_geometry): void
1312 {
1313 $this->thumb_geometry = ($a_geometry < 1) ? 100 : $a_geometry;
1314 }
1315
1319 public function rebuildThumbnails(): void
1320 {
1321 foreach ($this->terms as $term) {
1322 if (strlen($term->getPicture())) {
1323 $this->generateThumbForFile($this->getImagePath(), $term->getPicture());
1324 }
1325 }
1326 foreach ($this->definitions as $definition) {
1327 if (strlen($definition->getPicture())) {
1328 $this->generateThumbForFile($this->getImagePath(), $definition->getPicture());
1329 }
1330 }
1331 }
1332
1333 public function getThumbPrefix(): string
1334 {
1335 return "thumb.";
1336 }
1337
1338 protected function generateThumbForFile($path, $file): void
1339 {
1340 $filename = $path . $file;
1341 if (@file_exists($filename)) {
1342 $thumbpath = $path . $this->getThumbPrefix() . $file;
1343 $path_info = @pathinfo($filename);
1344 $ext = "";
1345 switch (strtoupper($path_info['extension'])) {
1346 case 'PNG':
1347 $ext = 'PNG';
1348 break;
1349 case 'GIF':
1350 $ext = 'GIF';
1351 break;
1352 default:
1353 $ext = 'JPEG';
1354 break;
1355 }
1356 ilShellUtil::convertImage($filename, $thumbpath, $ext, (string) $this->getThumbGeometry());
1357 }
1358 }
1359
1363 public function toJSON(): string
1364 {
1365 $result = [];
1366
1367 $result['id'] = $this->getId();
1368 $result['type'] = (string) $this->getQuestionType();
1369 $result['title'] = $this->getTitleForHTMLOutput();
1370 $result['question'] = $this->formatSAQuestion($this->getQuestion());
1371 $result['nr_of_tries'] = $this->getNrOfTries();
1372 $result['matching_mode'] = $this->getMatchingMode();
1373 $result['shuffle'] = true;
1374 $result['feedback'] = array(
1375 'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
1376 'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
1377 );
1378
1379 $this->setShuffler($this->randomGroup->shuffleArray(new RandomSeed()));
1380
1381 $terms = [];
1382 foreach ($this->getShuffler()->transform($this->getTerms()) as $term) {
1383 $terms[] = [
1384 "text" => $this->formatSAQuestion($term->getText()),
1385 "id" => $this->getId() . $term->getIdentifier()
1386 ];
1387 }
1388 $result['terms'] = $terms;
1389
1390 $this->setShuffler($this->randomGroup->shuffleArray(new RandomSeed()));
1391
1392 $definitions = [];
1393 foreach ($this->getShuffler()->transform($this->getDefinitions()) as $def) {
1394 $definitions[] = [
1395 "text" => $this->formatSAQuestion((string) $def->getText()),
1396 "id" => $this->getId() . $def->getIdentifier()
1397 ];
1398 }
1399 $result['definitions'] = $definitions;
1400
1401 // #10353
1402 $matchings = [];
1403 foreach ($this->getMatchingPairs() as $pair) {
1404 // fau: fixLmMatchingPoints - ignore matching pairs with 0 or negative points
1405 if ($pair->getPoints() <= 0) {
1406 continue;
1407 }
1408 // fau.
1409
1410 $pid = $pair->getDefinition()->getIdentifier();
1411 if ($this->getMatchingMode() == self::MATCHING_MODE_N_ON_N) {
1412 $pid .= '::' . $pair->getTerm()->getIdentifier();
1413 }
1414
1415 if (!isset($matchings[$pid]) || $matchings[$pid]["points"] < $pair->getPoints()) {
1416 $matchings[$pid] = [
1417 "term_id" => $this->getId() . $pair->getTerm()->getIdentifier(),
1418 "def_id" => $this->getId() . $pair->getDefinition()->getIdentifier(),
1419 "points" => (int) $pair->getPoints()
1420 ];
1421 }
1422 }
1423
1424 $result['matchingPairs'] = array_values($matchings);
1425
1426 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
1427 $result['mobs'] = $mobs;
1428
1429 $this->lng->loadLanguageModule('assessment');
1430 $result['reset_button_label'] = $this->lng->txt("reset_terms");
1431
1432 return json_encode($result);
1433 }
1434
1435 public function supportsJavascriptOutput(): bool
1436 {
1437 return true;
1438 }
1439
1440 public function supportsNonJsOutput(): bool
1441 {
1442 return false;
1443 }
1444
1445 public function setMatchingMode($matchingMode): void
1446 {
1447 $this->matchingMode = $matchingMode;
1448 }
1449
1450 public function getMatchingMode(): string
1451 {
1452 return $this->matchingMode;
1453 }
1454
1459 protected function calculateReachedPointsForSolution($found_values): float
1460 {
1461 $points = 0;
1462 if (! is_array($found_values)) {
1463 return $points;
1464 }
1465 foreach ($found_values as $definition => $terms) {
1466 if (!is_array($terms)) {
1467 continue;
1468 }
1469 foreach ($terms as $term) {
1470 foreach ($this->matchingpairs as $pair) {
1471 if ($pair->getDefinition()->getIdentifier() == $definition && $pair->getTerm()->getIdentifier() == $term) {
1472 $points += $pair->getPoints();
1473 }
1474 }
1475 }
1476 }
1477 return $points;
1478 }
1479
1488 public function getOperators($expression): array
1489 {
1491 }
1492
1497 public function getExpressionTypes(): array
1498 {
1499 return array(
1504 );
1505 }
1514 public function getUserQuestionResult($active_id, $pass): ilUserQuestionResult
1515 {
1517 global $DIC;
1518 $ilDB = $DIC['ilDB'];
1519 $result = new ilUserQuestionResult($this, $active_id, $pass);
1520
1521 $data = $ilDB->queryF(
1522 "SELECT ident FROM qpl_a_mdef WHERE question_fi = %s ORDER BY def_id",
1523 array("integer"),
1524 array($this->getId())
1525 );
1526
1527 $definitions = array();
1528 for ($index = 1; $index <= $ilDB->numRows($data); ++$index) {
1529 $row = $ilDB->fetchAssoc($data);
1530 $definitions[$row["ident"]] = $index;
1531 }
1532
1533 $data = $ilDB->queryF(
1534 "SELECT ident FROM qpl_a_mterm WHERE question_fi = %s ORDER BY term_id",
1535 array("integer"),
1536 array($this->getId())
1537 );
1538
1539 $terms = array();
1540 for ($index = 1; $index <= $ilDB->numRows($data); ++$index) {
1541 $row = $ilDB->fetchAssoc($data);
1542 $terms[$row["ident"]] = $index;
1543 }
1544
1545 $maxStep = $this->lookupMaxStep($active_id, $pass);
1546
1547 if ($maxStep !== null) {
1548 $data = $ilDB->queryF(
1549 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s",
1550 array("integer", "integer", "integer","integer"),
1551 array($active_id, $pass, $this->getId(), $maxStep)
1552 );
1553 } else {
1554 $data = $ilDB->queryF(
1555 "SELECT value1, value2 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
1556 array("integer", "integer", "integer"),
1557 array($active_id, $pass, $this->getId())
1558 );
1559 }
1560
1561 while ($row = $ilDB->fetchAssoc($data)) {
1562 if ($row["value1"] > 0) {
1563 $result->addKeyValue($definitions[$row["value2"]], $terms[$row["value1"]]);
1564 }
1565 }
1566
1567 $points = $this->calculateReachedPoints($active_id, $pass);
1568 $max_points = $this->getMaximumPoints();
1569
1570 $result->setReachedPercentage(($points / $max_points) * 100);
1571
1572 return $result;
1573 }
1574
1581 public function getAvailableAnswerOptions($index = null)
1582 {
1583 if ($index !== null) {
1584 return $this->getMatchingPair($index);
1585 } else {
1586 return $this->getMatchingPairs();
1587 }
1588 }
1589
1593 protected function afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId): void
1594 {
1595 parent::afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId);
1596
1597 $origImagePath = $this->buildImagePath($origQuestionId, $origParentObjId);
1598 $dupImagePath = $this->buildImagePath($dupQuestionId, $dupParentObjId);
1599
1600 ilFileUtils::delDir($origImagePath);
1601 if (is_dir($dupImagePath)) {
1602 ilFileUtils::makeDirParents($origImagePath);
1603 ilFileUtils::rCopy($dupImagePath, $origImagePath);
1604 }
1605 }
1606
1607 protected function createMatchingTerm(string $term = '', string $picture = '', int $identifier = 0): assAnswerMatchingTerm
1608 {
1609 return new assAnswerMatchingTerm($term, $picture, $identifier);
1610 }
1611 protected function createMatchingDefinition(string $term = '', string $picture = '', int $identifier = 0): assAnswerMatchingDefinition
1612 {
1613 return new assAnswerMatchingDefinition($term, $picture, $identifier);
1614 }
1615 protected function createMatchingPair(
1616 assAnswerMatchingTerm $term = null,
1617 assAnswerMatchingDefinition $definition = null,
1618 float $points = 0.0
1620 $term = $term ?? $this->createMatchingTerm();
1621 $definition = $definition ?? $this->createMatchingDefinition();
1622 return new assAnswerMatchingPair($term, $definition, $points);
1623 }
1624}
$filename
Definition: buildRTE.php:78
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...
Class for matching questions.
deleteDefinition($position)
Deletes a definition.
getEncryptedFilename($filename)
Returns the encrypted save filename of a matching picture Images are saved with an encrypted filename...
__construct( $title="", $comment="", $author="", $owner=-1, $question="", $matching_type=MT_TERMS_DEFINITIONS)
assMatchingQuestion constructor
getMatchingPairCount()
Returns the number of matching pairs.
calculateReachedPointsForSolution($found_values)
addDefinition($definition)
Adds a definition.
getMaximumPoints()
Calculates and Returns the maximum points, a learner can reach answering the question.
setThumbGeometry(int $a_geometry)
Set the thumbnail geometry.
savePreviewData(ilAssQuestionPreviewSession $previewSession)
copyObject($target_questionpool_id, $title="")
Copies an assMatchingQuestion.
toJSON()
Returns a JSON representation of the question.
getOperators($expression)
Get all available operations for a specific question.
getDefinitionCount()
Returns the number of definitions.
getDefinitions()
Returns the definitions of the matching question.
getMatchingPair($index=0)
Returns a matching pair with a given index.
createMatchingDefinition(string $term='', string $picture='', int $identifier=0)
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
getQuestionType()
Returns the question type of the question.
isComplete()
Returns true, if a matching question is complete for use.
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
& getMatchingPairs()
Returns the matchingpairs array.
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
rebuildThumbnails()
Rebuild the thumbnail images with a new thumbnail size.
insertDefinition($position, assAnswerMatchingDefinition $definition=null)
Inserts a definition.
duplicateImages($question_id, $objectId=null)
getTermCount()
Returns the number of terms.
getThumbGeometry()
Get the thumbnail geometry.
deleteTerm($position)
Deletes a term.
checkSubmittedMatchings($submittedMatchings)
createMatchingTerm(string $term='', string $picture='', int $identifier=0)
getTerms()
Returns the terms of the matching question.
createMatchingPair(assAnswerMatchingTerm $term=null, assAnswerMatchingDefinition $definition=null, float $points=0.0)
flushDefinitions()
Deletes all definitions.
fetchIndexedValuesFromValuePairs(array $valuePairs)
loadFromDb($question_id)
Loads a assMatchingQuestion object from a database.
getDefinitionWithIdentifier($a_identifier)
Returns a definition with a given identifier.
insertTerm($position, assAnswerMatchingTerm $term=null)
Inserts a term.
flushTerms()
Deletes all terms.
copyImages($question_id, $source_questionpool)
flushMatchingPairs()
Deletes all matching pairs.
saveToDb($original_id="")
Saves a assMatchingQuestion object to a database.
addTerm(assAnswerMatchingTerm $term)
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
setImageFile($image_tempfilename, $image_filename, $previous_filename='')
Sets the image file and uploads the image to the object's image directory.
getThumbSize()
Get the thumbnail geometry.
getTermWithIdentifier($a_identifier)
Returns a term with a given identifier.
addMatchingPair(assAnswerMatchingTerm $term=null, assAnswerMatchingDefinition $definition=null, $points=0.0)
Adds an matching pair for an matching choice question.
setTerm($term, $index)
Sets a specific term.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
deleteImagefile(string $filename)
Deletes an imagefile from the system if the file is deleted manually.
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
duplicate(bool $for_test=true, string $title="", string $author="", string $owner="", $testObjId=null)
Duplicates an assMatchingQuestion.
afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
{}
getExpressionTypes()
Get all available expression types for a specific question.
setExportDetailsXLS(ilAssExcelFormatHelper $worksheet, int $startrow, int $active_id, int $pass)
{}
deleteMatchingPair($index=0)
Deletes a matching pair with a given index.
insertMatchingPair($position, $term=null, $definition=null, $points=0.0)
Inserts a matching pair for an matching choice question.
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
Abstract basic class which is to be extended by the concrete assessment question type classes.
float $points
The maximum available points for the question.
setOriginalId(?int $original_id)
string $question
The question text.
static logAction(string $logtext, int $active_id, int $question_id)
setId(int $id=-1)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
static isFileAvailable(string $file)
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
getSolutionValues($active_id, $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
setQuestion(string $question="")
buildImagePath($questionId, $parentObjectId)
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
static _getOriginalId(int $question_id)
ILIAS DI LoggingServices $ilLog
saveQuestionDataToDb(int $original_id=-1)
setAuthor(string $author="")
bool $shuffle
Indicates whether the answers will be shuffled or not.
setComment(string $comment="")
setObjId(int $obj_id=0)
getSolutionMaxPass(int $active_id)
setOwner(int $owner=-1)
setNrOfTries(int $a_nr_of_tries)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
setTitle(string $title="")
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
setShuffler(Transformation $shuffler)
lookupMaxStep(int $active_id, int $pass)
setPoints(float $points)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setCell($a_row, $a_col, $a_value, $datatype=null)
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
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 rCopy(string $a_sdir, string $a_tdir, bool $preserveTimeAttributes=false)
Copies content of a directory $a_sdir recursively to a directory $a_tdir.
static _getMobsOfObject(string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
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...
static convertImage(string $a_from, string $a_to, string $a_target_format="", string $a_geometry="", string $a_background_color="")
convert image
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...
global $DIC
Definition: feed.php:28
$mobs
Definition: imgupload.php:70
const MT_TERMS_DEFINITIONS
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
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...
$path
Definition: ltiservices.php:32
$post
Definition: ltitoken.php:49
$index
Definition: metadata.php:145
$i
Definition: metadata.php:41
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
string $key
Consumer key/client ID value.
Definition: System.php:193
$query