19declare(strict_types=1);
100 if (strlen($this->title)
120 $result = $this->db->queryF(
125 if ($this->db->numRows($result) == 1) {
126 $data = $this->db->fetchAssoc($result);
127 $this->
setId($question_id);
130 $this->
setComment((
string) $data[
"description"]);
134 $this->
setPoints((
float) $data[
"points"]);
141 $this->matchcondition = (isset(
$data[
'matchcondition'])) ? (
int)
$data[
'matchcondition'] : 0;
156 $result = $this->db->queryF(
157 'SELECT * FROM qpl_a_essay WHERE question_fi = %s',
163 while ($row = $this->db->fetchAssoc($result)) {
164 $this->
addAnswer($row[
'answertext'] ??
'', $row[
'points'] ?? 0.0);
167 parent::loadFromDb($question_id);
177 $this->max_num_of_chars = $maxchars;
198 if (in_array($this->
getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
199 return parent::getPoints();
204 foreach ($this->answers as $answer) {
205 if ($answer->getPoints() > 0) {
215 if (in_array($this->
getKeywordRelation(), self::getScoringModesWithPointsByQuestion())) {
221 foreach ($this->answers as $answer) {
222 if ($answer->getPoints() < 0) {
232 switch ($textRating) {
261 switch ($textrating) {
275 $answertext = strip_tags($answertext);
277 if (preg_match_all(
"/([^\s.]+)/", $answertext, $matches)) {
278 foreach ($matches[1] as $answerword) {
279 array_push($answerwords, trim($answerword));
284 switch ($textrating) {
286 $transformation =
$refinery->string()->levenshtein()->standard($a_keyword, 1);
289 $transformation =
$refinery->string()->levenshtein()->standard($a_keyword, 2);
292 $transformation =
$refinery->string()->levenshtein()->standard($a_keyword, 3);
295 $transformation =
$refinery->string()->levenshtein()->standard($a_keyword, 4);
298 $transformation =
$refinery->string()->levenshtein()->standard($a_keyword, 5);
303 foreach ($answerwords as $a_original) {
304 if (isset($transformation) && $transformation->transform($a_original) >= 0) {
313 $decoded_solution = html_entity_decode($solution);
322 if ($answers === []) {
329 foreach ($answers as $answer) {
330 $qst_answer = $answer->getAnswertext();
331 $user_answer =
' ' . $decoded_solution;
333 $points += $answer->getPoints();
340 $qst_answer = $answer->getAnswertext();
341 $user_answer =
' ' . $decoded_solution;
349 foreach ($answers as $answer) {
350 $qst_answer = $answer->getAnswertext();
351 $user_answer =
' ' . $decoded_solution;
364 bool $authorized_solution =
true
366 if ($pass === null) {
373 if ($this->db->numRows($result) === 0) {
378 $row = $this->db->fetchAssoc($result);
379 if ($row[
'points'] !==
null) {
380 return (
float) $row[
"points"];
389 bool $authorized =
true
391 if ($pass === null) {
395 $answer = $this->getSolutionSubmit();
396 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
397 function () use ($answer, $active_id, $pass, $authorized) {
398 $this->removeCurrentSolution($active_id, $pass, $authorized);
400 if ($answer !==
'') {
401 $this->saveCurrentSolution($active_id, $pass, $answer,
null, $authorized);
411 $text = $this->questionpool_request->string(
'TEXT',
'');
413 $text = (
new ilRTESettings($this->
lng, $this->current_user))->getRichTextEditor() ===
'tinymce'
415 : htmlentities($text);
417 return ilUtil::isHTML($text) ? $this->getHtmlUserSolutionPurifier()->purify($text) : $text;
422 $this->db->manipulateF(
423 "DELETE FROM " . $this->getAdditionalTableName() .
" WHERE question_fi = %s",
429 'question_fi' => [
'integer', $this->
getId()],
430 'maxnumofchars' => [
'integer', $this->getMaxNumOfChars()],
431 'word_cnt_enabled' => [
'integer', (
int) $this->isWordCounterEnabled()],
432 'keywords' => [
'text',
null],
433 'textgap_rating' => [
'text', $this->getTextRating()],
434 'matchcondition' => [
'integer', $this->getMatchcondition()],
435 'keyword_relation' => [
'text', $this->getKeywordRelation()]
438 $this->db->insert($this->getAdditionalTableName(), $fields);
441 public function saveAnswerSpecificDataToDb()
443 $this->db->manipulateF(
444 "DELETE FROM qpl_a_essay WHERE question_fi = %s",
449 foreach ($this->answers as $answer) {
451 $nextID = $this->db->nextId(
'qpl_a_essay');
452 $this->db->manipulateF(
453 "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points) VALUES (%s, %s, %s, %s)",
454 [
'integer',
'integer',
'text',
'float'],
458 $answer->getAnswertext(),
467 return "assTextQuestion";
472 return $this->text_rating;
477 switch ($a_text_rating) {
485 $this->text_rating = $a_text_rating;
501 return "qpl_qst_essay";
510 return parent::getRTETextWithMediaObjects();
519 $result[
'id'] = $this->
getId();
520 $result[
'type'] = (string) $this->getQuestionType();
521 $result[
'title'] = $this->getTitleForHTMLOutput();
522 $result[
'question'] = $this->formatSAQuestion($this->getQuestion());
523 $result[
'nr_of_tries'] = $this->getNrOfTries();
524 $result[
'shuffle'] = $this->getShuffle();
525 $result[
'maxlength'] = $this->getMaxNumOfChars();
526 return json_encode($result);
531 return count($this->answers);
550 $points_unchecked = 0.0,
563 return $this->answers;
580 if (count($this->answers) < 1) {
583 if ($index >= count($this->answers)) {
587 return $this->answers[$index];
603 if (count($this->answers) < 1) {
606 if ($index >= count($this->answers)) {
609 $answer = $this->answers[$index];
613 unset($this->answers[$index]);
614 $this->answers = array_values($this->answers);
615 for ($i = 0, $iMax = count($this->answers); $i < $iMax; $i++) {
616 if ($this->answers[$i]->
getOrder() > $index) {
617 $this->answers[$i]->setOrder($i);
624 return 'qpl_a_essay';
640 if (isset($answers[
'answer'])) {
641 $count = count($answers[
'answer']);
644 $count = count($answers);
648 $this->flushAnswers();
650 for ($i = 0; $i < $count; $i++) {
653 $answers[
'answer'][$i],
654 $this->
refinery->kindlyTo()->float()->transform($answers[
'points'][$i])
657 $this->addAnswer($answers[$i], 0);
664 $result = $this->db->queryF(
665 "SELECT * FROM qpl_a_essay WHERE question_fi = %s",
669 if ($result->numRows()) {
670 while ($row = $this->db->fetchAssoc($result)) {
671 $next_id = $this->db->nextId(
'qpl_a_essay');
672 $affectedRows = $this->db->manipulateF(
673 "INSERT INTO qpl_a_essay (answer_id, question_fi, answertext, points)
674 VALUES (%s, %s, %s, %s)",
675 [
'integer',
'integer',
'text',
'float'],
676 [$next_id, $this->
getId(), $row[
"answertext"], $row[
"points"]]
684 return $this->keyword_relation;
700 return array_merge(self::getScoringModesWithPointsByQuestion(), self::getScoringModesWithPointsByKeyword());
706 self::SCORING_MODE_KEYWORD_RELATION_NONE,
707 self::SCORING_MODE_KEYWORD_RELATION_ALL,
708 self::SCORING_MODE_KEYWORD_RELATION_ONE
715 self::SCORING_MODE_KEYWORD_RELATION_ANY
721 $text = strip_tags($text);
723 $text = str_replace(
'>',
'>', $text);
724 $text = str_replace(
'<',
'<', $text);
725 $text = str_replace(
' ',
' ', $text);
726 $text = str_replace(
'&',
'&', $text);
728 $text = str_replace(
"\r\n",
"\n", $text);
729 $text = str_replace(
"\n",
"", $text);
739 $text = str_replace(
' ',
' ', $text);
741 $text = preg_replace(
'/[.,:;!?\-_#\'"+*\\/=()&%§$]/m',
'', $text);
743 $text = preg_replace(
'/^\s*/m',
'', $text);
744 $text = preg_replace(
'/\s*$/m',
'', $text);
745 $text = preg_replace(
'/\s+/m',
' ', $text);
747 return count(explode(
' ', $text));
752 $question_fi = $this->
getId();
755 $cntresult = $this->db->query(
757 SELECT count(solution_id) cnt
759 WHERE active_fi = ' . $this->db->quote($active_id,
'int') .
'
760 AND question_fi = ' . $this->db->quote($this->getId(),
'int') .
'
761 AND authorized = ' . $this->db->quote(0,
'int')
762 .
' AND pass = ' . $this->db->quote($pass,
'int')
764 $row = $this->db->fetchAssoc($cntresult);
765 if ($row[
'cnt'] > 0) {
766 $tresult = $this->db->query(
770 WHERE active_fi = ' . $this->db->quote($active_id,
'int') .
'
771 AND question_fi = ' . $this->db->quote($this->getId(),
'int') .
'
772 AND authorized = ' . $this->db->quote(0,
'int')
773 .
' AND pass = ' . $this->db->quote($pass,
'int')
775 $trow = $this->db->fetchAssoc($tresult);
776 return $trow[
'value1'];
784 AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->getQuestionType(),
785 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $this->getTitleForHTMLOutput(),
786 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $this->formatSAQuestion($this->getQuestion()),
787 AdditionalInformationGenerator::KEY_QUESTION_REACHABLE_POINTS => $this->getMaximumPoints(),
788 AdditionalInformationGenerator::KEY_QUESTION_TEXT_WORDCOUNT_ENABLED => $additional_info
790 AdditionalInformationGenerator::KEY_QUESTION_MAXCHARS => $this->getMaxNumOfChars(),
791 AdditionalInformationGenerator::KEY_QUESTION_TEXT_SCORING_MODE => $additional_info->
getTagForLangVar(
792 $this->getScoringModeLangVar($this->getKeywordRelation())
794 AdditionalInformationGenerator::KEY_QUESTION_CORRECT_ANSWER_OPTIONS => array_map(
796 AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTION => $answer->
getAnswertext(),
797 AdditionalInformationGenerator::KEY_QUESTION_REACHABLE_POINTS => $answer->
getPoints() === 0.0 ?
'' : $answer->
getPoints()
801 AdditionalInformationGenerator::KEY_FEEDBACK => [
802 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
803 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
810 switch ($scoring_mode) {
812 return 'essay_scoring_mode_without_keywords';
814 return 'essay_scoring_mode_keyword_relation_any';
816 return 'essay_scoring_mode_keyword_relation_all';
818 return 'essay_scoring_mode_keyword_relation_one';
826 array $solution_values
828 if (!array_key_exists(0, $solution_values)
829 || !array_key_exists(
'value1', $solution_values[0])) {
832 return $this->
refinery->string()->stripTags()->transform(
833 html_entity_decode($solution_values[0][
'value1'])
839 if (!array_key_exists(0, $solution_values)
840 || !array_key_exists(
'value1', $solution_values[0])) {
843 return $solution_values[0][
'value1'];
848 switch ($this->getKeywordRelation()) {
849 case self::SCORING_MODE_KEYWORD_RELATION_NONE:
ASS_AnswerBinaryStateImage is a class for answers with a binary state indicator (checked/unchecked,...
getPoints()
Gets the points.
getAnswertext()
Gets the answer text.
const TEXTGAP_RATING_CASESENSITIVE
const TEXTGAP_RATING_LEVENSHTEIN1
const TEXTGAP_RATING_LEVENSHTEIN5
const TEXTGAP_RATING_CASEINSENSITIVE
const TEXTGAP_RATING_LEVENSHTEIN4
const TEXTGAP_RATING_LEVENSHTEIN2
const TEXTGAP_RATING_LEVENSHTEIN3
setOriginalId(?int $original_id)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
setShuffle(?bool $shuffle=true)
setQuestion(string $question="")
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
setAuthor(string $author="")
setComment(string $comment="")
getSolutionMaxPass(int $active_id)
setNrOfTries(int $a_nr_of_tries)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
setTitle(string $title="")
saveQuestionDataToDb(?int $original_id=null)
Class for text questions.
const SCORING_MODE_KEYWORD_RELATION_NONE
const SCORING_MODE_KEYWORD_RELATION_ONE
isKeywordMatching($answertext, $a_keyword)
Checks if one of the keywords matches the answertext.
toLog(AdditionalInformationGenerator $additional_info)
MUST return an array of the question settings that can be stored in the log.
setWordCounterEnabled(bool $word_counter_enabled)
getLatestAutosaveContent(int $active_id, int $pass)
setMaxNumOfChars(int $maxchars=0)
setKeywordRelation(?string $relation)
This method implements a default behaviour.
solutionValuesToText(array $solution_values)
MUST convert the given solution values into text.
saveWorkingData(int $active_id, ?int $pass=null, bool $authorized=true)
addAnswer( $answertext="", $points=0.0, $points_unchecked=0.0, $order=0, $answerimage="")
Adds a possible answer for a multiple choice question.
const HAS_SPECIFIC_FEEDBACK
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
calculateReachedPointsForSolution(string $solution)
__construct(string $title="", string $comment="", string $author="", int $owner=-1, string $question="")
assTextQuestion constructor
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.
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
bool $word_counter_enabled
getAnswer($index=0)
Returns an answer with a given index.
const SCORING_MODE_KEYWORD_RELATION_ANY
setMatchcondition(int $matchcondition)
calculateReachedPoints(int $active_id, ?int $pass=null, bool $authorized_solution=true)
getAdditionalTableName()
Returns the name of the additional question data table in the database.
static getScoringModesWithPointsByKeyword()
getScoringModeLangVar(string $scoring_mode)
toJSON()
Returns a JSON representation of the question.
flushAnswers()
Deletes all answers.
setTextRating($a_text_rating)
static getValidScoringModes()
deleteAnswer($index=0)
Deletes an answer with a given index.
saveToDb(?int $original_id=null)
loadFromDb(int $question_id)
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
getCorrectSolutionForTextOutput(int $active_id, int $pass)
isValidTextRating($textRating)
const SCORING_MODE_KEYWORD_RELATION_ALL
static getScoringModesWithPointsByQuestion()
duplicateAnswers($original_id)
static getDraftInstance()
static getInstance($identifier)
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=0)
static strToLower(string $a_string)
static strLen(string $a_string)
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="")
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...
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
if(!file_exists('../ilias.ini.php'))