69 $this->shuffleAnswersEnabled =
true;
70 $this->answerType = self::ANSWER_TYPE_SINGLE_LINE;
71 $this->thumbSize = self::DEFAULT_THUMB_SIZE;
72 $this->scorePartialSolutionEnabled =
true;
73 $this->optionLabel = self::OPTION_LABEL_RIGHT_WRONG;
74 $this->customTrueOptionLabel =
'';
75 $this->customFalseOptionLabel =
'';
84 return 'assKprimChoice';
89 return "qpl_qst_kprim";
183 $answer->setAnswertext(
188 $this->answers = array_map($clean_answer_text,
$answers);
199 if ($answer->getPosition() == $position) {
212 $this->answers[] = $answer;
219 while (
$data = $this->db->fetchAssoc(
$res)) {
220 $this->
setId($questionId);
241 if (is_numeric($data[
'thumb_size'])) {
249 if ($data[
'custom_true'] !== null) {
253 if ($data[
'custom_false'] !== null) {
257 if ($data[
'score_partsol'] !== null) {
261 if (isset($data[
'feedback_setting'])) {
279 parent::loadFromDb($questionId);
285 $ilDB = $DIC[
'ilDB'];
287 $res = $this->db->queryF(
288 "SELECT * FROM {$this->getAnswerTableName()} WHERE question_fi = %s ORDER BY position ASC",
296 $answer->setPosition(
$data[
'position']);
300 $answer->setImageFile(
$data[
'imagefile']);
301 $answer->setThumbPrefix($this->getThumbPrefix());
305 $answer->setCorrectness(
$data[
'correctness']);
307 $this->answers[$answer->getPosition()] = $answer;
310 for ($i = count($this->answers); $i < self::NUM_REQUIRED_ANSWERS; $i++) {
313 $answer->setPosition($i);
315 $this->answers[$answer->getPosition()] = $answer;
321 if ($originalId ==
'') {
330 parent::saveToDb($originalId);
338 'question_fi' => [
'integer', $this->
getId()]
359 'question_fi' => [
'integer', $this->
getId()],
360 'position' => [
'integer', (
int) $answer->getPosition()]
363 'answertext' => [
'text', $answer->getAnswertext()],
364 'imagefile' => [
'text', $answer->getImageFile()],
365 'correctness' => [
'integer', (
int) $answer->getCorrectness()]
373 foreach ([$this->title, $this->author, $this->question] as $text) {
374 if (!strlen($text)) {
379 if (!isset($this->points)) {
386 if (is_null($answer->getCorrectness())) {
391 (!is_string($answer->getAnswertext()) || $answer->getAnswertext() ===
'') &&
392 (!is_string($answer->getImageFile()) || $answer->getImageFile() ===
'')
409 public function saveWorkingData($active_id, $pass = null, $authorized =
true):
bool 414 if ($pass === null) {
420 $this->
getProcessLocker()->executeUserSolutionUpdateLockOperation(
function () use (&$entered_values, $active_id, $pass, $authorized) {
425 foreach ($solutionSubmit as $answerIndex => $answerValue) {
426 if ($answerValue !== null) {
427 $this->
saveCurrentSolution($active_id, $pass, (
int) $answerIndex, (
int) $answerValue, $authorized);
433 if ($entered_values) {
437 "log_user_entered_values",
439 ), $active_id, $this->
getId());
445 "log_user_not_entered_values",
447 ), $active_id, $this->
getId());
464 public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution =
true, $returndetails =
false): float
466 if ($returndetails) {
467 throw new ilTestException(
'return details not implemented for ' . __METHOD__);
471 $ilDB = $DIC[
'ilDB'];
474 if (is_null($pass)) {
481 $found_values[(
int)
$data[
'value1']] = (
int)
$data[
'value2'];
491 return [self::ANSWER_TYPE_SINGLE_LINE, self::ANSWER_TYPE_MULTI_LINE];
512 self::ANSWER_TYPE_SINGLE_LINE => $lng->
txt(
'answers_singleline'),
513 self::ANSWER_TYPE_MULTI_LINE => $lng->
txt(
'answers_multiline')
520 self::OPTION_LABEL_RIGHT_WRONG,
521 self::OPTION_LABEL_PLUS_MINUS,
522 self::OPTION_LABEL_APPLICABLE_OR_NOT,
523 self::OPTION_LABEL_ADEQUATE_OR_NOT,
524 self::OPTION_LABEL_CUSTOM
531 self::OPTION_LABEL_RIGHT_WRONG => $lng->
txt(
'option_label_right_wrong'),
532 self::OPTION_LABEL_PLUS_MINUS => $lng->
txt(
'option_label_plus_minus'),
533 self::OPTION_LABEL_APPLICABLE_OR_NOT => $lng->
txt(
'option_label_applicable_or_not'),
534 self::OPTION_LABEL_ADEQUATE_OR_NOT => $lng->
txt(
'option_label_adequate_or_not'),
535 self::OPTION_LABEL_CUSTOM => $lng->
txt(
'option_label_custom')
548 case self::OPTION_LABEL_RIGHT_WRONG:
549 return $lng->
txt(
'option_label_right');
551 case self::OPTION_LABEL_PLUS_MINUS:
552 return $lng->
txt(
'option_label_plus');
554 case self::OPTION_LABEL_APPLICABLE_OR_NOT:
555 return $lng->
txt(
'option_label_applicable');
557 case self::OPTION_LABEL_ADEQUATE_OR_NOT:
558 return $lng->
txt(
'option_label_adequate');
560 case self::OPTION_LABEL_CUSTOM:
569 case self::OPTION_LABEL_RIGHT_WRONG:
570 return $lng->
txt(
'option_label_wrong');
572 case self::OPTION_LABEL_PLUS_MINUS:
573 return $lng->
txt(
'option_label_minus');
575 case self::OPTION_LABEL_APPLICABLE_OR_NOT:
576 return $lng->
txt(
'option_label_not_applicable');
578 case self::OPTION_LABEL_ADEQUATE_OR_NOT:
579 return $lng->
txt(
'option_label_not_adequate');
581 case self::OPTION_LABEL_CUSTOM:
590 $lng->
txt(
'kprim_instruction_text'),
598 return $labelValue == self::OPTION_LABEL_CUSTOM;
606 if (!isset($files[$answer->getPosition()])) {
618 if (!file_exists($imagePath)) {
640 if (file_exists($answer->getImageFsPath())) {
644 if (file_exists($answer->getThumbFsPath())) {
648 $answer->setImageFile(null);
653 $solutionSubmit = [];
654 $post = $this->dic->http()->wrapper()->post();
657 if (
$post->has(
"kprim_choice_result_$index")) {
658 $value =
$post->retrieve(
659 "kprim_choice_result_$index",
660 $this->dic->refinery()->kindlyTo()->string()
662 if (is_numeric($value)) {
663 $solutionSubmit[] = $value;
666 $solutionSubmit[] = null;
669 return $solutionSubmit;
675 if ($found_values == null) {
679 if (!isset($found_values[$answer->getPosition()])) {
683 if ($found_values[$answer->getPosition()] == $answer->getCorrectness()) {
688 if ($numCorrect >= self::NUM_REQUIRED_ANSWERS) {
697 if (count($found_values) == 0) {
706 if ($this->
id <= 0) {
711 $this_id = $this->
getId();
716 $original_id = $this->questioninfo->getOriginalId($this->
id);
719 if ((
int) $testObjId > 0) {
720 $clone->setObjId($testObjId);
741 $clone->copyPageOfQuestion($this_id);
743 $clone->copyXHTMLMediaObjectsOfQuestion($this_id);
745 $clone->cloneAnswerImages($this_id, $thisObjId, $clone->getId(), $clone->getObjId());
747 $clone->onDuplicate($thisObjId, $this_id, $clone->getObjId(), $clone->getId());
754 if ($this->
getId() <= 0) {
755 throw new RuntimeException(
'The question has not been saved. It cannot be duplicated');
759 $source_parent_id = $this->
getObjId();
765 $clone->setObjId($target_parent_id);
767 if ($target_question_title) {
768 $clone->setTitle($target_question_title);
773 $clone->copyPageOfQuestion($source_question_id);
775 $clone->copyXHTMLMediaObjectsOfQuestion($source_question_id);
777 $clone->cloneAnswerImages($source_question_id, $source_parent_id, $clone->getId(), $clone->getObjId());
779 $clone->onCopy($source_parent_id, $source_question_id, $target_parent_id, $clone->getId());
789 if ($this->
getId() <= 0) {
790 throw new RuntimeException(
'The question has not been saved. It cannot be duplicated');
795 $original_id = $this->questioninfo->getOriginalId($this->
id);
797 $source_questionpool_id = $this->
getObjId();
798 $clone->setObjId($target_questionpool_id);
808 $clone->cloneAnswerImages(
$original_id, $source_questionpool_id, $clone->getId(), $clone->getObjId());
810 $clone->onCopy($source_questionpool_id,
$original_id, $clone->getObjId(), $clone->getId());
817 parent::beforeSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId);
819 $question = self::instantiateQuestion($origQuestionId);
821 foreach (
$question->getAnswers() as $answer) {
822 $question->removeAnswerImage($answer->getPosition());
828 parent::afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId);
830 $this->cloneAnswerImages($dupQuestionId, $dupParentObjId, $origQuestionId, $origParentObjId);
833 protected function cloneAnswerImages(
843 $source_path = $this->questionFilesService->buildImagePath($source_question_id, $source_parent_id);
844 $target_path = $this->questionFilesService->buildImagePath($target_question_id, $target_parent_id);
853 if (!file_exists($target_path)) {
857 if (file_exists($source_path .
$filename)) {
858 if (!copy($source_path . $filename, $target_path . $filename)) {
860 "Could not clone source image '%s' to '%s' (srcQuestionId: %s|tgtQuestionId: %s|srcParentObjId: %s|tgtParentObjId: %s)",
861 $source_path . $filename,
862 $target_path . $filename,
871 if (file_exists($source_path . $this->getThumbPrefix() . $filename)) {
872 if (!copy($source_path . $this->getThumbPrefix() . $filename, $target_path . $this->getThumbPrefix() . $filename)) {
874 "Could not clone thumbnail source image '%s' to '%s' (srcQuestionId: %s|tgtQuestionId: %s|srcParentObjId: %s|tgtParentObjId: %s)",
875 $source_path . $this->getThumbPrefix() . $filename,
876 $target_path . $this->getThumbPrefix() . $filename,
889 $combinedText = parent::getRTETextWithMediaObjects();
892 $combinedText .= $answer->getAnswertext();
895 return $combinedText;
914 $this->
lng->loadLanguageModule(
'assessment');
917 $result[
'id'] = $this->
getId();
927 $result[
'feedback'] = [
928 'onenotcorrect' => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
false)),
929 'allcorrect' => $this->
formatSAQuestion($this->feedbackOBJ->getGenericFeedbackTestPresentation($this->getId(),
true))
941 if (strlen((
string) $answer->getImageFile())) {
947 'correctness' => (
bool) $answer->getCorrectness(),
948 'order' => (
int) $answer->getPosition(),
949 'image' => (string) $answer->getImageFile(),
951 $this->feedbackOBJ->getSpecificAnswerFeedbackExportPresentation($this->getId(), 0,
$key)
964 $result[
'mobs'] = $mobs;
966 return json_encode($result);
972 return self::NUM_REQUIRED_ANSWERS - self::PARTIAL_SCORING_NUM_CORRECT_ANSWERS;
980 return 'feedback_correct_kprim';
993 parent::setExportDetailsXLSX($worksheet, $startrow, $col, $active_id, $pass);
999 $worksheet->
setCell($startrow + $i, $col, $answer->getAnswertext());
1001 $correctness =
false;
1002 foreach ($solution as $solutionvalue) {
1003 if (
$id == $solutionvalue[
'value1']) {
1004 $correctness = $solutionvalue[
'value2'];
1008 $worksheet->
setCell($startrow + $i, $col + 2, $correctness);
1012 return $startrow + $i + 1;
1017 if ($position < 0 || $position >= (self::NUM_REQUIRED_ANSWERS - 1)) {
1021 for ($i = 0, $max = count($this->answers); $i < $max; $i++) {
1022 if ($i == $position) {
1023 $movingAnswer = $this->answers[$i];
1024 $targetAnswer = $this->answers[ $i + 1 ];
1026 $movingAnswer->setPosition($position + 1);
1027 $targetAnswer->setPosition($position);
1029 $this->answers[ $i + 1 ] = $movingAnswer;
1030 $this->answers[$i] = $targetAnswer;
1038 if ($position <= 0 || $position > (self::NUM_REQUIRED_ANSWERS - 1)) {
1042 for ($i = 0, $max = count($this->answers); $i < $max; $i++) {
1043 if ($i == $position) {
1044 $movingAnswer = $this->answers[$i];
1045 $targetAnswer = $this->answers[ $i - 1 ];
1047 $movingAnswer->setPosition($position - 1);
1048 $targetAnswer->setPosition($position);
1050 $this->answers[ $i - 1 ] = $movingAnswer;
1051 $this->answers[$i] = $targetAnswer;
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...
getValidOptionLabelsTranslated(ilLanguage $lng)
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)
static getInstance($identifier)
setImageFsDir($imageFsDir)
isValidAnswerType($answerType)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
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.
getRTETextWithMediaObjects()
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
setImageFile(?string $imageFile)
setScorePartialSolutionEnabled($scorePartialSolutionEnabled)
const OPTION_LABEL_RIGHT_WRONG
isCustomOptionLabel($labelValue)
Abstract basic class which is to be extended by the concrete assessment question type classes...
__construct($title='', $comment='', $author='', $owner=-1, $question='')
saveWorkingData(int $active_id, int $pass, bool $authorized=true)
Saves the learners input of the question to the database.
getColumnCoord(int $a_col)
Get column "name" from number.
const OPTION_LABEL_ADEQUATE_OR_NOT
const NUM_REQUIRED_ANSWERS
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getImagePathWeb()
Returns the web image path for web accessable images of a question.
const PARTIAL_SCORING_NUM_CORRECT_ANSWERS
removeAnswerImage($position)
lmMigrateQuestionTypeSpecificContent(ilAssSelfAssessmentMigrator $migrator)
getSpecificFeedbackSetting()
migrateToLmContent($content)
moveAnswerDown($position)
copyObject($target_questionpool_id, $title="")
Copies an assMultipleChoice object.
getSpecificFeedbackAllCorrectOptionLabel()
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setCustomTrueOptionLabel($customTrueOptionLabel)
isValidOptionLabel($optionLabel)
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
loadAnswerData($questionId)
setComment(string $comment="")
getTrueOptionLabelTranslation(ilLanguage $lng, $optionLabel)
float $points
The maximum available points for the question.
beforeSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
addAnswer(ilAssKprimChoiceAnswer $answer)
Base Exception for all Exceptions relating to Modules/Test.
setOptionLabel($optionLabel)
createNewOriginalFromThisDuplicate($target_parent_id, $target_question_title="")
const ANSWER_TYPE_MULTI_LINE
isScorePartialSolutionEnabled()
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
setBold(string $a_coords)
Set cell(s) to bold.
static _enabledAssessmentLogging()
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
buildHashedImageFilename(string $plain_image_filename, bool $unique=false)
isSingleLineAnswerType($answerType)
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
getAnswerTypeSelectOptions(ilLanguage $lng)
static logAction(string $logtext, int $active_id, int $question_id)
isShuffleAnswersEnabled()
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
setShuffleAnswersEnabled($shuffleAnswersEnabled)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
const OPTION_LABEL_APPLICABLE_OR_NOT
getCustomFalseOptionLabel()
handleFileUploads($answers, $files)
static moveUploadedFile(string $a_file, string $a_name, string $a_target, bool $a_raise_errors=true, string $a_mode="move_uploaded")
move uploaded file
string $question
The question text.
setCustomFalseOptionLabel($customFalseOptionLabel)
getFalseOptionLabelTranslation(ilLanguage $lng, $optionLabel)
saveQuestionDataToDb(int $original_id=-1)
const OPTION_LABEL_CUSTOM
getSolutionMaxPass(int $active_id)
calculateReachedPointsForSolution($found_values, $active_id=0)
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
const FEEDBACK_SETTING_ALL
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
setSpecificFeedbackSetting($specificFeedbackSetting)
duplicate(bool $for_test=true, string $title="", string $author="", int $owner=-1, $testObjId=null)
setOriginalId(?int $original_id)
setTitle(string $title="")
setLastChange($lastChange)
$a
thx to https://mlocati.github.io/php-cs-fixer-configurator for the examples
setThumbSize(int $thumbSize)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
getCustomTrueOptionLabel()
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
handleFileUpload(ilAssKprimChoiceAnswer $answer, $fileData)
saveAdditionalQuestionDataToDb()
Saves a record to the question types additional data table.
$scorePartialSolutionEnabled
ILIAS DI LoggingServices $ilLog
getHtmlQuestionContentPurifier()
setAuthor(string $author="")
const OPTION_LABEL_PLUS_MINUS
static isObligationPossible(int $questionId)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
setAnswerType($answerType)
setExportDetailsXLSX(ilAssExcelFormatHelper $worksheet, int $startrow, int $col, int $active_id, int $pass)
{}
getInstructionTextTranslation(ilLanguage $lng, $optionLabel)
static getDraftInstance()
const ANSWER_TYPE_SINGLE_LINE
toJSON()
Returns a JSON representation of the question.
afterSyncWithOriginal($origQuestionId, $dupQuestionId, $origParentObjId, $dupParentObjId)
setAnswertext($answertext)
setQuestion(string $question="")