19declare(strict_types=1);
52 count($this->answers) >= $this->correctanswers
71 $result = $this->db->queryF(
76 if ($result->numRows() == 1) {
77 $data = $this->db->fetchAssoc($result);
78 $this->
setId($question_id);
82 $this->
setComment((
string) $data[
'description']);
104 $result = $this->db->queryF(
105 "SELECT * FROM qpl_a_textsubset WHERE question_fi = %s ORDER BY aorder ASC",
109 if ($result->numRows() > 0) {
110 while (
$data = $this->db->fetchAssoc($result)) {
115 parent::loadFromDb($question_id);
125 if (array_key_exists($order, $this->answers)) {
129 for ($i = 0; $i < $order; $i++) {
130 $newchoices[] = $this->answers[$i];
132 $newchoices[] = $answer;
133 for ($i = $order, $iMax = count($this->answers); $i < $iMax; $i++) {
134 $changed = $this->answers[$i];
135 $changed->setOrder($i + 1);
136 $newchoices[] = $changed;
138 $this->answers = $newchoices;
154 return count($this->answers);
171 if (count($this->answers) < 1) {
174 if ($index >= count($this->answers)) {
178 return $this->answers[$index];
194 if (count($this->answers) < 1) {
197 if ($index >= count($this->answers)) {
200 unset($this->answers[$index]);
201 $this->answers = array_values($this->answers);
202 for ($i = 0, $iMax = count($this->answers); $i < $iMax; $i++) {
203 if ($this->answers[$i]->
getOrder() > $index) {
204 $this->answers[$i]->setOrder($i);
229 foreach ($this->answers as $answer) {
230 if ($answer->getPoints() > 0) {
231 $points[] = $answer->getPoints();
252 $available_answers = [];
253 foreach ($this->answers as $answer) {
254 $available_answers[] = $answer->getAnswertext();
256 return $available_answers;
275 foreach ($answers as $key => $value) {
276 if ($this->answers[$key]->
getPoints() <= 0) {
279 $value = html_entity_decode($value); #SB
280 switch ($textrating) {
287 if (strcmp($value, $answer) == 0) {
292 $transformation =
$refinery->string()->levenshtein()->standard($answer, 1);
295 $transformation =
$refinery->string()->levenshtein()->standard($answer, 2);
298 $transformation =
$refinery->string()->levenshtein()->standard($answer, 3);
301 $transformation =
$refinery->string()->levenshtein()->standard($answer, 4);
304 $transformation =
$refinery->string()->levenshtein()->standard($answer, 5);
309 if (isset($transformation) && $transformation->transform($value) >= 0) {
342 bool $authorized_solution =
true
344 if ($pass === null) {
350 while (
$data = $this->db->fetchAssoc($result)) {
351 $enteredTexts[] =
$data[
'value1'];
359 $this->correctanswers = $a_correct_answers;
364 return $this->correctanswers;
370 bool $authorized =
true
372 if ($pass === null) {
376 $solution_submit = $this->getSolutionSubmit();
377 $this->getProcessLocker()->executeUserSolutionUpdateLockOperation(
378 function () use ($active_id, $pass, $authorized, $solution_submit) {
379 $this->removeCurrentSolution($active_id, $pass, $authorized);
381 foreach ($solution_submit as $value) {
383 $this->saveCurrentSolution($active_id, $pass, $value,
null, $authorized);
395 $this->db->manipulateF(
396 "DELETE FROM " . $this->getAdditionalTableName() .
" WHERE question_fi = %s",
401 $this->db->manipulateF(
402 "INSERT INTO " . $this->getAdditionalTableName(
403 ) .
" (question_fi, textgap_rating, correctanswers) VALUES (%s, %s, %s)",
404 [
"integer",
"text",
"integer" ],
407 $this->getTextRating(),
408 $this->getCorrectAnswers()
415 $this->db->manipulateF(
416 "DELETE FROM qpl_a_textsubset WHERE question_fi = %s",
421 foreach ($this->answers as $key => $value) {
422 $answer_obj = $this->answers[$key];
423 $next_id = $this->db->nextId(
'qpl_a_textsubset');
424 $this->db->manipulateF(
425 "INSERT INTO qpl_a_textsubset (answer_id, question_fi, answertext, points, aorder, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
426 [
'integer',
'integer',
'text',
'float',
'integer',
'integer' ],
430 $answer_obj->getAnswertext(),
431 $answer_obj->getPoints(),
432 $answer_obj->getOrder(),
447 return "assTextSubset";
457 foreach ($this->answers as $answer) {
458 $key = $answer->getPoints() .
'';
460 if (!isset($join[$key]) || !is_array($join[$key])) {
464 $join[$key][] = $answer->getAnswertext();
479 foreach ($this->answers as $answer) {
480 $len = strlen($answer->getAnswertext());
481 if ($len > $maxwidth) {
485 return $maxwidth + 3;
496 return "qpl_qst_textsubset";
507 return "qpl_a_textsubset";
516 return parent::getRTETextWithMediaObjects();
521 return $this->answers;
530 $result[
'id'] = $this->
getId();
531 $result[
'type'] = (string) $this->getQuestionType();
532 $result[
'title'] = $this->getTitleForHTMLOutput();
533 $result[
'question'] = $this->formatSAQuestion($this->getQuestion());
534 $result[
'nr_of_tries'] = $this->getNrOfTries();
535 $result[
'matching_method'] = $this->getTextRating();
536 $result[
'feedback'] = [
537 'onenotcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
538 'allcorrect' => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
542 foreach ($this->getAnswers() as $key => $answer_obj) {
544 "answertext" => (string) $answer_obj->getAnswertext(),
545 "points" => (float) $answer_obj->getPoints(),
546 "order" => (
int) $answer_obj->getOrder()
549 $result[
'correct_answers'] = $answers;
552 for ($loop = 1; $loop <= $this->getCorrectAnswers(); $loop++) {
557 $result[
'answers'] = $answers;
560 $result[
'mobs'] = $mobs;
562 return json_encode($result);
570 $purifier = $this->getHtmlUserSolutionPurifier();
571 $post = $this->dic->http()->wrapper()->post();
573 $solutionSubmit = [];
574 foreach ($this->getAnswers() as $index =>
$a) {
575 if (
$post->has(
"TEXTSUBSET_$index")) {
576 $value =
$post->retrieve(
578 $this->dic->refinery()->kindlyTo()->string()
581 $value = $this->extendedTrim($value);
582 $value = $purifier->purify($value);
583 $solutionSubmit[] = $value;
588 return $solutionSubmit;
593 $enteredTexts ??= [];
594 $available_answers = $this->getAvailableAnswers();
596 foreach ($enteredTexts as $enteredtext) {
597 $index = $this->isAnswerCorrect($available_answers, html_entity_decode($enteredtext));
598 if ($index !==
false) {
599 unset($available_answers[$index]);
600 $points += $this->answers[$index]->getPoints();
627 $maxStep = $this->lookupMaxStep($active_id, $pass);
629 $data = $this->db->queryF(
630 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s AND step = %s ORDER BY solution_id",
631 [
"integer",
"integer",
"integer",
"integer"],
632 [$active_id, $pass, $this->
getId(), $maxStep]
635 $data = $this->db->queryF(
636 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s ORDER BY solution_id",
637 [
"integer",
"integer",
"integer"],
638 [$active_id, $pass, $this->
getId()]
642 for ($index = 1; $index <= $this->db->numRows(
$data); ++$index) {
643 $row = $this->db->fetchAssoc(
$data);
644 $result->addKeyValue($index, $row[
"value1"]);
647 $points = $this->calculateReachedPoints($active_id, $pass);
648 $max_points = $this->getMaximumPoints();
650 $result->setReachedPercentage(($points / $max_points) * 100);
663 if ($index !==
null) {
664 return $this->getAnswer($index);
666 return $this->getAnswers();
674 foreach ($this->getAnswers() as $item) {
675 if ($answerOptionValue !== $item->getAnswerText()) {
688 $this->addAnswer($answerOptionValue, $points, $qIndex);
694 AdditionalInformationGenerator::KEY_QUESTION_TYPE => (string) $this->getQuestionType(),
695 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $this->getTitleForHTMLOutput(),
696 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $this->formatSAQuestion($this->getQuestion()),
697 AdditionalInformationGenerator::KEY_QUESTION_TEXT_MATCHING_METHOD => $additional_info->
getTagForLangVar(
698 $this->getMatchingMethodLangVar($this->getTextRating())
700 AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTIONS => array_map(
702 AdditionalInformationGenerator::KEY_QUESTION_ANSWER_OPTION => $answer->
getAnswertext(),
703 AdditionalInformationGenerator::KEY_QUESTION_REACHABLE_POINTS => $answer->
getPoints()
707 AdditionalInformationGenerator::KEY_FEEDBACK => [
708 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_INCOMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
709 AdditionalInformationGenerator::KEY_QUESTION_FEEDBACK_ON_COMPLETE => $this->formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
716 switch ($matching_method) {
718 return 'cloze_textgap_case_insensitive';
720 return 'cloze_textgap_case_sensitive';
722 return 'cloze_textgap_levenshtein_of:1';
724 return 'cloze_textgap_levenshtein_of:2';
726 return 'cloze_textgap_levenshtein_of:3';
728 return 'cloze_textgap_levenshtein_of:4';
730 return 'cloze_textgap_levenshtein_of:5';
738 array $solution_values
741 static fn(array $v): string => $v[
'value1'],
749 static fn(array $v):
string => $v[
'value1'],
756 return $this->getAvailableAnswers();
Class for answers with a binary state indicator.
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)
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 TextSubset questions.
getExpressionTypes()
Get all available expression types for a specific question.
getMaxTextboxWidth()
Returns the maximum width needed for the answer textboxes.
setCorrectAnswers(int $a_correct_answers)
getMaximumPoints()
Returns the maximum points, a learner can reach answering the question.
getAdditionalTableName()
Returns the name of the additional question data table in the database.
isAnswerCorrect($answers, $answer)
Returns the index of the found answer, if the given answer is in the set of correct answers and match...
loadFromDb(int $question_id)
getCorrectSolutionForTextOutput(int $active_id, int $pass)
& joinAnswers()
Returns the answers of the question as a comma separated string.
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
toJSON()
Returns a JSON representation of the question.
deleteAnswer($index=0)
Deletes an answer with a given index.
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.
saveToDb(?int $original_id=null)
addAnswerOptionValue(int $qIndex, string $answerOptionValue, float $points)
saveWorkingData(int $active_id, ?int $pass=null, bool $authorized=true)
calculateReachedPoints(int $active_id, ?int $pass=null, bool $authorized_solution=true)
getOperators(string $expression)
Get all available operations for a specific question.
calculateReachedPointsForSolution(?array $enteredTexts)
setTextRating(string $text_rating)
addAnswer($answertext, $points, $order)
Adds an answer to the question.
getAnswerTableName()
Returns the name of the answer table in the database.
getUserQuestionResult(int $active_id, int $pass)
Get the user solution for a question by active_id and the test pass.
getAvailableAnswers()
Returns the available answers for the question.
getMatchingMethodLangVar(string $matching_method)
getQuestionType()
Returns the question type of the question.
getAnswerCount()
Returns the number of answers.
solutionValuesToText(array $solution_values)
MUST convert the given solution values into text.
flushAnswers()
Deletes all answers.
getAvailableAnswerOptions($index=null)
If index is null, the function returns an array with all anwser options Else it returns the specific ...
saveAnswerSpecificDataToDb()
Saves the answer specific records into a question types answer table.
getRTETextWithMediaObjects()
Collects all text in the question which could contain media objects which were created with the Rich ...
isAddableAnswerOptionValue(int $qIndex, string $answerOptionValue)
toLog(AdditionalInformationGenerator $additional_info)
MUST return an array of the question settings that can be stored in the log.
getAnswer($index=0)
Returns an answer with a given index.
static getDraftInstance()
static getInstance($identifier)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static getOperatorsByExpression(string $expression)
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 strToLower(string $a_string)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
return['delivery_method'=> 'php',]
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...
const PercentageResultExpression
const StringResultExpression
const NumericResultExpression
const EmptyAnswerExpression
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...
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
if(!file_exists('../ilias.ini.php'))