ILIAS  trunk Revision v11.0_alpha-3011-gc6b235a2e85
class.assLongMenu.php
Go to the documentation of this file.
1<?php
2
19declare(strict_types=1);
20
24
26{
27 public const ANSWER_TYPE_SELECT_VAL = 0;
28 public const ANSWER_TYPE_TEXT_VAL = 1;
29 public const GAP_PLACEHOLDER = 'Longmenu';
30 public const MIN_LENGTH_AUTOCOMPLETE = 3;
31 public const MAX_INPUT_FIELDS = 500;
32
33 protected const HAS_SPECIFIC_FEEDBACK = false;
34
35 private ?array $answerType = null;
36 private string $long_menu_text = '';
37 private string $json_structure = '';
40 private bool $identical_scoring = true;
41
42 private array $correct_answers = [];
43 private array $answers = [];
44
45
46 public function getAnswerType(): ?array
47 {
48 return $this->answerType;
49 }
50
51 public function setAnswerType(array $answerType): void
52 {
53 $this->answerType = $answerType;
54 }
55
59 public function getCorrectAnswers()
60 {
62 }
63
64
65 public function setCorrectAnswers(array $correct_answers): void
66 {
67 $this->correct_answers = $correct_answers;
68 }
69
70 private function buildFolderName(): string
71 {
72 return ilFileUtils::getDataDir() . '/assessment/longMenuQuestion/' . $this->getId() . '/' ;
73 }
74
75 public function getAnswerTableName(): string
76 {
77 return "qpl_a_lome";
78 }
79
80 private function buildFileName($gap_id): ?string
81 {
82 try {
83 $this->assertDirExists();
84 return $this->buildFolderName() . $gap_id . '.txt';
85 } catch (ilException $e) {
86 }
87 return null;
88 }
89
90 public function setLongMenuTextValue(string $long_menu_text = ''): void
91 {
92 $this->long_menu_text = $this->getHtmlQuestionContentPurifier()->purify($long_menu_text);
93 }
94
95 public function getLongMenuTextValue(): string
96 {
98 }
99
100 public function setAnswers(array $answers): void
101 {
102 $this->answers = $answers;
103 }
104
105 public function getAnswers(): array
106 {
107 return $this->answers;
108 }
109
113 public function getJsonStructure(): string
114 {
116 }
117
121 private function setJsonStructure(string $json_structure): void
122 {
123 $this->json_structure = $json_structure;
124 }
125
127 {
128 $this->specificFeedbackSetting = $specificFeedbackSetting;
129 }
130
132 {
134 }
135
136 public function setMinAutoComplete(int $min_auto_complete): void
137 {
138 $this->minAutoComplete = $min_auto_complete;
139 }
140
141 public function getMinAutoComplete(): int
142 {
144 }
145
146 public function isComplete(): bool
147 {
148 if (strlen($this->title)
149 && $this->author
150 && $this->long_menu_text
151 && sizeof($this->answers) > 0
152 && sizeof($this->correct_answers) > 0
153 && $this->getPoints() > 0
154 ) {
155 return true;
156 }
157 return false;
158 }
159
160 public function saveToDb(?int $original_id = null): void
161 {
165 parent::saveToDb();
166 }
167
172 public function checkQuestionCustomPart($form = null): bool
173 {
174 $hidden_text_files = $this->getAnswers();
175 $correct_answers = $this->getCorrectAnswers();
176 $points = [];
177 if ($correct_answers === null
178 || $correct_answers === []
179 || $hidden_text_files === null
180 || $hidden_text_files === []) {
181 return false;
182 }
183 if (sizeof($correct_answers) != sizeof($hidden_text_files)) {
184 return false;
185 }
186 foreach ($correct_answers as $key => $correct_answers_row) {
187 if ($this->correctAnswerDoesNotExistInAnswerOptions($correct_answers_row, $hidden_text_files[$key])) {
188 return false;
189 }
190 if (!is_array($correct_answers_row[0]) || $correct_answers_row[0] === []) {
191 return false;
192 }
193 if ($correct_answers_row[1] > 0) {
194 array_push($points, $correct_answers_row[1]);
195 }
196 }
197 if (sizeof($correct_answers) != sizeof($points)) {
198 return false;
199 }
200
201 foreach ($points as $row) {
202 if ($row <= 0) {
203 return false;
204 }
205 }
206 return true;
207 }
208
214 private function correctAnswerDoesNotExistInAnswerOptions($answers, $answer_options): bool
215 {
216 foreach ($answers[0] as $key => $answer) {
217 if (!in_array($answer, $answer_options)) {
218 return true;
219 }
220 }
221 return false;
222 }
223
224
231 public function getMaximumPoints(): float
232 {
233 $sum = 0;
234 $points = $this->getCorrectAnswers();
235 if ($points) {
236 foreach ($points as $add) {
237 $sum += (float) $add[1];
238 }
239 }
240 return $sum;
241 }
242
244 {
245 // save additional data
246 $this->db->manipulateF(
247 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
248 [ "integer" ],
249 [ $this->getId() ]
250 );
251 $this->db->manipulateF(
252 "INSERT INTO " . $this->getAdditionalTableName(
253 ) . " (question_fi, long_menu_text, feedback_setting, min_auto_complete, identical_scoring) VALUES (%s, %s, %s, %s, %s)",
254 [ "integer", "text", "integer", "integer", "integer"],
255 [
256 $this->getId(),
257 $this->getLongMenuTextValue(),
259 $this->getMinAutoComplete(),
260 $this->getIdenticalScoring()
261 ]
262 );
263
264 $this->createFileFromArray();
265 }
266
267 public function saveAnswerSpecificDataToDb(): void
268 {
269 $this->clearAnswerSpecificDataFromDb($this->getId());
270 $type_array = $this->getAnswerType();
271 $points = 0;
272 foreach ($this->getCorrectAnswers() as $gap_number => $gap) {
273 foreach ($gap[0] as $position => $answer) {
274 if ($type_array == null) {
275 $type = $gap[2];
276 } else {
277 $type = $type_array[$gap_number];
278 }
279 $this->db->replace(
280 $this->getAnswerTableName(),
281 [
282 'question_fi' => ['integer', $this->getId()],
283 'gap_number' => ['integer', (int) $gap_number],
284 'position' => ['integer', (int) $position]
285 ],
286 [
287 'answer_text' => ['text', $answer],
288 'points' => ['float', $gap[1]],
289 'type' => ['integer', (int) $type]
290 ]
291 );
292 }
293 $points += $gap[1];
294 }
295 $this->setPoints($points);
296 }
297
298 private function createFileFromArray(): void
299 {
300 $array = $this->getAnswers();
301 $this->clearFolder();
302 foreach ($array as $gap => $values) {
303 $file_content = '';
304 if (is_array($values)) {
305 foreach ($values as $key => $value) {
306 $file_content .= $value . "\n";
307 }
308 $file_content = rtrim($file_content, "\n");
309 $file = fopen($this->buildFileName($gap), "w");
310 fwrite($file, $file_content);
311 fclose($file);
312 }
313 }
314 }
315
316 private function createArrayFromFile(): array
317 {
318 $files = glob($this->buildFolderName() . '*.txt');
319
320 if ($files === false) {
321 $files = [];
322 }
323
324 $answers = [];
325
326 foreach ($files as $file) {
327 $gap = str_replace('.txt', '', basename($file));
328 $answers[(int) $gap] = explode("\n", file_get_contents($file));
329 }
330 // Sort by gap keys, to ensure the numbers are in ascending order.
331 // Glob will report the keys in files order like 0, 1, 10, 11, 2,...
332 // json_encoding the array with keys in order 0,1,10,11,2,.. will create
333 // a json_object instead of a list when keys are numeric, sorted and start with 0
334 ksort($answers);
335 $this->setAnswers($answers);
336 return $answers;
337 }
338
339 private function clearFolder($let_folder_exists = true): void
340 {
341 ilFileUtils::delDir($this->buildFolderName(), $let_folder_exists);
342 }
343
344 private function assertDirExists(): void
345 {
346 $folder_name = $this->buildFolderName();
347 if (!ilFileUtils::makeDirParents($folder_name)) {
348 throw new ilException('Cannot create export directory');
349 }
350
351 if (
352 !is_dir($folder_name) ||
353 !is_readable($folder_name) ||
354 !is_writable($folder_name)
355 ) {
356 throw new ilException('Cannot create export directory');
357 }
358 }
359
360 public function loadFromDb($question_id): void
361 {
362 $result = $this->db->queryF(
363 "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",
364 ["integer"],
365 [$question_id]
366 );
367 if ($result->numRows() == 1) {
368 $data = $this->db->fetchAssoc($result);
369 $this->setId($question_id);
370 $this->setObjId($data['obj_fi']);
371 $this->setNrOfTries($data['nr_of_tries']);
372 $this->setTitle((string) $data['title']);
373 $this->setComment((string) $data['description']);
374 $this->setOriginalId($data['original_id']);
375 $this->setAuthor($data['author']);
376 $this->setPoints($data['points']);
377 $this->setIdenticalScoring((bool) $data['identical_scoring']);
378 $this->setOwner($data['owner']);
379 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data['question_text'], 1));
380 $this->setLongMenuTextValue(ilRTE::_replaceMediaObjectImageSrc((string) $data['long_menu_text'], 1));
381 $this->setMinAutoComplete($data['min_auto_complete'] ?? self::MIN_LENGTH_AUTOCOMPLETE);
382 if (isset($data['feedback_setting'])) {
383 $this->setSpecificFeedbackSetting((int) $data['feedback_setting']);
384 }
385
386 try {
387 $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
390 }
391
392 try {
393 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
395 }
396 }
397
398 $this->loadCorrectAnswerData($question_id);
399 $this->createArrayFromFile();
400 parent::loadFromDb($question_id);
401 }
402
403 private function loadCorrectAnswerData($question_id): void
404 {
405 $res = $this->db->queryF(
406 "SELECT * FROM {$this->getAnswerTableName()} WHERE question_fi = %s ORDER BY gap_number, position ASC",
407 ['integer'],
408 [$question_id]
409 );
410
411 $correct_answers = [];
412 while ($data = $this->db->fetchAssoc($res)) {
413 $correct_answers[$data['gap_number']][0][$data['position']] = rtrim($data['answer_text']);
414 $correct_answers[$data['gap_number']][1] = $data['points'];
415 $correct_answers[$data['gap_number']][2] = $data['type'];
416 }
417 $this->setJsonStructure(json_encode($correct_answers));
418 $this->setCorrectAnswers($correct_answers);
419 }
420
421 public function getCorrectAnswersForQuestionSolution($question_id): array
422 {
423 $correct_answers = [];
424 $res = $this->db->queryF(
425 'SELECT gap_number, answer_text FROM ' . $this->getAnswerTableName() . ' WHERE question_fi = %s',
426 ['integer'],
427 [$question_id]
428 );
429 while ($data = $this->db->fetchAssoc($res)) {
430 if (array_key_exists($data['gap_number'], $correct_answers)) {
431 $correct_answers[$data['gap_number']] .= ' ' . $this->lng->txt("or") . ' ';
432 $correct_answers[$data['gap_number']] .= rtrim($data['answer_text']);
433 } else {
434 $correct_answers[$data['gap_number']] = rtrim($data['answer_text']);
435 }
436 }
437 return $correct_answers;
438 }
439
440 private function getCorrectAnswersForGap($question_id, $gap_id): array
441 {
442 $correct_answers = [];
443 $res = $this->db->queryF(
444 'SELECT answer_text FROM ' . $this->getAnswerTableName() . ' WHERE question_fi = %s AND gap_number = %s',
445 ['integer', 'integer'],
446 [$question_id, $gap_id]
447 );
448 while ($data = $this->db->fetchAssoc($res)) {
449 $correct_answers[] = rtrim($data['answer_text']);
450 }
451 return $correct_answers;
452 }
453
454 private function getPointsForGap($question_id, $gap_id): float
455 {
456 $points = 0.0;
457 $res = $this->db->queryF(
458 'SELECT points FROM ' . $this->getAnswerTableName() . ' WHERE question_fi = %s AND gap_number = %s GROUP BY gap_number, points',
459 ['integer', 'integer'],
460 [$question_id, $gap_id]
461 );
462 while ($data = $this->db->fetchAssoc($res)) {
463 $points = (float) $data['points'];
464 }
465 return $points;
466 }
467
468
469 public function getAnswersObject()
470 {
471 return json_encode($this->createArrayFromFile());
472 }
473
474 public function getCorrectAnswersAsJson()
475 {
476 $this->loadCorrectAnswerData($this->getId());
477 return $this->getJsonStructure();
478 }
479
480 public function calculateReachedPoints(
481 int $active_id,
482 ?int $pass = null,
483 bool $authorized_solution = true
484 ): float {
485 $found_values = [];
486 if (is_null($pass)) {
487 $pass = $this->getSolutionMaxPass($active_id);
488 }
489 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorized_solution);
490 while ($data = $this->db->fetchAssoc($result)) {
491 $found_values[(int) $data['value1']] = $data['value2'];
492 }
493
494 return $this->calculateReachedPointsForSolution($found_values, $active_id);
495 }
496
497 protected function calculateReachedPointsForSolution(?array $found_values, int $active_id = 0): float
498 {
499 if ($found_values == null) {
500 $found_values = [];
501 }
502 $points = 0.0;
503 $solution_values_text = [];
504 foreach ($found_values as $key => $answer) {
505 if ($answer === '') {
506 continue;
507 }
508
509 $correct_answers = $this->getCorrectAnswersForGap($this->id, $key);
510 if (!in_array($answer, $correct_answers)) {
511 continue;
512 }
513
514 $points_gap = $this->getPointsForGap($this->id, $key);
515 if (!$this->getIdenticalScoring()
516 && in_array($answer, $solution_values_text)
517 && ($points > 0)) {
518 $points_gap = 0;
519 }
520
521 $points += $points_gap;
522 array_push($solution_values_text, $answer);
523 }
524
525 return $points;
526 }
527
528 public function saveWorkingData(
529 int $active_id,
530 ?int $pass = null,
531 bool $authorized = true
532 ): bool {
533 if (is_null($pass)) {
534 $pass = ilObjTest::_getPass($active_id);
535 }
536
537 $answer = $this->getSolutionSubmit();
538 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
539 function () use ($answer, $active_id, $pass, $authorized) {
540 $this->removeCurrentSolution($active_id, $pass, $authorized);
541
542 foreach ($answer as $key => $value) {
543 if ($value === '') {
544 continue;
545 }
546 $this->saveCurrentSolution($active_id, $pass, $key, $value, $authorized);
547 }
548 }
549 );
550
551 return true;
552 }
553
554 // fau: testNav - overridden function lookupForExistingSolutions (specific for long menu question: ignore unselected values)
559 public function lookupForExistingSolutions(int $activeId, int $pass): array
560 {
561 $return = [
562 'authorized' => false,
563 'intermediate' => false
564 ];
565
566 $query = "
567 SELECT authorized, COUNT(*) cnt
568 FROM tst_solutions
569 WHERE active_fi = " . $this->db->quote($activeId, 'integer') . "
570 AND question_fi = " . $this->db->quote($this->getId(), 'integer') . "
571 AND pass = " . $this->db->quote($pass, 'integer') . "
572 AND value2 <> '-1'
573 ";
574
575 if ($this->getStep() !== null) {
576 $query .= " AND step = " . $this->db->quote((int) $this->getStep(), 'integer') . " ";
577 }
578
579 $query .= "
580 GROUP BY authorized
581 ";
582
583 $result = $this->db->query($query);
584
585 while ($row = $this->db->fetchAssoc($result)) {
586 if ($row['authorized']) {
587 $return['authorized'] = $row['cnt'] > 0;
588 } else {
589 $return['intermediate'] = $row['cnt'] > 0;
590 }
591 }
592 return $return;
593 }
594 // fau.
595
596
597 protected function getSolutionSubmit(): array
598 {
599 $solution_submit = [];
600 foreach ($this->questionpool_request->strArray('answer') as $key => $value) {
601 $solution_submit[$key] = $value;
602 }
603 return $solution_submit;
604 }
605
606 protected function savePreviewData(ilAssQuestionPreviewSession $preview_session): void
607 {
608 $answer = $this->questionpool_request->strArray('answer');
609 $preview_session->setParticipantsSolution(array_map(static fn($value) => trim($value), $answer));
610 }
611
617 public function getQuestionType(): string
618 {
619 return "assLongMenu";
620 }
621
622 public function getAdditionalTableName(): string
623 {
624 return 'qpl_qst_lome';
625 }
626
631 public function getRTETextWithMediaObjects(): string
632 {
633 return parent::getRTETextWithMediaObjects() . $this->getLongMenuTextValue();
634 }
635
644 public function getUserQuestionResult($active_id, $pass): ilUserQuestionResult
645 {
646 $result = new ilUserQuestionResult($this, $active_id, $pass);
647
648 $points = $this->calculateReachedPoints($active_id, $pass);
649 $max_points = $this->getMaximumPoints();
650
651 $result->setReachedPercentage(($points / $max_points) * 100);
652
653 return $result;
654 }
655
664 public function getAvailableAnswerOptions($index = null)
665 {
666 return $this->createArrayFromFile();
667 }
668
669 public function isShuffleAnswersEnabled(): bool
670 {
671 return false;
672 }
673
674 public function clearAnswerSpecificDataFromDb(int $question_id): void
675 {
676 $this->db->manipulateF(
677 'DELETE FROM ' . $this->getAnswerTableName() . ' WHERE question_fi = %s',
678 [ 'integer' ],
679 [ $question_id ]
680 );
681 }
682
683 public function delete(int $question_id): void
684 {
685 parent::delete($question_id);
686 $this->clearFolder(false);
687 }
688
693 {
694 $this->setLongMenuTextValue($migrator->migrateToLmContent($this->getLongMenuTextValue()));
695 }
696
700 public function toJSON(): string
701 {
702 $result = [];
703 $result['id'] = $this->getId();
704 $result['type'] = (string) $this->getQuestionType();
705 $result['title'] = $this->getTitleForHTMLOutput();
706 $result['question'] = $this->formatSAQuestion($this->getQuestion());
707 $replaced_quesiton_text = $this->getLongMenuTextValue();
708 $result['lmtext'] = $this->formatSAQuestion($replaced_quesiton_text);
709 $result['nr_of_tries'] = $this->getNrOfTries();
710 $result['shuffle'] = $this->getShuffle();
711 $result['feedback'] = [
712 'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
713 'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
714 ];
715
716 $mobs = ilObjMediaObject::_getMobsOfObject("qpl:html", $this->getId());
717 $result['answers'] = $this->getAnswers();
718 $result['correct_answers'] = $this->getCorrectAnswers();
719 $result['mobs'] = $mobs;
720 return json_encode($result);
721 }
722
723 public function getIdenticalScoring(): bool
724 {
725 return $this->identical_scoring;
726 }
727
728 public function setIdenticalScoring(bool $identical_scoring): void
729 {
730 $this->identical_scoring = $identical_scoring;
731 }
732
733 public function toLog(AdditionalInformationGenerator $additional_info): array
734 {
735 return [
736 AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->getQuestionType(),
737 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $this->getTitleForHTMLOutput(),
738 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $this->formatSAQuestion($this->getQuestion()),
739 AdditionalInformationGenerator::KEY_QUESTION_LONGMENU_TEXT => $this->formatSAQuestion($this->getLongMenuTextValue()),
740 AdditionalInformationGenerator::KEY_QUESTION_SHUFFLE_ANSWER_OPTIONS => $additional_info
741 ->getTrueFalseTagForBool($this->getShuffle()),
742 AdditionalInformationGenerator::KEY_FEEDBACK => [
743 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), false)),
744 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(), true))
745 ],
746 AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTIONS => $this->getAnswersForLog($additional_info),
747 AdditionalInformationGenerator::KEY_QUESTION_CORRECT_ANSWER_OPTIONS => $this->getCorrectAnswersForLog($additional_info)
748 ];
749 }
750
751 private function getAnswersForLog(AdditionalInformationGenerator $additional_info): string
752 {
753 $i = 1;
754 return array_reduce(
755 $this->getAnswers(),
756 static function (string $c, array $v) use ($additional_info, &$i): string {
757 return $c . $additional_info->getTagForLangVar('gap')
758 . ' ' . $i++ . ': ' . implode(',', $v) . '; ';
759 },
760 ''
761 );
762 }
763
764 private function getCorrectAnswersForLog(AdditionalInformationGenerator $additional_info): string
765 {
766 $answer_types = [
767 self::ANSWER_TYPE_SELECT_VAL => $additional_info->getTagForLangVar('answers_select'),
768 self::ANSWER_TYPE_TEXT_VAL => $additional_info->getTagForLangVar('answers_text_box')
769 ];
770
771 $i = 1;
772 return array_reduce(
773 $this->getCorrectAnswers(),
774 static function (string $c, array $v) use ($additional_info, $answer_types, &$i): string {
775 return $c . $additional_info->getTagForLangVar('gap')
776 . ' ' . $i++ . ': ' . implode(',', $v[0]) . ', '
777 . $additional_info->getTagForLangVar('points') . ': ' . $v[1] . ', '
778 . $additional_info->getTagForLangVar('type') . ': ' . $answer_types[$v[2]] . '; ';
779 },
780 ''
781 );
782 }
783
784 protected function solutionValuesToLog(
785 AdditionalInformationGenerator $additional_info,
786 array $solution_values
787 ): array {
788 $parsed_solution = [];
789 foreach ($this->getCorrectAnswers() as $gap_index => $gap) {
790 foreach ($solution_values as $solution) {
791 if ($gap_index !== (int) $solution['value1']) {
792 continue;
793 }
794 $value = $solution['value2'];
795 if ($gap[2] === self::ANSWER_TYPE_SELECT_VAL
796 && $value === '-1') {
797 $value = '';
798 }
799 $parsed_solution[$gap_index + 1] = $value;
800 break;
801 }
802 }
803 return $parsed_solution;
804 }
805
806 public function solutionValuesToText(array $solution_values): array
807 {
808 $parsed_solution = [];
809
810 foreach ($this->getCorrectAnswers() as $gap_index => $gap) {
811 foreach ($solution_values as $solution) {
812 if ($gap_index !== (int) $solution['value1']) {
813 continue;
814 }
815 $value = $solution['value2'];
816 if ($gap[2] === self::ANSWER_TYPE_SELECT_VAL
817 && $value === '-1') {
818 $value = '';
819 }
820 $parsed_solution[] = $this->lng->txt('gap') . ' ' . $gap_index + 1 . ': ' . $value;
821 break;
822 }
823 }
824 return $parsed_solution;
825 }
826
827 public function getCorrectSolutionForTextOutput(int $active_id, int $pass): array
828 {
829 $correct_answers = [];
830 foreach ($this->getCorrectAnswers() as $gap_index => $gap) {
831 $correct_answers[] = $this->lng->txt('gap')
832 . ' ' . $gap_index . ': ' . implode(',', $gap[0]);
833 }
834 return $correct_answers;
835 }
836}
getCorrectAnswersForLog(AdditionalInformationGenerator $additional_info)
lmMigrateQuestionTypeSpecificContent(ilAssSelfAssessmentMigrator $migrator)
saveWorkingData(int $active_id, ?int $pass=null, bool $authorized=true)
loadCorrectAnswerData($question_id)
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
string $json_structure
checkQuestionCustomPart($form=null)
calculateReachedPoints(int $active_id, ?int $pass=null, bool $authorized_solution=true)
const MIN_LENGTH_AUTOCOMPLETE
solutionValuesToLog(AdditionalInformationGenerator $additional_info, array $solution_values)
MUST convert the given solution values into an array or a string that can be stored in the log.
setAnswerType(array $answerType)
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
saveToDb(?int $original_id=null)
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
calculateReachedPointsForSolution(?array $found_values, int $active_id=0)
int $specificFeedbackSetting
getCorrectAnswersForGap($question_id, $gap_id)
const ANSWER_TYPE_TEXT_VAL
string $long_menu_text
clearAnswerSpecificDataFromDb(int $question_id)
buildFileName($gap_id)
setAnswers(array $answers)
getQuestionType()
Returns the question type of the question.
savePreviewData(ilAssQuestionPreviewSession $preview_session)
const ANSWER_TYPE_SELECT_VAL
getAnswersForLog(AdditionalInformationGenerator $additional_info)
toJSON()
Returns a JSON representation of the question.
getPointsForGap($question_id, $gap_id)
clearFolder($let_folder_exists=true)
loadFromDb($question_id)
getCorrectSolutionForTextOutput(int $active_id, int $pass)
setJsonStructure(string $json_structure)
setSpecificFeedbackSetting($specificFeedbackSetting)
setLongMenuTextValue(string $long_menu_text='')
const HAS_SPECIFIC_FEEDBACK
correctAnswerDoesNotExistInAnswerOptions($answers, $answer_options)
setMinAutoComplete(int $min_auto_complete)
solutionValuesToText(array $solution_values)
MUST convert the given solution values into text.
toLog(AdditionalInformationGenerator $additional_info)
MUST return an array of the question settings that can be stored in the log.
getCorrectAnswersForQuestionSolution($question_id)
lookupForExistingSolutions(int $activeId, int $pass)
Lookup if an authorized or intermediate solution exists.
setIdenticalScoring(bool $identical_scoring)
setCorrectAnswers(array $correct_answers)
setOriginalId(?int $original_id)
setId(int $id=-1)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
setQuestion(string $question="")
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
setAuthor(string $author="")
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="")
saveQuestionDataToDb(?int $original_id=null)
setPoints(float $points)
Base class for ILIAS Exception handling.
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 getDataDir()
get data directory (outside webspace)
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...
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$c
Definition: deliver.php:25
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...
$res
Definition: ltiservices.php:69
if(!file_exists('../ilias.ini.php'))