ILIAS  release_8 Revision v8.24
class.assTextQuestion.php
Go to the documentation of this file.
1<?php
2
19require_once './Modules/TestQuestionPool/classes/class.assQuestion.php';
20require_once './Modules/Test/classes/inc.AssessmentConstants.php';
21require_once './Modules/TestQuestionPool/interfaces/interface.ilObjQuestionScoringAdjustable.php';
22require_once './Modules/TestQuestionPool/interfaces/interface.ilObjAnswerScoringAdjustable.php';
23
38{
39 protected const HAS_SPECIFIC_FEEDBACK = false;
48
53
62 public $keywords;
63
64 public $answers;
65
72
73 /* method for automatic string matching */
75
76 public $keyword_relation = 'any';
77
90 public function __construct(
91 $title = "",
92 $comment = "",
93 $author = "",
94 $owner = -1,
95 $question = ""
96 ) {
98 $this->wordCounterEnabled = false;
99 $this->maxNumOfChars = 0;
100 $this->points = 1;
101 $this->answers = array();
102 $this->matchcondition = 0;
103 }
104
105 public function getMatchcondition(): int
106 {
108 }
109
110 public function setMatchcondition(int $matchcondition): void
111 {
112 $this->matchcondition = $matchcondition;
113 }
114
120 public function isComplete(): bool
121 {
122 if (strlen($this->title)
123 && $this->author
124 && $this->question
125 && $this->getMaximumPoints() > 0
126 ) {
127 return true;
128 }
129 return false;
130 }
131
137 public function saveToDb($original_id = ""): void
138 {
139 if ($original_id == '') {
140 $this->saveQuestionDataToDb();
141 } else {
143 }
144
147 parent::saveToDb();
148 }
149
157 public function loadFromDb($question_id): void
158 {
159 global $DIC;
160 $ilDB = $DIC['ilDB'];
161
162 $result = $ilDB->queryF(
163 "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",
164 array("integer"),
165 array($question_id)
166 );
167 if ($ilDB->numRows($result) == 1) {
168 $data = $ilDB->fetchAssoc($result);
169 $this->setId($question_id);
170 $this->setObjId($data["obj_fi"]);
171 $this->setTitle((string) $data["title"]);
172 $this->setComment((string) $data["description"]);
173 $this->setOriginalId($data["original_id"]);
174 $this->setNrOfTries($data['nr_of_tries']);
175 $this->setAuthor($data["author"]);
176 $this->setPoints((float) $data["points"]);
177 $this->setOwner($data["owner"]);
178 include_once("./Services/RTE/classes/class.ilRTE.php");
179 $this->setQuestion(ilRTE::_replaceMediaObjectImageSrc((string) $data["question_text"], 1));
180 $this->setShuffle(false);
181 $this->setWordCounterEnabled((bool) $data['word_cnt_enabled']);
182 $this->setMaxNumOfChars($data["maxnumofchars"]);
183 $this->setTextRating($this->isValidTextRating($data["textgap_rating"]) ? $data["textgap_rating"] : TEXTGAP_RATING_CASEINSENSITIVE);
184 $this->matchcondition = (strlen($data['matchcondition'])) ? (int) $data['matchcondition'] : 0;
185 $this->setKeywordRelation(($data['keyword_relation']));
186
187 try {
188 $this->setLifecycle(ilAssQuestionLifecycle::getInstance($data['lifecycle']));
191 }
192
193 try {
194 $this->setAdditionalContentEditingMode($data['add_cont_edit_mode']);
196 }
197 }
198
199 $result = $ilDB->queryF(
200 "SELECT * FROM qpl_a_essay WHERE question_fi = %s",
201 array("integer"),
202 array($this->getId())
203 );
204
205 $this->flushAnswers();
206 while ($row = $ilDB->fetchAssoc($result)) {
207 $this->addAnswer($row['answertext'], $row['points']);
208 }
209
210 parent::loadFromDb($question_id);
211 }
212
218 public function duplicate(bool $for_test = true, string $title = "", string $author = "", string $owner = "", $testObjId = null): int
219 {
220 if ($this->id <= 0) {
221 // The question has not been saved. It cannot be duplicated
222 return -1;
223 }
224 // duplicate the question in database
225 $this_id = $this->getId();
226 $thisObjId = $this->getObjId();
227
228 $clone = $this;
229 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
231 $clone->id = -1;
232
233 if ((int) $testObjId > 0) {
234 $clone->setObjId($testObjId);
235 }
236
237 if ($title) {
238 $clone->setTitle($title);
239 }
240
241 if ($author) {
242 $clone->setAuthor($author);
243 }
244 if ($owner) {
245 $clone->setOwner($owner);
246 }
247
248 if ($for_test) {
249 $clone->saveToDb($original_id);
250 } else {
251 $clone->saveToDb();
252 }
253
254 // copy question page content
255 $clone->copyPageOfQuestion($this_id);
256 // copy XHTML media objects
257 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
258 #$clone->duplicateAnswers($this_id);
259
260 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
261
262 return $clone->id;
263 }
264
270 public function copyObject($target_questionpool_id, $title = ""): int
271 {
272 if ($this->getId() <= 0) {
273 throw new RuntimeException('The question has not been saved. It cannot be duplicated');
274 }
275 // duplicate the question in database
276 $clone = $this;
277 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
279 $clone->id = -1;
280 $source_questionpool_id = $this->getObjId();
281 $clone->setObjId($target_questionpool_id);
282 if ($title) {
283 $clone->setTitle($title);
284 }
285 $clone->saveToDb();
286 // copy question page content
287 $clone->copyPageOfQuestion($original_id);
288 // copy XHTML media objects
289 $clone->copyXHTMLMediaObjectsOfQuestion($original_id);
290 // duplicate answers
291 #$clone->duplicateAnswers($original_id);
292
293 $clone->onCopy($source_questionpool_id, $original_id, $clone->getObjId(), $clone->getId());
294
295 return $clone->id;
296 }
297
298 public function createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle = ""): int
299 {
300 if ($this->getId() <= 0) {
301 throw new RuntimeException('The question has not been saved. It cannot be duplicated');
302 }
303
304 include_once("./Modules/TestQuestionPool/classes/class.assQuestion.php");
305
306 $sourceQuestionId = $this->id;
307 $sourceParentId = $this->getObjId();
308
309 // duplicate the question in database
310 $clone = $this;
311 $clone->id = -1;
312
313 $clone->setObjId($targetParentId);
314
315 if ($targetQuestionTitle) {
316 $clone->setTitle($targetQuestionTitle);
317 }
318
319 $clone->saveToDb();
320 // copy question page content
321 $clone->copyPageOfQuestion($sourceQuestionId);
322 // copy XHTML media objects
323 $clone->copyXHTMLMediaObjectsOfQuestion($sourceQuestionId);
324 // duplicate answers
325 #$clone->duplicateAnswers($sourceQuestionId);
326
327 $clone->onCopy($sourceParentId, $sourceQuestionId, $clone->getObjId(), $clone->getId());
328
329 return $clone->id;
330 }
331
339 public function getMaxNumOfChars(): int
340 {
341 if (strcmp($this->maxNumOfChars, "") == 0) {
342 return 0;
343 } else {
345 }
346 }
347
355 public function setMaxNumOfChars($maxchars = 0): void
356 {
357 $this->maxNumOfChars = $maxchars;
358 }
359
363 public function isWordCounterEnabled(): bool
364 {
366 }
367
372 {
373 $this->wordCounterEnabled = $wordCounterEnabled;
374 }
375
382 public function getMaximumPoints(): float
383 {
384 if (in_array($this->getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
385 return parent::getPoints();
386 }
387
388 $points = 0;
389
390 foreach ($this->answers as $answer) {
391 if ($answer->getPoints() > 0) {
392 $points = $points + $answer->getPoints();
393 }
394 }
395
396 return $points;
397 }
398
399 public function getMinimumPoints()
400 {
401 if (in_array($this->getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
402 return 0;
403 }
404
405 $points = 0;
406
407 foreach ($this->answers as $answer) {
408 if ($answer->getPoints() < 0) {
409 $points = $points + $answer->getPoints();
410 }
411 }
412
413 return $points;
414 }
424 public function setReachedPoints($active_id, $points, $pass = null): bool
425 {
426 global $DIC;
427 $ilDB = $DIC['ilDB'];
428
429 if (($points > 0) && ($points <= $this->getPoints())) {
430 if (is_null($pass)) {
431 $pass = $this->getSolutionMaxPass($active_id);
432 }
433 $affectedRows = $ilDB->manipulateF(
434 "UPDATE tst_test_result SET points = %s WHERE active_fi = %s AND question_fi = %s AND pass = %s",
435 array('float','integer','integer','integer'),
436 array($points, $active_id, $this->getId(), $pass)
437 );
438 self::_updateTestPassResults($active_id, $pass);
439 return true;
440 } else {
441 return true;
442 }
443 }
444
445 private function isValidTextRating($textRating): bool
446 {
447 switch ($textRating) {
455 return true;
456 }
457
458 return false;
459 }
460
469 public function isKeywordMatching($answertext, $a_keyword): bool
470 {
471 global $DIC;
472 $refinery = $DIC->refinery();
473 $result = false;
474 $textrating = $this->getTextRating();
475 include_once "./Services/Utilities/classes/class.ilStr.php";
476
477 switch ($textrating) {
479 if (ilStr::strPos(ilStr::strToLower($answertext), ilStr::strToLower($a_keyword)) !== false) {
480 return true;
481 }
482 break;
484 if (ilStr::strPos($answertext, $a_keyword) !== false) {
485 return true;
486 }
487 break;
488 }
489
490 // "<p>red</p>" would not match "red" even with distance of 5
491 $answertext = strip_tags($answertext);
492 $answerwords = array();
493 if (preg_match_all("/([^\s.]+)/", $answertext, $matches)) {
494 foreach ($matches[1] as $answerword) {
495 array_push($answerwords, trim($answerword));
496 }
497 }
498
499 // create correct transformation
500 switch ($textrating) {
502 $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 1);
503 break;
505 $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 2);
506 break;
508 $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 3);
509 break;
511 $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 4);
512 break;
514 $transformation = $refinery->string()->levenshtein()->standard($a_keyword, 5);
515 break;
516 }
517
518 // run answers against Levenshtein methods
519 foreach ($answerwords as $a_original) {
520 if (isset($transformation) && $transformation->transform($a_original) >= 0) {
521 return true;
522 }
523 }
524 return $result;
525 }
526
527 protected function calculateReachedPointsForSolution($solution)
528 {
529 $solution = html_entity_decode($solution);
530 // Return min points when keyword relation is NON KEYWORDS
531 if ($this->getKeywordRelation() == 'non') {
532 return $this->getMinimumPoints();
533 }
534
535 // Return min points if there are no answers present.
536 $answers = $this->getAnswers();
537
538 if (count($answers) == 0) {
539 return $this->getMinimumPoints();
540 }
541
542 switch ($this->getKeywordRelation()) {
543 case 'any':
544 $points = 0;
545 foreach ($answers as $answer) {
546 $qst_answer = $answer->getAnswertext();
547 $user_answer = ' ' . $solution;
548 if ($this->isKeywordMatching($user_answer, $qst_answer)) {
549 $points += $answer->getPoints();
550 }
551 }
552 break;
553
554 case 'all':
555 $points = $this->getMaximumPoints();
556 foreach ($answers as $answer) {
557 $qst_answer = $answer->getAnswertext();
558 $user_answer = ' ' . $solution;
559 if (!$this->isKeywordMatching($user_answer, $qst_answer)) {
560 $points = 0;
561 break;
562 }
563 }
564 break;
565
566 case 'one':
567 $points = 0;
568 foreach ($answers as $answer) {
569 $qst_answer = $answer->getAnswertext();
570 $user_answer = ' ' . $solution;
571 if ($this->isKeywordMatching($user_answer, $qst_answer)) {
572 $points = $this->getMaximumPoints();
573 break;
574 }
575 }
576 break;
577 }
578
579 return $points;
580 }
581
592 public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution = true, $returndetails = false)
593 {
594 if ($returndetails) {
595 throw new ilTestException('return details not implemented for ' . __METHOD__);
596 }
597
598 global $DIC;
599 $ilDB = $DIC['ilDB'];
600
601 if (is_null($pass)) {
602 $pass = $this->getSolutionMaxPass($active_id);
603 }
604
605 $result = $this->getCurrentSolutionResultSet($active_id, $pass, $authorizedSolution);
606
607 // Return min points when no answer was given.
608 if ($ilDB->numRows($result) == 0) {
609 return $this->getMinimumPoints();
610 }
611
612 // Return points of points are already on the row.
613 $row = $ilDB->fetchAssoc($result);
614 if ($row["points"] != null) {
615 return $row["points"];
616 }
617
618 return $this->calculateReachedPointsForSolution($row['value1']);
619 }
620
629 public function saveWorkingData($active_id, $pass = null, $authorized = true): bool
630 {
631 global $DIC;
632 $ilDB = $DIC['ilDB'];
633 $ilUser = $DIC['ilUser'];
634
635 include_once "./Services/Utilities/classes/class.ilStr.php";
636 if (is_null($pass)) {
637 include_once "./Modules/Test/classes/class.ilObjTest.php";
638 $pass = ilObjTest::_getPass($active_id);
639 }
640
641 $entered_values = 0;
642 $text = $this->getSolutionSubmit();
643
644 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(function () use (&$entered_values, $active_id, $pass, $authorized, $text) {
645 $this->removeCurrentSolution($active_id, $pass, $authorized);
646
647 if (strlen($text)) {
648 $this->saveCurrentSolution($active_id, $pass, trim($text), null, $authorized);
649 $entered_values++;
650 }
651 });
652
653 if ($entered_values) {
654 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
656 assQuestion::logAction($this->lng->txtlng(
657 "assessment",
658 "log_user_entered_values",
660 ), $active_id, $this->getId());
661 }
662 } else {
663 include_once("./Modules/Test/classes/class.ilObjAssessmentFolder.php");
665 assQuestion::logAction($this->lng->txtlng(
666 "assessment",
667 "log_user_not_entered_values",
669 ), $active_id, $this->getId());
670 }
671 }
672
673 return true;
674 }
675
679 public function getSolutionSubmit()
680 {
681 if (ilObjAdvancedEditing::_getRichTextEditor() === 'tinymce') {
682 $text = ilUtil::stripSlashes($_POST["TEXT"], false);
683 } else {
684 $text = htmlentities($_POST["TEXT"]);
685 }
686
687 if (ilUtil::isHTML($text)) {
688 $text = $this->getHtmlUserSolutionPurifier()->purify($text);
689 }
690
691 return $text;
692 }
693
694 public function saveAdditionalQuestionDataToDb()
695 {
697 global $DIC;
698 $ilDB = $DIC['ilDB'];
699 $ilDB->manipulateF(
700 "DELETE FROM " . $this->getAdditionalTableName() . " WHERE question_fi = %s",
701 array( "integer" ),
702 array( $this->getId()
703 )
704 );
705
706 $fields = array(
707 'question_fi' => array('integer', $this->getId()),
708 'maxnumofchars' => array('integer', $this->getMaxNumOfChars()),
709 'word_cnt_enabled' => array('integer', (int) $this->isWordCounterEnabled()),
710 'keywords' => array('text', null),
711 'textgap_rating' => array('text', $this->getTextRating()),
712 'matchcondition' => array('integer', $this->getMatchcondition()),
713 'keyword_relation' => array('text', $this->getKeywordRelation())
714 );
715
716 $ilDB->insert($this->getAdditionalTableName(), $fields);
717 }
718
719 public function saveAnswerSpecificDataToDb()
720 {
722 global $DIC;
723 $ilDB = $DIC['ilDB'];
724
725 $ilDB->manipulateF(
726 "DELETE FROM qpl_a_essay WHERE question_fi = %s",
727 array( "integer" ),
728 array( $this->getId() )
729 );
730
731 foreach ($this->answers as $answer) {
733 $nextID = $ilDB->nextId('qpl_a_essay');
734 $ilDB->manipulateF(
735 "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points) VALUES (%s, %s, %s, %s)",
736 array( "integer", "integer", "text", 'float' ),
737 array(
738 $nextID,
739 $this->getId(),
740 $answer->getAnswertext(),
741 $answer->getPoints()
742 )
743 );
744 }
745 }
746
753 public function getQuestionType(): string
754 {
755 return "assTextQuestion";
756 }
757
765 public function getTextRating(): string
766 {
767 return $this->text_rating;
768 }
769
777 public function setTextRating($a_text_rating): void
778 {
779 switch ($a_text_rating) {
787 $this->text_rating = $a_text_rating;
788 break;
789 default:
790 $this->text_rating = TEXTGAP_RATING_CASEINSENSITIVE;
791 break;
792 }
793 }
794
801 public function getAdditionalTableName(): string
802 {
803 return "qpl_qst_essay";
804 }
805
810 public function getRTETextWithMediaObjects(): string
811 {
812 return parent::getRTETextWithMediaObjects();
813 }
814
818 public function setExportDetailsXLS(ilAssExcelFormatHelper $worksheet, int $startrow, int $active_id, int $pass): int
819 {
820 parent::setExportDetailsXLS($worksheet, $startrow, $active_id, $pass);
821
822 $solutions = $this->getSolutionValues($active_id, $pass);
823
824 $i = 1;
825 $worksheet->setCell($startrow + $i, 0, $this->lng->txt("result"));
826 $worksheet->setBold($worksheet->getColumnCoord(0) . ($startrow + $i));
827
828 require_once 'Modules/Test/classes/class.ilObjAssessmentFolder.php';
829 $assessment_folder = new ilObjAssessmentFolder();
830
831 $string_escaping_org_value = $worksheet->getStringEscaping();
832 if ($assessment_folder->getExportEssayQuestionsWithHtml()) {
833 $worksheet->setStringEscaping(false);
834 }
835
836 if (array_key_exists(0, $solutions) && strlen($solutions[0]["value1"])) {
837 $worksheet->setCell($startrow + $i, 2, html_entity_decode($solutions[0]["value1"]));
838 }
839 $i++;
840
841 $worksheet->setStringEscaping($string_escaping_org_value);
842 return $startrow + $i + 1;
843 }
844
848 public function toJSON(): string
849 {
850 include_once("./Services/RTE/classes/class.ilRTE.php");
851 $result = array();
852 $result['id'] = $this->getId();
853 $result['type'] = (string) $this->getQuestionType();
854 $result['title'] = $this->getTitleForHTMLOutput();
855 $result['question'] = $this->formatSAQuestion($this->getQuestion());
856 $result['nr_of_tries'] = $this->getNrOfTries();
857 $result['shuffle'] = $this->getShuffle();
858 $result['maxlength'] = $this->getMaxNumOfChars();
859 return json_encode($result);
860 }
861
862 public function getAnswerCount(): int
863 {
864 return count($this->answers);
865 }
866
880 public function addAnswer(
881 $answertext = "",
882 $points = 0.0,
883 $points_unchecked = 0.0,
884 $order = 0,
885 $answerimage = ""
886 ): void {
887 include_once "./Modules/TestQuestionPool/classes/class.assAnswerMultipleResponseImage.php";
888
889 // add answer
890 $answer = new ASS_AnswerMultipleResponseImage($answertext, $points);
891 $this->answers[] = $answer;
892 }
893
894 public function getAnswers(): array
895 {
896 return $this->answers;
897 }
898
908 public function getAnswer($index = 0): ?object
909 {
910 if ($index < 0) {
911 return null;
912 }
913 if (count($this->answers) < 1) {
914 return null;
915 }
916 if ($index >= count($this->answers)) {
917 return null;
918 }
919
920 return $this->answers[$index];
921 }
922
931 public function deleteAnswer($index = 0): void
932 {
933 if ($index < 0) {
934 return;
935 }
936 if (count($this->answers) < 1) {
937 return;
938 }
939 if ($index >= count($this->answers)) {
940 return;
941 }
942 $answer = $this->answers[$index];
943 //if (strlen($answer->getImage())) {
944 // $this->deleteImage($answer->getImage());
945 //}
946 unset($this->answers[$index]);
947 $this->answers = array_values($this->answers);
948 for ($i = 0, $iMax = count($this->answers); $i < $iMax; $i++) {
949 if ($this->answers[$i]->getOrder() > $index) {
950 $this->answers[$i]->setOrder($i);
951 }
952 }
953 }
954
955 public function getAnswerTableName(): string
956 {
957 return 'qpl_a_essay';
958 }
959
966 public function flushAnswers(): void
967 {
968 $this->answers = array();
969 }
970
971 public function setAnswers($answers): void
972 {
973 if (isset($answers['answer'])) {
974 $count = count($answers['answer']);
975 $withPoints = true;
976 } else {
977 $count = count($answers);
978 $withPoints = false;
979 }
980
981 $this->flushAnswers();
982
983 for ($i = 0; $i < $count; $i++) {
984 if ($withPoints) {
985 $this->addAnswer($answers['answer'][$i], $answers['points'][$i]);
986 } else {
987 $this->addAnswer($answers[$i], 0);
988 }
989 }
990 }
991
992 public function duplicateAnswers($original_id): void
993 {
994 global $DIC;
995 $ilDB = $DIC['ilDB'];
996
997 $result = $ilDB->queryF(
998 "SELECT * FROM qpl_a_essay WHERE question_fi = %s",
999 array('integer'),
1000 array($original_id)
1001 );
1002 if ($result->numRows()) {
1003 while ($row = $ilDB->fetchAssoc($result)) {
1004 $next_id = $ilDB->nextId('qpl_a_essay');
1005 $affectedRows = $ilDB->manipulateF(
1006 "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points)
1007 VALUES (%s, %s, %s, %s)",
1008 array('integer','integer','text','float'),
1009 array($next_id, $this->getId(), $row["answertext"], $row["points"])
1010 );
1011 }
1012 }
1013 }
1014
1015 public function getKeywordRelation()
1016 {
1017 return $this->keyword_relation;
1018 }
1019
1024 public function setKeywordRelation($a_relation): void
1025 {
1026 $this->keyword_relation = $a_relation;
1027 }
1028
1029 public static function getValidScoringModes(): array
1030 {
1031 return array_merge(self::getScoringModesWithPointsByQuestion(), self::getScoringModesWithPointsByKeyword());
1032 }
1033
1034 public static function getScoringModesWithPointsByQuestion(): array
1035 {
1036 return array('non', 'all', 'one');
1037 }
1038
1039 public static function getScoringModesWithPointsByKeyword(): array
1040 {
1041 return array('any');
1042 }
1043
1044
1055 public function isAnswered(int $active_id, int $pass): bool
1056 {
1057 $numExistingSolutionRecords = assQuestion::getNumExistingSolutionRecords($active_id, $pass, $this->getId());
1058
1059 return $numExistingSolutionRecords > 0;
1060 }
1061
1072 public static function isObligationPossible(int $questionId): bool
1073 {
1074 return true;
1075 }
1076
1077 public function countLetters($text): int
1078 {
1079 $text = strip_tags($text);
1080
1081 $text = str_replace('&gt;', '>', $text);
1082 $text = str_replace('&lt;', '<', $text);
1083 $text = str_replace('&nbsp;', ' ', $text);
1084 $text = str_replace('&amp;', '&', $text);
1085
1086 $text = str_replace("\r\n", "\n", $text);
1087 $text = str_replace("\n", "", $text);
1088
1089 return ilStr::strLen($text);
1090 }
1091
1092 public function countWords($text): int
1093 {
1094 if ($text === '') {
1095 return 0;
1096 }
1097 $text = str_replace('&nbsp;', ' ', $text);
1098
1099 $text = preg_replace('/[.,:;!?\-_#\'"+*\\/=()&%§$]/m', '', $text);
1100
1101 $text = preg_replace('/^\s*/m', '', $text);
1102 $text = preg_replace('/\s*$/m', '', $text);
1103 $text = preg_replace('/\s+/m', ' ', $text);
1104
1105 return count(explode(' ', $text));
1106 }
1107
1108 public function getLatestAutosaveContent(int $active_id, int $pass): ?string
1109 {
1110 // Do we have an unauthorized result?
1111 $cntresult = $this->db->query(
1112 '
1113 SELECT count(solution_id) cnt
1114 FROM tst_solutions
1115 WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
1116 AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
1117 AND authorized = ' . $this->db->quote(0, 'int')
1118 . ' AND pass = ' . $this->db->quote($pass, 'int')
1119 );
1120 $row = $this->db->fetchAssoc($cntresult);
1121 if ($row['cnt'] > 0) {
1122 $tresult = $this->db->query(
1123 '
1124 SELECT value1
1125 FROM tst_solutions
1126 WHERE active_fi = ' . $this->db->quote($active_id, 'int') . '
1127 AND question_fi = ' . $this->db->quote($this->getId(), 'int') . '
1128 AND authorized = ' . $this->db->quote(0, 'int')
1129 . ' AND pass = ' . $this->db->quote($pass, 'int')
1130 );
1131 $trow = $this->db->fetchAssoc($tresult);
1132 return $trow['value1'];
1133 }
1134 return null;
1135 }
1136}
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Abstract basic class which is to be extended by the concrete assessment question type classes.
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)
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
setShuffle(?bool $shuffle=true)
getSolutionValues($active_id, $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
ILIAS Refinery Factory $refinery
setQuestion(string $question="")
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
static _getOriginalId(int $question_id)
saveQuestionDataToDb(int $original_id=-1)
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)
static getNumExistingSolutionRecords(int $activeId, int $pass, int $questionId)
setTitle(string $title="")
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
setPoints(float $points)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setMaxNumOfChars($maxchars=0)
Sets the maximum number of characters for the text solution.
isAnswered(int $active_id, int $pass)
returns boolean wether the question is answered during test pass or not
setExportDetailsXLS(ilAssExcelFormatHelper $worksheet, int $startrow, int $active_id, int $pass)
{}
isKeywordMatching($answertext, $a_keyword)
Checks if one of the keywords matches the answertext.
getLatestAutosaveContent(int $active_id, int $pass)
saveToDb($original_id="")
Saves a assTextQuestion object to a database.
loadFromDb($question_id)
Loads a assTextQuestion object from a database.
addAnswer( $answertext="", $points=0.0, $points_unchecked=0.0, $order=0, $answerimage="")
Adds a possible answer for a multiple choice question.
saveWorkingData($active_id, $pass=null, $authorized=true)
Saves the learners input of the question to the database.
static isObligationPossible(int $questionId)
returns boolean wether it is possible to set this question type as obligatory or not considering the ...
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
isComplete()
Returns true, if a multiple choice question is complete for use.
setKeywordRelation($a_relation)
This method implements a default behaviour.
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
getAnswer($index=0)
Returns an answer with a given index.
setMatchcondition(int $matchcondition)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
static getScoringModesWithPointsByKeyword()
setWordCounterEnabled($wordCounterEnabled)
toJSON()
Returns a JSON representation of the question.
flushAnswers()
Deletes all answers.
setTextRating($a_text_rating)
Sets the rating option for text comparisons.
copyObject($target_questionpool_id, $title="")
Copies an assTextQuestion object.
getQuestionType()
Returns the question type of the question.
deleteAnswer($index=0)
Deletes an answer with a given index.
getMaxNumOfChars()
Gets the maximum number of characters for the text solution.
calculateReachedPointsForSolution($solution)
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
isValidTextRating($textRating)
duplicate(bool $for_test=true, string $title="", string $author="", string $owner="", $testObjId=null)
Duplicates an assTextQuestion.
createNewOriginalFromThisDuplicate($targetParentId, $targetQuestionTitle="")
setReachedPoints($active_id, $points, $pass=null)
Sets the points, a learner has reached answering the question.
__construct( $title="", $comment="", $author="", $owner=-1, $question="")
assTextQuestion constructor
static getScoringModesWithPointsByQuestion()
getTextRating()
Returns the rating option for text comparisons.
duplicateAnswers($original_id)
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)
setBold(string $a_coords)
Set cell(s) to bold.
getColumnCoord(int $a_col)
Get column "name" from number.
static _getRichTextEditor()
Returns the identifier for the Rich Text Editor.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
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 strPos(string $a_haystack, string $a_needle, ?int $a_offset=null)
Definition: class.ilStr.php:42
static strToLower(string $a_string)
Definition: class.ilStr.php:72
static strLen(string $a_string)
Definition: class.ilStr.php:63
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static isHTML(string $a_text)
Checks if a given string contains HTML or not.
static stripSlashes(string $a_str, bool $a_strip_html=true, string $a_allow="")
global $DIC
Definition: feed.php:28
$ilUser
Definition: imgupload.php:34
const TEXTGAP_RATING_LEVENSHTEIN5
const TEXTGAP_RATING_LEVENSHTEIN4
const TEXTGAP_RATING_LEVENSHTEIN3
const TEXTGAP_RATING_CASESENSITIVE
const TEXTGAP_RATING_LEVENSHTEIN2
const TEXTGAP_RATING_CASEINSENSITIVE
const TEXTGAP_RATING_LEVENSHTEIN1
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
$index
Definition: metadata.php:145
$i
Definition: metadata.php:41
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc