ILIAS  release_9 Revision v9.13-25-g2c18ec4c24f
class.assTextQuestion.php
Go to the documentation of this file.
1 <?php
2 
19 require_once './Modules/Test/classes/inc.AssessmentConstants.php';
20 
35 {
36  protected const HAS_SPECIFIC_FEEDBACK = false;
45 
50 
59  public $keywords;
60 
61  public $answers;
62 
68  public $text_rating;
69 
70  /* method for automatic string matching */
71  private $matchcondition;
72 
73  public $keyword_relation = 'non';
74 
87  public function __construct(
88  $title = "",
89  $comment = "",
90  $author = "",
91  $owner = -1,
92  $question = ""
93  ) {
95  $this->wordCounterEnabled = false;
96  $this->maxNumOfChars = 0;
97  $this->points = 1;
98  $this->answers = [];
99  $this->matchcondition = 0;
100  }
101 
102  public function getMatchcondition(): int
103  {
104  return $this->matchcondition;
105  }
106 
107  public function setMatchcondition(int $matchcondition): void
108  {
109  $this->matchcondition = $matchcondition;
110  }
111 
117  public function isComplete(): bool
118  {
119  if (strlen($this->title)
120  && $this->author
121  && $this->question
122  && $this->getMaximumPoints() > 0
123  ) {
124  return true;
125  }
126  return false;
127  }
128 
134  public function saveToDb($original_id = ""): void
135  {
136  if ($original_id == '') {
137  $this->saveQuestionDataToDb();
138  } else {
140  }
141 
144  parent::saveToDb();
145  }
146 
154  public function loadFromDb($question_id): void
155  {
156  global $DIC;
157  $ilDB = $DIC['ilDB'];
158 
159  $result = $ilDB->queryF(
160  "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",
161  ["integer"],
162  [$question_id]
163  );
164  if ($ilDB->numRows($result) == 1) {
165  $data = $ilDB->fetchAssoc($result);
166  $this->setId($question_id);
167  $this->setObjId($data["obj_fi"]);
168  $this->setTitle((string) $data["title"]);
169  $this->setComment((string) $data["description"]);
170  $this->setOriginalId($data["original_id"]);
171  $this->setNrOfTries($data['nr_of_tries']);
172  $this->setAuthor($data["author"]);
173  $this->setPoints((float) $data["points"]);
174  $this->setOwner($data["owner"]);
175  $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data["question_text"], 1));
176  $this->setShuffle(false);
177  $this->setWordCounterEnabled((bool) $data['word_cnt_enabled']);
178  $this->setMaxNumOfChars($data["maxnumofchars"] ?? 0);
179  $this->setTextRating($this->isValidTextRating($data["textgap_rating"]) ? $data["textgap_rating"] : TEXTGAP_RATING_CASEINSENSITIVE);
180  $this->matchcondition = (isset($data['matchcondition'])) ? (int) $data['matchcondition'] : 0;
181  $this->setKeywordRelation(($data['keyword_relation']));
182 
183  try {
184  $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
187  }
188 
189  try {
190  $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
191  } catch (ilTestQuestionPoolException $e) {
192  }
193  }
194 
195  $result = $ilDB->queryF(
196  "SELECT * FROM qpl_a_essay WHERE question_fi = %s",
197  ['integer'],
198  [$this->getId()]
199  );
200 
201  $this->flushAnswers();
202  while ($row = $ilDB->fetchAssoc($result)) {
203  $this->addAnswer($row['answertext'], $row['points']);
204  }
205 
206  parent::loadFromDb($question_id);
207  }
208 
214  public function duplicate(bool $for_test = true, string $title = "", string $author = "", int $owner = -1, $testObjId = null): int
215  {
216  if ($this->id <= 0) {
217  // The question has not been saved. It cannot be duplicated
218  return -1;
219  }
220  // duplicate the question in database
221  $this_id = $this->getId();
222  $thisObjId = $this->getObjId();
223 
224  $clone = $this;
225 
226  $original_id = $this->questioninfo->getOriginalId($this->id);
227  $clone->id = -1;
228 
229  if ((int) $testObjId > 0) {
230  $clone->setObjId($testObjId);
231  }
232 
233  if ($title) {
234  $clone->setTitle($title);
235  }
236 
237  if ($author) {
238  $clone->setAuthor($author);
239  }
240  if ($owner) {
241  $clone->setOwner($owner);
242  }
243 
244  if ($for_test) {
245  $clone->saveToDb($original_id);
246  } else {
247  $clone->saveToDb();
248  }
249 
250  // copy question page content
251  $clone->copyPageOfQuestion($this_id);
252  // copy XHTML media objects
253  $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
254  #$clone->duplicateAnswers($this_id);
255 
256  $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
257 
258  return $clone->id;
259  }
260 
266  public function copyObject($target_questionpool_id, $title = ""): int
267  {
268  if ($this->getId() <= 0) {
269  throw new RuntimeException('The question has not been saved. It cannot be duplicated');
270  }
271  // duplicate the question in database
272  $clone = $this;
273 
274  $original_id = $this->questioninfo->getOriginalId($this->id);
275  $clone->id = -1;
276  $source_questionpool_id = $this->getObjId();
277  $clone->setObjId($target_questionpool_id);
278  if ($title) {
279  $clone->setTitle($title);
280  }
281  $clone->saveToDb();
282  // copy question page content
283  $clone->copyPageOfQuestion($original_id);
284  // copy XHTML media objects
285  $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
286  // duplicate answers
287  #$clone->duplicateAnswers($original_id);
288 
289  $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
290 
291  return $clone->id;
292  }
293 
294  public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = ""): int
295  {
296  if ($this->getId() <= 0) {
297  throw new RuntimeException('The question has not been saved. It cannot be duplicated');
298  }
299 
300  $sourceQuestionId = $this->id;
301  $sourceParentId = $this->getObjId();
302 
303  // duplicate the question in database
304  $clone = $this;
305  $clone->id = -1;
306 
307  $clone->setObjId($targetParentId);
308 
309  if ($targetQuestionTitle) {
310  $clone->setTitle($targetQuestionTitle);
311  }
312 
313  $clone->saveToDb();
314  // copy question page content
315  $clone->copyPageOfQuestion($sourceQuestionId);
316  // copy XHTML media objects
317  $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
318  // duplicate answers
319  #$clone->duplicateAnswers($sourceQuestionId);
320 
321  $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
322 
323  return $clone->id;
324  }
325 
333  public function getMaxNumOfChars(): int
334  {
335  return $this->maxNumOfChars;
336  }
337 
345  public function setMaxNumOfChars(int $maxchars = 0): void
346  {
347  $this->maxNumOfChars = $maxchars;
348  }
349 
353  public function isWordCounterEnabled(): bool
354  {
356  }
357 
362  {
363  $this->wordCounterEnabled = $wordCounterEnabled;
364  }
365 
372  public function getMaximumPoints(): float
373  {
374  if (in_array($this->getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
375  return parent::getPoints();
376  }
377 
378  $points = 0;
379 
380  foreach ($this->answers as $answer) {
381  if ($answer->getPoints() > 0) {
382  $points = $points + $answer->getPoints();
383  }
384  }
385 
386  return $points;
387  }
388 
389  public function getMinimumPoints()
390  {
391  if (in_array($this->getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
392  return 0;
393  }
394 
395  $points = 0;
396 
397  foreach ($this->answers as $answer) {
398  if ($answer->getPoints() < 0) {
399  $points = $points + $answer->getPoints();
400  }
401  }
402 
403  return $points;
404  }
405 
406  private function isValidTextRating($textRating): bool
407  {
408  switch ($textRating) {
416  return true;
417  }
418 
419  return false;
420  }
421 
430  public function isKeywordMatching($answertext, $a_keyword): bool
431  {
432  global $DIC;
433  $refinery = $DIC->refinery();
434  $result = false;
435  $textrating = $this->getTextRating();
436 
437  switch ($textrating) {
439  if (ilStr::strPos(ilStr::strToLower($answertext), ilStr::strToLower($a_keyword), 0) !== false) {
440  return true;
441  }
442  break;
444  if (ilStr::strPos($answertext, $a_keyword) !== false) {
445  return true;
446  }
447  break;
448  }
449 
450  // "<p>red</p>" would not match "red" even with distance of 5
451  $answertext = strip_tags($answertext);
452  $answerwords = [];
453  if (preg_match_all("/([^\s.]+)/", $answertext, $matches)) {
454  foreach ($matches[1] as $answerword) {
455  array_push($answerwords, trim($answerword));
456  }
457  }
458 
459  // create correct transformation
460  switch ($textrating) {
462  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 1);
463  break;
465  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 2);
466  break;
468  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 3);
469  break;
471  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 4);
472  break;
474  $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 5);
475  break;
476  }
477 
478  // run answers against Levenshtein methods
479  foreach ($answerwords as $a_original) {
480  if (isset($transformation) && $transformation->transform($a_original) >= 0) {
481  return true;
482  }
483  }
484  return $result;
485  }
486 
487  protected function calculateReachedPointsForSolution($solution): float
488  {
489  $solution = html_entity_decode($solution);
490  // Return min points when keyword relation is NON KEYWORDS
491  if ($this->getKeywordRelation() == 'non') {
492  return $this->getMinimumPoints();
493  }
494 
495  // Return min points if there are no answers present.
496  $answers = $this->getAnswers();
497 
498  if (count($answers) == 0) {
499  return $this->getMinimumPoints();
500  }
501 
502  switch ($this->getKeywordRelation()) {
503  case 'any':
504  $points = 0;
505  foreach ($answers as $answer) {
506  $qst_answer = $answer->getAnswertext();
507  $user_answer = ' ' . $solution;
508  if ($this->isKeywordMatching($user_answer, $qst_answer)) {
509  $points += $answer->getPoints();
510  }
511  }
512  break;
513 
514  case 'all':
515  $points = $this->getMaximumPoints();
516  foreach ($answers as $answer) {
517  $qst_answer = $answer->getAnswertext();
518  $user_answer = ' ' . $solution;
519  if (!$this->isKeywordMatching($user_answer, $qst_answer)) {
520  $points = 0;
521  break;
522  }
523  }
524  break;
525 
526  case 'one':
527  $points = 0;
528  foreach ($answers as $answer) {
529  $qst_answer = $answer->getAnswertext();
530  $user_answer = ' ' . $solution;
531  if ($this->isKeywordMatching($user_answer, $qst_answer)) {
532  $points = $this->getMaximumPoints();
533  break;
534  }
535  }
536  break;
537  }
538 
539  return (float) $points;
540  }
541 
552  public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false): float
553  {
554  if ($returndetails) {
555  throw new ilTestException('return details not implemented for ' . __METHOD__);
556  }
557 
558  global $DIC;
559  $ilDB = $DIC['ilDB'];
560 
561  if (is_null($pass)) {
562  $pass = $this->getSolutionMaxPass($active_id);
563  }
564 
565  $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
566 
567  // Return min points when no answer was given.
568  if ($ilDB->numRows($result) == 0) {
569  return $this->getMinimumPoints();
570  }
571 
572  // Return points of points are already on the row.
573  $row = $ilDB->fetchAssoc($result);
574  if ($row["points"] != null) {
575  return (float) $row["points"];
576  }
577 
578  return $this->calculateReachedPointsForSolution($row['value1']);
579  }
580 
589  public function saveWorkingData($active_id, $pass = null, $authorized = true): bool
590  {
591  global $DIC;
592  $ilDB = $DIC['ilDB'];
593  $ilUser = $DIC['ilUser'];
594 
595  if (is_null($pass)) {
596  $pass = ilObjTest::_getPass($active_id);
597  }
598 
599  $entered_values = 0;
600  $text = $this->getSolutionSubmit();
601 
602  $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$entered_values, $active_id, $pass, $authorized, $text) {
603  $this->removeCurrentSolution($active_id, $pass, $authorized);
604 
605  if (strlen($text)) {
606  $this->saveCurrentSolution($active_id, $pass, trim($text), null, $authorized);
607  $entered_values++;
608  }
609  });
610 
611  if ($entered_values) {
613  assQuestion::logAction($this->lng->txtlng(
614  "assessment",
615  "log_user_entered_values",
617  ), $active_id, $this->getId());
618  }
619  } else {
621  assQuestion::logAction($this->lng->txtlng(
622  "assessment",
623  "log_user_not_entered_values",
625  ), $active_id, $this->getId());
626  }
627  }
628 
629  return true;
630  }
631 
635  public function getSolutionSubmit()
636  {
637  if (ilObjAdvancedEditing::_getRichTextEditor() === 'tinymce') {
638  $text = ilUtil::stripSlashes($_POST["TEXT"], false);
639  } else {
640  $text = htmlentities($_POST["TEXT"]);
641  }
642 
643  if (ilUtil::isHTML($text)) {
644  $text = $this->getHtmlUserSolutionPurifier()->purify($text);
645  }
646 
647  return $text;
648  }
649 
650  public function saveAdditionalQuestionDataToDb()
651  {
653  global $DIC;
654  $ilDB = $DIC['ilDB'];
655  $ilDB->manipulateF(
656  "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
657  ['integer'],
658  [$this->getId()]
659  );
660 
661  $fields = [
662  'question_fi' => ['integer', $this->getId()],
663  'maxnumofchars' => ['integer', $this->getMaxNumOfChars()],
664  'word_cnt_enabled' => ['integer', (int) $this->isWordCounterEnabled()],
665  'keywords' => ['text', null],
666  'textgap_rating' => ['text', $this->getTextRating()],
667  'matchcondition' => ['integer', $this->getMatchcondition()],
668  'keyword_relation' => ['text', $this->getKeywordRelation()]
669  ];
670 
671  $ilDB->insert($this->getAdditionalTableName(), $fields);
672  }
673 
674  public function saveAnswerSpecificDataToDb()
675  {
677  global $DIC;
678  $ilDB = $DIC['ilDB'];
679 
680  $ilDB->manipulateF(
681  "DELETE FROM qpl_a_essay WHERE question_fi = %s",
682  ['integer'],
683  [$this->getId()]
684  );
685 
686  foreach ($this->answers as $answer) {
688  $nextID = $ilDB->nextId('qpl_a_essay');
689  $ilDB->manipulateF(
690  "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points) VALUES (%s, %s, %s, %s)",
691  ['integer', 'integer', 'text', 'float'],
692  [
693  $nextID,
694  $this->getId(),
695  $answer->getAnswertext(),
696  $answer->getPoints()
697  ]
698  );
699  }
700  }
701 
708  public function getQuestionType(): string
709  {
710  return "assTextQuestion";
711  }
712 
720  public function getTextRating(): string
721  {
722  return $this->text_rating;
723  }
724 
732  public function setTextRating($a_text_rating): void
733  {
734  switch ($a_text_rating) {
742  $this->text_rating = $a_text_rating;
743  break;
744  default:
745  $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
746  break;
747  }
748  }
749 
756  public function getAdditionalTableName(): string
757  {
758  return "qpl_qst_essay";
759  }
760 
765  public function getRTETextWithMediaObjects(): string
766  {
767  return parent::getRTETextWithMediaObjects();
768  }
769 
773  public function setExportDetailsXLSX(ilAssExcelFormatHelper $worksheet, int $startrow, int $col, int $active_id, int $pass): int
774  {
775  parent::setExportDetailsXLSX($worksheet, $startrow, $col, $active_id, $pass);
776 
777  $solutions = $this->getSolutionValues($active_id, $pass);
778 
779  $i = 1;
780  $worksheet->setCell($startrow + $i, $col, $this->lng->txt("result"));
781  $worksheet->setBold($worksheet->getColumnCoord($col) . ($startrow + $i));
782 
783  $assessment_folder = new ilObjAssessmentFolder();
784 
785  $string_escaping_org_value = $worksheet->getStringEscaping();
786  if ($assessment_folder->getExportEssayQuestionsWithHtml()) {
787  $worksheet->setStringEscaping(false);
788  }
789 
790  if (array_key_exists(0, $solutions) && strlen($solutions[0]["value1"])) {
791  $worksheet->setCell($startrow + $i, $col + 2, html_entity_decode($solutions[0]["value1"]));
792  }
793  $i++;
794 
795  $worksheet->setStringEscaping($string_escaping_org_value);
796  return $startrow + $i + 1;
797  }
798 
802  public function toJSON(): string
803  {
804  $result = [];
805  $result['id'] = $this->getId();
806  $result['type'] = (string) $this->getQuestionType();
807  $result['title'] = $this->getTitleForHTMLOutput();
808  $result['question'] = $this->formatSAQuestion($this->getQuestion());
809  $result['nr_of_tries'] = $this->getNrOfTries();
810  $result['shuffle'] = $this->getShuffle();
811  $result['maxlength'] = $this->getMaxNumOfChars();
812  return json_encode($result);
813  }
814 
815  public function getAnswerCount(): int
816  {
817  return count($this->answers);
818  }
819 
833  public function addAnswer(
834  $answertext = "",
835  $points = 0.0,
836  $points_unchecked = 0.0,
837  $order = 0,
838  $answerimage = ""
839  ): void {
840  $answer = new ASS_AnswerMultipleResponseImage($answertext, $points);
841  $this->answers[] = $answer;
842  }
843 
844  public function getAnswers(): array
845  {
846  return $this->answers;
847  }
848 
858  public function getAnswer($index = 0): ?object
859  {
860  if ($index < 0) {
861  return null;
862  }
863  if (count($this->answers) < 1) {
864  return null;
865  }
866  if ($index >= count($this->answers)) {
867  return null;
868  }
869 
870  return $this->answers[$index];
871  }
872 
881  public function deleteAnswer($index = 0): void
882  {
883  if ($index < 0) {
884  return;
885  }
886  if (count($this->answers) < 1) {
887  return;
888  }
889  if ($index >= count($this->answers)) {
890  return;
891  }
892  $answer = $this->answers[$index];
893  //if (strlen($answer->getImage())) {
894  // $this->deleteImage($answer->getImage());
895  //}
896  unset($this->answers[$index]);
897  $this->answers = array_values($this->answers);
898  for ($i = 0, $iMax = count($this->answers); $i < $iMax; $i++) {
899  if ($this->answers[$i]->getOrder() > $index) {
900  $this->answers[$i]->setOrder($i);
901  }
902  }
903  }
904 
905  public function getAnswerTableName(): string
906  {
907  return 'qpl_a_essay';
908  }
909 
916  public function flushAnswers(): void
917  {
918  $this->answers = [];
919  }
920 
921  public function setAnswers($answers): void
922  {
923  if (isset($answers['answer'])) {
924  $count = count($answers['answer']);
925  $withPoints = true;
926  } else {
927  $count = count($answers);
928  $withPoints = false;
929  }
930 
931  $this->flushAnswers();
932 
933  for ($i = 0; $i < $count; $i++) {
934  if ($withPoints) {
935  $this->addAnswer($answers['answer'][$i], $answers['points'][$i]);
936  } else {
937  $this->addAnswer($answers[$i], 0);
938  }
939  }
940  }
941 
942  public function duplicateAnswers($original_id): void
943  {
944  global $DIC;
945  $ilDB = $DIC['ilDB'];
946 
947  $result = $ilDB->queryF(
948  "SELECT * FROM qpl_a_essay WHERE question_fi = %s",
949  ['integer'],
950  [$original_id]
951  );
952  if ($result->numRows()) {
953  while ($row = $ilDB->fetchAssoc($result)) {
954  $next_id = $ilDB->nextId('qpl_a_essay');
955  $affectedRows = $ilDB->manipulateF(
956  "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points)
957  VALUES (%s, %s, %s, %s)",
958  ['integer','integer','text','float'],
959  [$next_id, $this->getId(), $row["answertext"], $row["points"]]
960  );
961  }
962  }
963  }
964 
965  public function getKeywordRelation()
966  {
968  }
969 
974  public function setKeywordRelation(?string $relation): void
975  {
976  if ($relation !== null) {
977  $this->keyword_relation = $relation;
978  }
979  }
980 
981  public static function getValidScoringModes(): array
982  {
983  return array_merge(self::getScoringModesWithPointsByQuestion(), self::getScoringModesWithPointsByKeyword());
984  }
985 
986  public static function getScoringModesWithPointsByQuestion(): array
987  {
988  return ['non', 'all', 'one'];
989  }
990 
991  public static function getScoringModesWithPointsByKeyword(): array
992  {
993  return ['any'];
994  }
995 
1006  public static function isObligationPossible(int $questionId): bool
1007  {
1008  return true;
1009  }
1010 
1011  public function countLetters($text): int
1012  {
1013  $text = strip_tags($text);
1014 
1015  $text = str_replace('&gt;', '>', $text);
1016  $text = str_replace('&lt;', '<', $text);
1017  $text = str_replace('&nbsp;', ' ', $text);
1018  $text = str_replace('&amp;', '&', $text);
1019 
1020  $text = str_replace("\r\n", "\n", $text);
1021  $text = str_replace("\n", "", $text);
1022 
1023  return ilStr::strLen($text);
1024  }
1025 
1026  public function countWords($text): int
1027  {
1028  if ($text === '') {
1029  return 0;
1030  }
1031  $text = str_replace('&nbsp;', ' ', $text);
1032 
1033  $text = preg_replace('/[.,:;!?\-_#\'"+*\\/=()&%§$]/m', '', $text);
1034 
1035  $text = preg_replace('/^\s*/m', '', $text);
1036  $text = preg_replace('/\s*$/m', '', $text);
1037  $text = preg_replace('/\s+/m', ' ', $text);
1038 
1039  return count(explode(' ', $text));
1040  }
1041 
1042  public function getLatestAutosaveContent(int $active_id, int $pass): ?string
1043  {
1044  $question_fi = $this->getId();
1045 
1046  // Do we have an unauthorized result?
1047  $cntresult = $this->db->query(
1048  '
1049  SELECT count(solution_id) cnt
1050  FROM tst_solutions
1051  WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
1052  AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
1053  AND authorized = ' . $this->db->quote(0, 'int')
1054  . ' AND pass = ' . $this->db->quote($pass, 'int')
1055  );
1056  $row = $this->db->fetchAssoc($cntresult);
1057  if ($row['cnt'] > 0) {
1058  $tresult = $this->db->query(
1059  '
1060  SELECT value1
1061  FROM tst_solutions
1062  WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
1063  AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
1064  AND authorized = ' . $this->db->quote(0, 'int')
1065  . ' AND pass = ' . $this->db->quote($pass, 'int')
1066  );
1067  $trow = $this->db->fetchAssoc($tresult);
1068  return $trow['value1'];
1069  }
1070  return null;
1071  }
1072 }
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
getSolutionValues($active_id, $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
setNrOfTries(int $a_nr_of_tries)
const TEXTGAP_RATING_LEVENSHTEIN5
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static getScoringModesWithPointsByKeyword()
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static isObligationPossible(int $questionId)
returns boolean wether it is possible to set this question type as obligatory or not considering the ...
$relation
getLatestAutosaveContent(int $active_id, int $pass)
static _getRichTextEditor()
Returns the identifier for the Rich Text Editor.
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
const TEXTGAP_RATING_LEVENSHTEIN2
static isHTML(string $a_text)
Checks if a given string contains HTML or not.
const TEXTGAP_RATING_LEVENSHTEIN1
Abstract basic class which is to be extended by the concrete assessment question type classes...
setOwner(int $owner=-1)
static strPos(string $a_haystack, string $a_needle, int $a_offset=0)
Definition: class.ilStr.php:42
isComplete()
Returns true, if a multiple choice question is complete for use.
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
setMaxNumOfChars(int $maxchars=0)
Sets the maximum number of characters for the text solution.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
getColumnCoord(int $a_col)
Get column "name" from number.
ASS_AnswerBinaryStateImage is a class for answers with a binary state indicator (checked/unchecked, set/unset) and an image file.
loadFromDb($question_id)
Loads a assTextQuestion object from a database.
saveToDb($original_id="")
Saves a assTextQuestion object to a database.
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
copyObject($target_questionpool_id, $title="")
Copies an assTextQuestion object.
toJSON()
Returns a JSON representation of the question.
setCell($a_row, $a_col, $a_value, $datatype=null)
setComment(string $comment="")
duplicate(bool $for_test=true, string $title="", string $author="", int $owner=-1, $testObjId=null)
Duplicates an assTextQuestion.
setWordCounterEnabled($wordCounterEnabled)
float $points
The maximum available points for the question.
Base Exception for all Exceptions relating to Modules/Test.
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
global $DIC
Definition: feed.php:28
static strLen(string $a_string)
Definition: class.ilStr.php:63
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assTextQuestion constructor
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
setBold(string $a_coords)
Set cell(s) to bold.
__construct(VocabulariesInterface $vocabularies)
isValidTextRating($textRating)
const TEXTGAP_RATING_LEVENSHTEIN3
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...
calculateReachedPointsForSolution($solution)
setMatchcondition(int $matchcondition)
duplicateAnswers($original_id)
flushAnswers()
Deletes all answers.
static logAction(string $logtext, int $active_id, int $question_id)
Class ilObjAssessmentFolder.
static getScoringModesWithPointsByQuestion()
const TEXTGAP_RATING_CASESENSITIVE
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setTextRating($a_text_rating)
Sets the rating option for text comparisons.
getQuestionType()
Returns the question type of the question.
isKeywordMatching($answertext, $a_keyword)
Checks if one of the keywords matches the answertext.
setPoints(float $points)
setObjId(int $obj_id=0)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
string $question
The question text.
getAnswer($index=0)
Returns an answer with a given index.
deleteAnswer($index=0)
Deletes an answer with a given index.
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
addAnswer( $answertext="", $points=0.0, $points_unchecked=0.0, $order=0, $answerimage="")
Adds a possible answer for a multiple choice question.
setKeywordRelation(?string $relation)
This method implements a default behaviour.
saveQuestionDataToDb(int $original_id=-1)
getMaxNumOfChars()
Gets the maximum number of characters for the text solution.
getSolutionMaxPass(int $active_id)
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
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)
const TEXTGAP_RATING_LEVENSHTEIN4
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setTitle(string $title="")
static strToLower(string $a_string)
Definition: class.ilStr.php:72
setLifecycle(ilAssQuestionLifecycle $lifecycle)
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
getTextRating()
Returns the rating option for text comparisons.
setExportDetailsXLSX(ilAssExcelFormatHelper $worksheet, int $startrow, int $col, int $active_id, int $pass)
{}
setAuthor(string $author="")
setShuffle(?bool $shuffle=true)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
ILIAS Refinery Factory $refinery
const TEXTGAP_RATING_CASEINSENSITIVE
setQuestion(string $question="")