ILIAS  trunk Revision v11.0_alpha-1723-g8e69f309bab
All Data Structures Namespaces Files Functions Variables Enumerations Enumerator Modules Pages
class.assLongMenu.php
Go to the documentation of this file.
1 <?php
2 
19 declare(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 = '';
39  private int $minAutoComplete = self::MIN_LENGTH_AUTOCOMPLETE;
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  {
97  return $this->long_menu_text;
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  {
115  return $this->json_structure;
116  }
117 
121  private function setJsonStructure(string $json_structure): void
122  {
123  $this->json_structure = $json_structure;
124  }
125 
126  public function setSpecificFeedbackSetting($specificFeedbackSetting): void
127  {
128  $this->specificFeedbackSetting = $specificFeedbackSetting;
129  }
130 
131  public function getSpecificFeedbackSetting(): int
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  {
143  return $this->minAutoComplete;
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']);
394  } catch (ilTestQuestionPoolException $e) {
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  {
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
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 }
lookupForExistingSolutions(int $activeId, int $pass)
Lookup if an authorized or intermediate solution exists.
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
setNrOfTries(int $a_nr_of_tries)
correctAnswerDoesNotExistInAnswerOptions($answers, $answer_options)
lmMigrateQuestionTypeSpecificContent(ilAssSelfAssessmentMigrator $migrator)
calculateReachedPoints(int $active_id, ?int $pass=null, bool $authorized_solution=true)
$res
Definition: ltiservices.php:66
setCorrectAnswers(array $correct_answers)
getCorrectAnswersForQuestionSolution($question_id)
savePreviewData(ilAssQuestionPreviewSession $preview_session)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
calculateReachedPointsForSolution(?array $found_values, int $active_id=0)
getCorrectAnswersForGap($question_id, $gap_id)
getCorrectSolutionForTextOutput(int $active_id, int $pass)
saveWorkingData(int $active_id, ?int $pass=null, bool $authorized=true)
setOwner(int $owner=-1)
solutionValuesToLog(AdditionalInformationGenerator $additional_info, array $solution_values)
checkQuestionCustomPart($form=null)
setAnswerType(array $answerType)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setSpecificFeedbackSetting($specificFeedbackSetting)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getCorrectAnswersForLog(AdditionalInformationGenerator $additional_info)
$c
Definition: deliver.php:25
loadCorrectAnswerData($question_id)
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
setComment(string $comment="")
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
int $specificFeedbackSetting
const MIN_LENGTH_AUTOCOMPLETE
const ANSWER_TYPE_TEXT_VAL
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
getUserQuestionResult($active_id, $pass)
Get the user solution for a question by active_id and the test pass.
string $json_structure
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
loadFromDb($question_id)
saveToDb(?int $original_id=null)
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
toLog(AdditionalInformationGenerator $additional_info)
getAnswersForLog(AdditionalInformationGenerator $additional_info)
setAnswers(array $answers)
setLongMenuTextValue(string $long_menu_text='')
toJSON()
Returns a JSON representation of the question.
string $long_menu_text
setMinAutoComplete(int $min_auto_complete)
setPoints(float $points)
setObjId(int $obj_id=0)
saveQuestionDataToDb(?int $original_id=null)
static getDataDir()
get data directory (outside webspace)
getPointsForGap($question_id, $gap_id)
static _getMobsOfObject(string $a_type, int $a_id, int $a_usage_hist_nr=0, string $a_lang="-")
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
const HAS_SPECIFIC_FEEDBACK
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
solutionValuesToText(array $solution_values)
getSolutionMaxPass(int $active_id)
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
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)
getQuestionType()
Returns the question type of the question.
setTitle(string $title="")
setIdenticalScoring(bool $identical_scoring)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
clearAnswerSpecificDataFromDb(int $question_id)
setJsonStructure(string $json_structure)
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
setAuthor(string $author="")
clearFolder($let_folder_exists=true)
const ANSWER_TYPE_SELECT_VAL
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
buildFileName($gap_id)
setQuestion(string $question="")