30 require_once
'./Modules/Test/classes/inc.AssessmentConstants.php';
176 string $comment =
"",
179 string $question =
"" 185 $ilDB = $DIC[
'ilDB'];
186 $ilLog = $DIC->logger();
187 $this->questioninfo = $DIC->testQuestionPool()->questionInfo();
188 $this->questionFilesService = $DIC->testQuestionPool()->questionFiles();
189 $this->testParticipantInfo = $DIC->test()->testParticipantInfo();
190 $this->current_user = $DIC[
'ilUser'];
195 $this->
http = $DIC->http();
198 $this->thumb_size = self::DEFAULT_THUMB_SIZE;
209 $this->suggested_solutions = [];
211 $this->nr_of_tries = 0;
214 $this->questionActionCmd =
'handleQuestionAction';
215 $this->export_image_path =
'';
216 $this->shuffler = $DIC->refinery()->random()->dontShuffle();
218 $this->skillUsageService = $DIC->skills()->usage();
230 return self::$forcePassResultsUpdateEnabled;
235 if (!isset($_POST[
'cmd']) || !isset($_POST[
'cmd'][$this->questionActionCmd])) {
239 if (!is_array($_POST[
'cmd'][$this->questionActionCmd]) || $_POST[
'cmd'][$this->questionActionCmd] === []) {
243 return key($_POST[
'cmd'][$this->questionActionCmd]);
248 if (!isset($_POST[$postSubmissionFieldname])) {
252 if (!is_array($_POST[$postSubmissionFieldname])) {
256 if (!count($_POST[$postSubmissionFieldname])) {
263 protected function log(
int $active_id,
string $langVar): void
301 public function fromXML($item,
int $questionpool_id, ?
int $tst_id, &$tst_object,
int &$question_counter, array $import_mapping, array &$solutionhints = []): array
304 $import =
new $classname($this);
305 $import_mapping = $import->fromXML($item, $questionpool_id, $tst_id, $tst_object, $question_counter, $import_mapping);
307 foreach ($solutionhints as $hint) {
308 $this->
importHint($import->getQuestionId(), $hint);
310 return $import_mapping;
313 private function importHint(
int $question_id, array $hint_array): void
316 $hint->setQuestionId($question_id);
317 $hint->setIndex($hint_array[
'index'] ??
'');
318 $hint->setPoints($hint_array[
'points'] ??
'');
322 $hint_page->setParentId($question_id);
323 $hint_page->setId($hint->getId());
324 $hint_page->setXMLContent($hint_array[
'txt']);
325 $hint_page->createFromXML();
329 $hint->setText($hint_array[
'txt'] ??
'');
339 bool $a_include_header =
true,
340 bool $a_include_binary =
true,
341 bool $a_shuffle =
false,
342 bool $test_output =
false,
343 bool $force_image_references =
false 346 $export =
new $classname($this);
347 return $export->toXML($a_include_header, $a_include_binary, $a_shuffle, $test_output, $force_image_references);
362 public function setId(
int $id = -1): void
369 $this->test_id =
$id;
379 $this->shuffle = $shuffle ??
false;
384 if ($author ===
'') {
385 $author = $this->current_user->getFullname();
402 return htmlspecialchars($this->title);
432 return htmlspecialchars($this->
comment);
442 if ($a_size >= self::MINIMUM_THUMB_SIZE) {
443 $this->thumb_size = $a_size;
445 throw new ilException(
"Thumb size must be at least " . self::MINIMUM_THUMB_SIZE .
"px");
451 return self::MINIMUM_THUMB_SIZE;
456 return self::MAXIMUM_THUMB_SIZE;
466 return $this->
refinery->string()->stripTags()->transform($this->author);
501 if ($this->external_id === null || $this->external_id ===
'') {
502 if ($this->
getId() > 0) {
505 return uniqid(
'',
true);
512 $question = self::instantiateQuestion($question_id);
513 if (!is_object($question)) {
516 return $question->getSuggestedSolutionOutput();
522 foreach ($this->suggested_solutions as $solution) {
523 switch ($solution->getType()) {
524 case assQuestionSuggestedSolution::TYPE_LM:
525 case assQuestionSuggestedSolution::TYPE_LM_CHAPTER:
526 case assQuestionSuggestedSolution::TYPE_LM_PAGE:
527 case assQuestionSuggestedSolution::TYPE_GLOSARY_TERM:
528 $output[] =
'<a href="' 531 . $this->
lng->txt(
"solution_hint")
535 case assQuestionSuggestedSolution::TYPE_FILE:
536 $possible_texts = array_values(
541 $this->
lng->txt(
'tst_show_solution_suggested')
547 $output[] =
'<a href="' 557 return implode(
"<br />", $output);
568 $ilDB = $DIC[
'ilDB'];
572 $result =
$ilDB->queryF(
573 "SELECT * FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
574 array(
'integer',
'integer',
'integer'),
575 array($active_id, $question_id, $pass)
577 if ($result->numRows() == 1) {
578 $row =
$ilDB->fetchAssoc($result);
579 $points = (float) $row[
"points"];
586 return round(self::_getReachedPoints($active_id, $this->
getId(), $pass), 2);
606 $requestsStatisticData = $hintTracking->getRequestStatisticDataByQuestionAndTestpass();
607 $reached_points = $reached_points - $requestsStatisticData->getRequestsPoints();
612 return $reached_points;
623 $requestsStatisticData = $questionHintTracking->getRequestStatisticDataByQuestionAndTestpass();
624 $reached_points = $reached_points - $requestsStatisticData->getRequestsPoints();
630 $isAnswered = $this->
isAnswered($active_id, $pass);
635 if (is_null($reached_points)) {
636 $reached_points = 0.0;
643 function () use ($active_id, $pass, $reached_points, $requestsStatisticData, $isAnswered, $existingSolutions) {
645 DELETE FROM tst_test_result 652 $types = [
'integer',
'integer',
'integer'];
653 $values = [$active_id, $this->
getId(), $pass];
655 if ($this->
getStep() !== null) {
660 $types[] =
'integer';
663 $this->db->manipulateF($query, $types, $values);
665 if ($existingSolutions[
'authorized']) {
666 $next_id = $this->db->nextId(
"tst_test_result");
668 'test_result_id' => array(
'integer', $next_id),
669 'active_fi' => array(
'integer', $active_id),
670 'question_fi' => array(
'integer', $this->
getId()),
671 'pass' => array(
'integer', $pass),
672 'points' => array(
'float', $reached_points),
673 'tstamp' => array(
'integer', time()),
674 'hint_count' => array(
'integer', $requestsStatisticData->getRequestsCount()),
675 'hint_points' => array(
'float', $requestsStatisticData->getRequestsPoints()),
676 'answered' => array(
'integer', $isAnswered)
679 if ($this->
getStep() !== null) {
680 $fieldData[
'step'] = array(
'integer', $this->
getStep());
683 $this->db->insert(
'tst_test_result', $fieldData);
693 "log_user_answered_question",
708 $test->updateTestPassResults($active_id, $pass, $obligationsEnabled, $this->
getProcessLocker());
716 final public function persistWorkingState(
int $active_id, $pass,
bool $obligationsEnabled =
false,
bool $authorized =
true): bool
724 $this->
getProcessLocker()->executePersistWorkingStateLockOperation(
function () use ($active_id, $pass, $authorized, $obligationsEnabled, &$saveStatus) {
725 if ($pass === null) {
765 abstract public function saveWorkingData(
int $active_id,
int $pass,
bool $authorized =
true): bool;
772 public static function logAction(
string $logtext,
int $active_id,
int $question_id): void
775 $original_id = $DIC->testQuestionPool()->questionInfo()->getOriginalId($question_id);
778 $DIC->user()->getId(),
788 return CLIENT_WEB_DIR .
"/assessment/$this->obj_id/$this->id/solution/";
795 public function getImagePath($question_id = null, $object_id = null): string
797 if ($question_id === null) {
801 if ($object_id === null) {
805 return $this->questionFilesService->buildImagePath($question_id, $object_id);
825 if (!$this->export_image_path) {
850 if (!count($solution)) {
864 if ($pass === null && is_numeric($active_id)) {
868 if ($this->
getStep() !== null) {
877 ORDER BY solution_id";
879 $result = $this->db->queryF(
881 array(
'integer',
'integer',
'integer',
'integer',
'integer'),
882 array((
int) $active_id, $this->
getId(), $pass, $this->
getStep(), (
int) $authorized)
895 $result = $this->db->queryF(
897 array(
'integer',
'integer',
'integer',
'integer'),
898 array((
int) $active_id, $this->
getId(), $pass, (
int) $authorized)
904 while ($row = $this->db->fetchAssoc($result)) {
925 if (!is_array($answer_table_name)) {
926 $answer_table_name = array($answer_table_name);
929 foreach ($answer_table_name as $table) {
930 if (strlen($table)) {
931 $this->db->manipulateF(
932 "DELETE FROM $table WHERE question_fi = %s",
944 if (!is_array($additional_table_name)) {
945 $additional_table_name = array($additional_table_name);
948 foreach ($additional_table_name as $table) {
949 if (strlen($table)) {
950 $this->db->manipulateF(
951 "DELETE FROM $table WHERE question_fi = %s",
967 public function delete(
int $question_id):
void 969 if ($question_id < 1) {
973 $result = $this->db->queryF(
974 "SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
978 if ($this->db->numRows($result) == 1) {
979 $row = $this->db->fetchAssoc($result);
980 $obj_id = $row[
"obj_fi"];
987 $this->
ilLog->root()->error(
"EXCEPTION: Could not delete page of question $question_id: $e");
991 $affectedRows = $this->db->manipulateF(
992 "DELETE FROM qpl_questions WHERE question_id = %s",
996 if ($affectedRows == 0) {
1006 $this->
ilLog->root()->error(
"EXCEPTION: Could not delete additional table data of question $question_id: $e");
1011 $affectedRows = $this->db->manipulateF(
1012 "DELETE FROM tst_test_question WHERE question_fi = %s",
1017 $this->
ilLog->root()->error(
"EXCEPTION: Could not delete delete question $question_id from a test: $e");
1023 $this->
ilLog->root()->error(
"EXCEPTION: Could not delete suggested solutions of question $question_id: $e");
1027 $directory =
CLIENT_WEB_DIR .
"/assessment/" . $obj_id .
"/$question_id";
1028 if (preg_match(
"/\d+/", $obj_id) and preg_match(
"/\d+/", $question_id) and is_dir($directory)) {
1032 $this->
ilLog->root()->error(
"EXCEPTION: Could not delete question file directory $directory of question $question_id: $e");
1041 foreach ($mobs as $mob) {
1049 $this->
ilLog->root()->error(
"EXCEPTION: Error deleting the media objects of question $question_id: $e");
1051 ilAssQuestionHintTracking::deleteRequestsByQuestionIds(array($question_id));
1054 $assignmentList->setParentObjId($obj_id);
1055 $assignmentList->setQuestionIdFilter($question_id);
1056 $assignmentList->loadFromDb();
1057 foreach ($assignmentList->getAssignmentsByQuestionId($question_id) as $assignment) {
1059 $assignment->deleteFromDb();
1062 if (!$assignment->isSkillUsed()) {
1063 $this->skillUsageService->removeUsage(
1064 $assignment->getParentObjId(),
1065 $assignment->getSkillBaseId(),
1066 $assignment->getSkillTrefId()
1077 $this->
ilLog->root()->error(
"EXCEPTION: Error updating the question pool question count of question pool " . $this->
getObjId() .
" when deleting question $question_id: $e");
1085 foreach ($taxIds as $taxId) {
1087 $taxNodeAssignment->deleteAssignmentsOfItem($this->
getId());
1094 $result = $this->db->queryF(
1095 "SELECT question_id FROM qpl_questions WHERE original_id = %s OR question_id = %s",
1096 array(
'integer',
'integer'),
1097 array($this->
id, $this->
id)
1099 if ($this->db->numRows($result) == 0) {
1103 while ($row = $this->db->fetchAssoc($result)) {
1104 $found_id[] = $row[
"question_id"];
1107 $result = $this->db->query(
"SELECT * FROM tst_test_result WHERE " . $this->db->in(
'question_fi', $found_id,
false,
'integer'));
1109 return $this->db->numRows($result);
1114 if (!file_exists($file)) {
1118 if (!is_file($file)) {
1122 if (!is_readable($file)) {
1132 foreach ($mobs as $mob) {
1140 foreach ($mobs as $mob) {
1149 $this->page->setId($this->
getId());
1150 $this->page->setParentId($qpl_id);
1151 $this->page->setXMLContent(
"<PageObject><PageContent>" .
1152 "<Question QRef=\"il__qst_" . $this->
getId() .
"\"/>" .
1153 "</PageContent></PageObject>");
1154 $this->page->create(
false);
1162 ilPCPlugged::handleCopiedPluggedContent(
$page,
$page->getDomDoc());
1163 $xml = str_replace(
"il__qst_" . $a_q_id,
"il__qst_" . $this->
id,
$page->getXMLFromDom());
1164 $this->page->setXMLContent($xml);
1165 $this->page->updateFromXML();
1172 return $page->getXMLContent();
1186 'ok.svg' =>
'ok.png',
1187 'not_ok.svg' =>
'not_ok.png',
1188 'object/checkbox_checked.svg' =>
'checkbox_checked.png',
1189 'object/checkbox_unchecked.svg' =>
'checkbox_unchecked.png',
1190 'object/radiobutton_checked.svg' =>
'radiobutton_checked.png',
1191 'object/radiobutton_unchecked.svg' =>
'radiobutton_unchecked.png' 1194 public function fixSvgToPng(
string $imageFilenameContainingString): string
1196 $needles = array_keys(self::$imageSourceFixReplaceMap);
1197 $replacements = array_values(self::$imageSourceFixReplaceMap);
1198 return str_replace($needles, $replacements, $imageFilenameContainingString);
1204 if (preg_match_all(
'/src="(.*?)"/m', $html, $matches)) {
1205 $sources = $matches[1];
1207 $needleReplacementMap = [];
1209 foreach ($sources as $src) {
1212 if (file_exists($file)) {
1216 $levels = explode(DIRECTORY_SEPARATOR, $src);
1217 if (count($levels) < 5 || $levels[0] !==
'Customizing' || $levels[2] !==
'skin') {
1223 if ($levels[4] ===
'Modules' || $levels[4] ===
'Services') {
1224 $component = $levels[4] . DIRECTORY_SEPARATOR . $levels[5];
1230 if (count($needleReplacementMap)) {
1231 $html = str_replace(array_keys($needleReplacementMap), array_values($needleReplacementMap), $html);
1240 $result = $this->db->queryF(
1241 'SELECT external_id FROM qpl_questions WHERE question_id = %s',
1245 if ($this->db->numRows($result) === 1) {
1246 $data = $this->db->fetchAssoc($result);
1247 $this->external_id =
$data[
'external_id'];
1251 $this->suggested_solutions = array();
1252 if ($suggested_solutions) {
1253 foreach ($suggested_solutions as $solution) {
1254 $this->suggested_solutions[$solution->getSubquestionIndex()] = $solution;
1270 $obj_id = ($this->
getObjId() <= 0) ? (
ilObject::_lookupObjId((strlen($this->dic->testQuestionPool()->internal()->request()->getRefId())) ? $this->dic->testQuestionPool()->internal()->request()->getRefId() : $_POST[
"sel_qpl"])) : $this->
getObjId();
1272 if ($a_create_page) {
1279 $next_id = $this->db->nextId(
'qpl_questions');
1280 $this->db->insert(
"qpl_questions", array(
1281 "question_id" => array(
"integer", $next_id),
1283 "obj_fi" => array(
"integer", $obj_id),
1284 "title" => array(
"text", null),
1285 "description" => array(
"text", null),
1286 "author" => array(
"text", $this->
getAuthor()),
1287 "owner" => array(
"integer", $ilUser->getId()),
1288 "question_text" => array(
"clob", null),
1289 "points" => array(
"float",
"0.0"),
1291 "complete" => array(
"text", $complete),
1292 "created" => array(
"integer", time()),
1293 "original_id" => array(
"integer", null),
1294 "tstamp" => array(
"integer", $tstamp),
1298 $this->
setId($next_id);
1300 if ($a_create_page) {
1306 return $this->
getId();
1311 if ($this->
getId() == -1) {
1312 $next_id = $this->db->nextId(
'qpl_questions');
1313 $this->db->insert(
"qpl_questions", array(
1314 "question_id" => array(
"integer", $next_id),
1316 "obj_fi" => array(
"integer", $this->
getObjId()),
1317 "title" => [
"text", mb_substr($this->
getTitle(), 0, 124)],
1318 "description" => [
"text", mb_substr($this->
getComment(), 0, 1000)],
1319 "author" => [
"text", mb_substr($this->
getAuthor(), 0, 512)],
1320 "owner" => array(
"integer", $this->
getOwner()),
1323 "nr_of_tries" => array(
"integer", $this->
getNrOfTries()),
1324 "created" => array(
"integer", time()),
1325 "original_id" => array(
"integer", ($original_id != -1) ? $original_id : null),
1326 "tstamp" => array(
"integer", time()),
1330 $this->
setId($next_id);
1335 $this->db->update(
"qpl_questions", array(
1336 "obj_fi" => array(
"integer", $this->
getObjId()),
1337 "title" => [
"text", mb_substr($this->
getTitle(), 0, 124)],
1338 "description" => [
"text", mb_substr($this->
getComment(), 0, 1000)],
1339 "author" => [
"text", mb_substr($this->
getAuthor(), 0, 512)],
1342 "nr_of_tries" => array(
"integer", $this->
getNrOfTries()),
1343 "tstamp" => array(
"integer", time()),
1344 'complete' => array(
'integer', $this->
isComplete()),
1347 "question_id" => array(
"integer", $this->
getId())
1365 'tstamp' => [
'integer', time()],
1366 'owner' => [
'integer', $this->
getOwner()],
1367 'complete' => [
'integer', $complete],
1368 'lifecycle' => [
'text', $this->
getLifecycle()->getIdentifier()],
1371 'question_id' => array(
'integer', $this->
getId())
1381 $ilDB = $DIC->database();
1382 $query =
"UPDATE qpl_questions SET tstamp = %s, original_id = %s WHERE question_id = %s";
1386 [
'integer',
'integer',
'text'],
1387 [time(), $originalId, $questionId]
1394 $ilDB = $DIC->database();
1396 $query =
"UPDATE qpl_questions SET tstamp = %s, original_id = NULL WHERE question_id = %s";
1400 [
'integer',
'text'],
1401 [time(), $questionId]
1405 protected function onDuplicate(
int $originalParentId,
int $originalQuestionId,
int $duplicateParentId,
int $duplicateQuestionId): void
1409 $this->feedbackOBJ->duplicateFeedback($originalQuestionId, $duplicateQuestionId);
1412 $this->
duplicateComments($originalParentId, $originalQuestionId, $duplicateParentId, $duplicateQuestionId);
1415 protected function beforeSyncWithOriginal(
int $origQuestionId,
int $dupQuestionId,
int $origParentObjId,
int $dupParentObjId): void
1419 protected function afterSyncWithOriginal(
int $origQuestionId,
int $dupQuestionId,
int $origParentObjId,
int $dupParentObjId): void
1421 $this->feedbackOBJ->syncFeedback($origQuestionId, $dupQuestionId);
1424 protected function onCopy(
int $sourceParentId,
int $sourceQuestionId,
int $targetParentId,
int $targetQuestionId): void
1428 $this->feedbackOBJ->duplicateFeedback($sourceQuestionId, $targetQuestionId);
1431 $this->
duplicateComments($sourceParentId, $sourceQuestionId, $targetParentId, $targetQuestionId);
1435 int $parent_source_id,
1437 int $parent_target_id,
1442 $notes = $manager->getNotesForRepositoryObjIds([$parent_source_id], Note::PUBLIC);
1443 $notes = array_filter(
1445 fn($n) => $n->getContext()->getSubObjId() === $source_id
1448 foreach ($notes as $note) {
1449 $new_context = $data_service->context(
1452 $note->getContext()->getType()
1454 $new_note = $data_service->note(
1460 $note->getCreationDate(),
1461 $note->getUpdateDate(),
1462 $note->getRecipient()
1464 $manager->createNote($new_note, [],
true);
1472 $source_id = $this->
getId();
1473 $notes = $manager->getNotesForRepositoryObjIds([$this->
getObjId()], Note::PUBLIC);
1474 $notes = array_filter(
1476 fn($n) => $n->getContext()->getSubObjId() === $source_id
1478 foreach ($notes as $note) {
1479 $repo->deleteNote($note->getId());
1486 return $service->internal()->domain()->notes();
1492 return $service->internal()->data();
1498 return $service->internal()->repo()->note();
1506 $this->suggested_solutions = [];
1512 if (array_key_exists($subquestion_index, $this->suggested_solutions)) {
1513 return $this->suggested_solutions[$subquestion_index];
1519 int $target_question_id,
1531 foreach ($this->suggested_solutions as $index => $solution) {
1532 if (!$solution->isOfTypeFile()) {
1537 $filepath_original = str_replace(
1538 "/{$this->obj_id}/{$this->id}/solution",
1539 "/$parent_id/$question_id/solution",
1542 if (!file_exists($filepath)) {
1547 !copy($filepath_original .
$filename, $filepath . $filename)) {
1548 $this->
ilLog->root()->error(
"File could not be duplicated!!!!");
1549 $this->
ilLog->root()->error(
"object: " . print_r($this,
true));
1555 int $target_question_id,
1559 $filepath_original = str_replace(
1560 "{$this->getObjId()}/{$this->id}/solution",
1561 "{$target_obj_id}/{$target_question_id}/solution",
1565 foreach ($this->suggested_solutions as $index => $solution) {
1566 if ($solution->isOfTypeFile()) {
1567 if (!file_exists($filepath_original)) {
1572 if (!@copy($filepath .
$filename, $filepath_original . $filename)) {
1573 $this->
ilLog->root()->error(
"File could not be duplicated!!!!");
1574 $this->
ilLog->root()->error(
"object: " . print_r($this,
true));
1583 foreach ($this->suggested_solutions as $index => $solution) {
1584 if ($solution->isOfTypeFile()) {
1586 $filepath_original = str_replace(
"/$this->obj_id/$this->id/solution",
"/$source_questionpool_id/$source_question_id/solution", $filepath);
1587 if (!file_exists($filepath)) {
1592 if (!copy($filepath_original .
$filename, $filepath . $filename)) {
1593 $this->
ilLog->root()->error(
"File could not be copied!!!!");
1594 $this->
ilLog->root()->error(
"object: " . print_r($this,
true));
1605 $solution = $solution->withQuestionId($target_question_id);
1606 $update[] = $solution;
1613 if (preg_match(
"/il_(\d+)_(\w+)_(\d+)/", $internal_link, $matches)) {
1614 switch ($matches[2]) {
1631 if ($resolved_link === null | $resolved_link === 0) {
1632 $resolved_link =
"il__{$matches[2]}_{$matches[3]}";
1635 $resolved_link = $internal_link;
1637 return $resolved_link ??
'';
1643 $result = $this->db->queryF(
1644 "SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
1646 array($this->
getId())
1648 if ($this->db->numRows($result) > 0) {
1649 while ($row = $this->db->fetchAssoc($result)) {
1650 $internal_link = $row[
"internal_link"];
1652 if ($internal_link !== $resolved_link) {
1654 $this->db->manipulateF(
1655 "UPDATE qpl_sol_sug SET internal_link = %s WHERE suggested_solution_id = %s",
1656 array(
'text',
'integer'),
1657 array($resolved_link, $row[
"suggested_solution_id"])
1663 if ($resolvedlinks) {
1668 $result = $this->db->queryF(
1669 "SELECT * FROM qpl_sol_sug WHERE question_fi = %s",
1671 array($this->
getId())
1673 if ($this->db->numRows($result) > 0) {
1674 while ($row = $this->db->fetchAssoc($result)) {
1675 if (preg_match(
"/il_(\d*?)_(\w+)_(\d+)/", $row[
"internal_link"], $matches)) {
1687 "lm" =>
"LearningModule",
1688 "pg" =>
"PageObject",
1689 "st" =>
"StructureObject",
1690 "git" =>
"GlossaryItem",
1691 "mob" =>
"MediaObject" 1694 if (preg_match(
"/il__(\w+)_(\d+)/", $target, $matches)) {
1695 $type = $matches[1];
1696 $target_id = $matches[2];
1697 switch ($linktypes[$matches[1]]) {
1699 $href =
"./ilias.php?baseClass=ilLMPresentationGUI&obj_type=" . $linktypes[$type]
1700 .
"&cmd=media&ref_id=" . $DIC->testQuestionPool()->internal()->request()->getRefId()
1701 .
"&mob_id=" . $target_id;
1703 case "StructureObject":
1704 case "GlossaryItem":
1706 case "LearningModule":
1708 $href =
"./goto.php?target=" . $type .
"_" . $target_id;
1718 if ($original_id === null) {
1722 $original_obj_id = self::lookupParentObjId($this->
getOriginalId());
1724 if (!$original_obj_id) {
1730 $original = clone $this;
1733 $original->setOriginalId(null);
1734 $original->setObjId($original_obj_id);
1736 $original->saveToDb();
1739 $original->createPageObject();
1740 $original->copyPageOfQuestion($this->
getId());
1756 $ilCtrl = $DIC[
'ilCtrl'];
1757 $ilDB = $DIC[
'ilDB'];
1759 $questioninfo = $DIC->testQuestionPool()->questionInfo();
1760 $question_type = $questioninfo->getQuestionType($question_id);
1761 if ($question_type ===
'') {
1765 $question =
new $question_type();
1766 $question->loadFromDb($question_id);
1768 $feedbackObjectClassname = self::getFeedbackClassNameByQuestionType($question_type);
1769 $question->feedbackOBJ =
new $feedbackObjectClassname($question, $ilCtrl,
$ilDB, $lng);
1776 if (strcmp($this->points,
"") == 0) {
1790 return self::_getSolutionMaxPass($this->
getId(), $active_id);
1802 $ilDB = $DIC[
'ilDB'];
1804 $result =
$ilDB->queryF(
1805 "SELECT MAX(pass) maxpass FROM tst_test_result WHERE active_fi = %s AND question_fi = %s",
1806 array(
'integer',
'integer'),
1807 array($active_id, $question_id)
1809 if ($result->numRows() === 1) {
1810 $row =
$ilDB->fetchAssoc($result);
1811 return $row[
"maxpass"];
1820 $ilDB = $DIC[
'ilDB'];
1822 if (($question_id < 1) || ($user_id < 1)) {
1826 $result =
$ilDB->queryF(
1827 "SELECT obj_fi FROM qpl_questions WHERE question_id = %s",
1831 if (
$ilDB->numRows($result) == 1) {
1832 $row =
$ilDB->fetchAssoc($result);
1833 $qpl_object_id = (
int) $row[
"obj_fi"];
1851 abstract public function calculateReachedPoints($active_id, $pass = null, $authorizedSolution =
true, $returndetails =
false):
float|array;
1859 $reachedPoints = $reachedPoints - $requestsStatisticData->getRequestsPoints();
1861 return $reachedPoints;
1874 return $points > 0 ?
$points : 0;
1898 if ($count_system == 1) {
1904 if ($score_cutting == 0) {
1915 if (preg_match(
"/.*\.(png|jpg|gif|jpeg)$/i", $plain_image_filename, $matches)) {
1916 $extension =
"." . $matches[1];
1920 $plain_image_filename = uniqid($plain_image_filename . microtime(
true),
true);
1923 return md5($plain_image_filename) . $extension;
1942 bool $manualscoring,
1943 bool $obligationsEnabled,
1944 ?
int $test_id = null
1947 $ilDB = $DIC[
'ilDB'];
1948 $refinery = $DIC[
'refinery'];
1950 $float_trafo = $refinery->kindlyTo()->float();
1952 $points = $float_trafo->transform($points);
1957 if ($points <= $maxpoints) {
1958 if ($pass === null) {
1965 if ($pass !== null) {
1966 $result =
$ilDB->queryF(
1967 "SELECT points FROM tst_test_result WHERE active_fi = %s AND question_fi = %s AND pass = %s",
1968 array(
'integer',
'integer',
'integer'),
1969 array($active_id, $question_id, $pass)
1971 $manual = ($manualscoring) ? 1 : 0;
1972 $rowsnum = $result->numRows();
1975 $row =
$ilDB->fetchAssoc($result);
1976 $old_points = $row[
"points"];
1977 if ($old_points != $points) {
1978 $affectedRows =
$ilDB->manipulateF(
1979 "UPDATE tst_test_result SET points = %s, manual = %s, tstamp = %s WHERE active_fi = %s AND question_fi = %s AND pass = %s",
1980 array(
'float',
'integer',
'integer',
'integer',
'integer',
'integer'),
1981 array($points, $manual, time(), $active_id, $question_id, $pass)
1985 $next_id =
$ilDB->nextId(
'tst_test_result');
1986 $affectedRows =
$ilDB->manipulateF(
1987 "INSERT INTO tst_test_result (test_result_id, active_fi, question_fi, points, pass, manual, tstamp) VALUES (%s, %s, %s, %s, %s, %s, %s)",
1988 array(
'integer',
'integer',
'integer',
'float',
'integer',
'integer',
'integer'),
1989 array($next_id, $active_id, $question_id, $points, $pass, $manual, time())
1993 if (self::isForcePassResultUpdateEnabled() || $old_points != $points || $rowsnum == 0) {
1995 if ($test_id === null || $test_id == 0) {
2002 $test->updateTestPassResults($active_id, $pass, $obligationsEnabled);
2007 $ilUser = $DIC[
'ilUser'];
2012 "log_answer_changed_points",
2018 $ilUser->getFullname() .
" (" . $ilUser->getLogin() .
")" 2019 ), $active_id, $question_id);
2043 || !(
new ilSetting(
'advanced_editing'))->
get(
'advanced_editing_javascript_editor') ===
'tinymce') {
2044 $purified_content = nl2br($purified_content);
2067 $result = $this->db->queryF(
2068 "SELECT question_type_id FROM qpl_qst_type WHERE type_tag = %s",
2072 if ($this->db->numRows($result) == 1) {
2073 $row = $this->db->fetchAssoc($result);
2074 return (
int) $row[
"question_type_id"];
2082 $this->db->manipulateF(
2083 "DELETE FROM qpl_hints WHERE qht_question_fi = %s",
2085 array($this->original_id)
2089 $result = $this->db->queryF(
2090 "SELECT * FROM qpl_hints WHERE qht_question_fi = %s",
2092 array($this->
getId())
2096 if ($this->db->numRows($result) > 0) {
2097 while ($row = $this->db->fetchAssoc($result)) {
2098 $next_id = $this->db->nextId(
'qpl_hints');
2102 'qht_hint_id' => array(
'integer', $next_id),
2103 'qht_question_fi' => array(
'integer', $this->original_id),
2104 'qht_hint_index' => array(
'integer', $row[
"qht_hint_index"]),
2105 'qht_hint_points' => array(
'float', $row[
"qht_hint_points"]),
2106 'qht_hint_text' => array(
'text', $row[
"qht_hint_text"]),
2118 $collected .= $this->feedbackOBJ->getGenericFeedbackContent($this->
getId(),
false);
2119 $collected .= $this->feedbackOBJ->getGenericFeedbackContent($this->
getId(),
true);
2120 $collected .= $this->feedbackOBJ->getAllSpecificAnswerFeedbackContents($this->
getId());
2123 foreach ($questionHintList as $questionHint) {
2125 $collected .= $questionHint->getText();
2139 $result = $this->db->queryF(
2140 "SELECT question_id FROM qpl_questions WHERE original_id = %s",
2142 array($this->
getId())
2146 while ($row = $this->db->fetchAssoc($result)) {
2147 $ids[] = $row[
"question_id"];
2149 foreach ($ids as $question_id) {
2151 $result = $this->db->queryF(
2152 "SELECT tst_tests.obj_fi FROM tst_tests, tst_test_question WHERE tst_test_question.question_fi = %s AND tst_test_question.test_fi = tst_tests.test_id",
2156 while ($row = $this->db->fetchAssoc($result)) {
2160 $result = $this->db->queryF(
2161 "SELECT tst_tests.obj_fi FROM tst_tests, tst_test_rnd_qst, tst_active WHERE tst_test_rnd_qst.active_fi = tst_active.active_id AND tst_test_rnd_qst.question_fi = %s AND tst_tests.test_id = tst_active.test_fi",
2165 while ($row = $this->db->fetchAssoc($result)) {
2169 foreach ($instances as
$key => $value) {
2178 $questioninfo = $DIC->testQuestionPool()->questionInfo();
2180 $questiontype = $questioninfo->getQuestionType($question_id);
2181 if (in_array($questiontype, $scoring)) {
2196 $result = $this->db->queryF(
2197 "SELECT * FROM tst_active WHERE active_id = %s",
2201 if ($this->db->numRows($result)) {
2202 $row = $this->db->fetchAssoc($result);
2203 return array(
"user_id" => $row[
"user_fi"],
"test_id" => $row[
"test_fi"]);
2211 return static::HAS_SPECIFIC_FEEDBACK;
2216 return str_replace(
'ass',
'ilAss', $questionType) .
'Feedback';
2226 $ilCtrl = $DIC[
'ilCtrl'];
2227 $ilDB = $DIC[
'ilDB'];
2229 $ilUser = $DIC[
'ilUser'];
2230 $questioninfo = $DIC->testQuestionPool()->questionInfo();
2231 if (strcmp($a_question_id,
"") != 0) {
2232 $question_type = $questioninfo->getQuestionType($a_question_id);
2234 $question_type_gui = $question_type .
'GUI';
2235 $question_gui =
new $question_type_gui();
2236 $question_gui->object->loadFromDb($a_question_id);
2238 $feedbackObjectClassname = self::getFeedbackClassNameByQuestionType($question_type);
2239 $question_gui->object->feedbackOBJ =
new $feedbackObjectClassname($question_gui->object, $ilCtrl,
$ilDB, $lng);
2241 $assSettings =
new ilSetting(
'assessment');
2243 $processLockerFactory->setQuestionId($question_gui->object->getId());
2244 $processLockerFactory->setUserId($ilUser->getId());
2246 $question_gui->object->setProcessLocker($processLockerFactory->getLocker());
2249 $ilLog = $DIC[
'ilLog'];
2250 $ilLog->write(
'Instantiate question called without question id. (instantiateQuestionGUI@assQuestion)', $ilLog->WARNING);
2251 throw new InvalidArgumentException(
'Instantiate question called without question id. (instantiateQuestionGUI@assQuestion)');
2253 return $question_gui;
2271 $this->nr_of_tries = $a_nr_of_tries;
2276 $this->export_image_path =
$path;
2282 $ilDB = $DIC[
'ilDB'];
2284 if ($question_id < 1) {
2288 $result =
$ilDB->queryF(
2289 "SELECT question_fi FROM tst_test_question WHERE question_fi = %s AND test_fi = %s",
2290 array(
'integer',
'integer'),
2291 array($question_id, $test_id)
2293 return $ilDB->numRows($result) == 1;
2303 return new \ilAssSelfAssessmentQuestionFormatter();
2324 $this->feedbackOBJ->migrateContentForLearningModule($migrator, $this->
getId());
2362 $ilDB = $DIC[
'ilDB'];
2364 $query =
"SELECT obj_fi FROM qpl_questions WHERE question_id = %s";
2366 $res =
$ilDB->queryF($query, array(
'integer'), array($questionId));
2369 return $row[
'obj_fi'];
2377 foreach ($hintIds as $originalHintId => $duplicateHintId) {
2380 $originalXML = $originalPageObject->getXMLContent();
2383 $duplicatePageObject->setId($duplicateHintId);
2384 $duplicatePageObject->setParentId($this->
getId());
2385 $duplicatePageObject->setXMLContent($originalXML);
2386 $duplicatePageObject->createFromXML();
2394 $assignmentList->setParentObjId($srcParentId);
2395 $assignmentList->setQuestionIdFilter($srcQuestionId);
2396 $assignmentList->loadFromDb();
2398 foreach ($assignmentList->getAssignmentsByQuestionId($srcQuestionId) as $assignment) {
2399 $assignment->setParentObjId($trgParentId);
2400 $assignment->setQuestionId($trgQuestionId);
2401 $assignment->saveToDb();
2404 $this->skillUsageService->addUsage(
2406 $assignment->getSkillBaseId(),
2407 $assignment->getSkillTrefId()
2412 public function syncSkillAssignments(
int $srcParentId,
int $srcQuestionId,
int $trgParentId,
int $trgQuestionId): void
2415 $assignmentList->setParentObjId($trgParentId);
2416 $assignmentList->setQuestionIdFilter($trgQuestionId);
2417 $assignmentList->loadFromDb();
2419 foreach ($assignmentList->getAssignmentsByQuestionId($trgQuestionId) as $assignment) {
2420 $assignment->deleteFromDb();
2423 if (!$assignment->isSkillUsed()) {
2424 $this->skillUsageService->removeUsage(
2425 $assignment->getParentObjId(),
2426 $assignment->getSkillBaseId(),
2427 $assignment->getSkillTrefId()
2439 $pageObject->setParentId($this->
getId());
2440 $pageObject->setId($pageObjectId);
2441 $pageObject->createFromXML();
2448 return $numExistingSolutionRecords > 0;
2459 $ilDB = $DIC[
'ilDB'];
2462 SELECT count(active_fi) cnt 2466 WHERE active_fi = %s 2467 AND question_fi = %s 2473 array(
'integer',
'integer',
'integer'),
2474 array($activeId, $questionId, $pass)
2479 return (
int) $row[
'cnt'];
2513 self::ADDITIONAL_CONTENT_EDITING_MODE_RTE,
2514 self::ADDITIONAL_CONTENT_EDITING_MODE_IPE
2537 SELECT qpl_questions.*, 2538 {$this->getAdditionalTableName()}.* 2540 LEFT JOIN {$this->getAdditionalTableName()} 2541 ON {$this->getAdditionalTableName()}.question_fi = qpl_questions.question_id 2542 WHERE qpl_questions.question_id = %s 2558 if ($this->
getStep() !== null) {
2562 WHERE active_fi = %s 2563 AND question_fi = %s 2569 return $this->db->queryF(
2571 array(
'integer',
'integer',
'integer',
'integer',
'integer'),
2572 array($active_id, $this->
getId(), $pass, $this->
getStep(), (
int) $authorized)
2579 WHERE active_fi = %s 2580 AND question_fi = %s 2585 return $this->db->queryF(
2587 array(
'integer',
'integer',
'integer',
'integer'),
2588 array($active_id, $this->
getId(), $pass, (
int) $authorized)
2594 return $this->db->manipulateF(
2595 "DELETE FROM tst_solutions WHERE solution_id = %s",
2607 $result = $this->db->queryF(
2608 "SELECT * FROM tst_solutions WHERE solution_id = %s",
2613 if ($this->db->numRows($result) > 0) {
2614 return $this->db->fetchAssoc($result);
2622 $this->
getProcessLocker()->executeUserSolutionUpdateLockOperation(
function () use ($active_id, $pass) {
2632 if ($this->
getStep() !== null) {
2634 DELETE FROM tst_solutions 2635 WHERE active_fi = %s 2636 AND question_fi = %s 2642 return $this->db->manipulateF(
2644 array(
'integer',
'integer',
'integer',
'integer',
'integer'),
2645 array($active_id, $this->
getId(), $pass, $this->
getStep(), (
int) $authorized)
2650 DELETE FROM tst_solutions 2651 WHERE active_fi = %s 2652 AND question_fi = %s 2657 return $this->db->manipulateF(
2659 array(
'integer',
'integer',
'integer',
'integer'),
2660 array($active_id, $this->
getId(), $pass, (
int) $authorized)
2667 $next_id = $this->db->nextId(
"tst_solutions");
2670 "solution_id" => array(
"integer", $next_id),
2671 "active_fi" => array(
"integer", $active_id),
2672 "question_fi" => array(
"integer", $this->
getId()),
2673 "value1" => array(
"clob", $value1),
2674 "value2" => array(
"clob", $value2),
2675 "pass" => array(
"integer", $pass),
2676 "tstamp" => array(
"integer", ((
int) $tstamp > 0) ? (
int) $tstamp : time()),
2677 'authorized' => array(
'integer', (
int) $authorized)
2680 if ($this->
getStep() !== null) {
2681 $fieldData[
'step'] = array(
"integer", $this->
getStep());
2684 return $this->db->insert(
"tst_solutions", $fieldData);
2691 "value1" => array(
"clob", $value1),
2692 "value2" => array(
"clob", $value2),
2693 "tstamp" => array(
"integer", time()),
2694 'authorized' => array(
'integer', (
int) $authorized)
2697 if ($this->
getStep() !== null) {
2698 $fieldData[
'step'] = array(
"integer", $this->
getStep());
2701 return $this->db->update(
"tst_solutions", $fieldData, array(
2702 'solution_id' => array(
'integer', $solutionId)
2710 'authorized' => array(
'integer', (
int) $authorized)
2714 $fieldData[
'tstamp'] = array(
'integer', time());
2718 'question_fi' => array(
'integer', $this->
getId()),
2719 'active_fi' => array(
'integer', $activeId),
2720 'pass' => array(
'integer', $pass)
2723 if ($this->
getStep() !== null) {
2724 $whereData[
'step'] = array(
"integer", $this->
getStep());
2727 return $this->db->update(
'tst_solutions', $fieldData, $whereData);
2746 foreach ($this->
getSolutionValues($activeId, $passIndex,
false) as $solutionRec) {
2747 if ($solutionRec[
'value1'] ==
'' && $solutionRec[
'value2'] ==
'') {
2755 return !strlen($solutionRecord[
'value1']) && !strlen($solutionRecord[
'value2']);
2760 $types = array(
"integer",
"integer",
"integer",
"integer");
2761 $values = array($activeId, $this->
getId(), $passIndex, (
int) $authorized);
2762 $valuesCondition = [];
2764 foreach ($matchValues as $valueField => $value) {
2765 switch ($valueField) {
2768 $valuesCondition[] =
"{$valueField} = %s";
2778 $valuesCondition = implode(
' AND ', $valuesCondition);
2781 DELETE FROM tst_solutions 2782 WHERE active_fi = %s 2783 AND question_fi = %s 2786 AND $valuesCondition 2789 if ($this->
getStep() !== null) {
2790 $query .=
" AND step = %s ";
2791 $types[] =
'integer';
2795 $this->db->manipulateF($query, $types, $values);
2801 $this->
saveCurrentSolution($activeId, $passIndex, $rec[
'value1'], $rec[
'value2'],
true, $rec[
'tstamp']);
2809 if (!count($intermediateSolution)) {
2817 if ($considerDummyRecordCreation) {
2831 $this->step =
$step;
2845 $time_array = explode(
':', $time);
2846 if (count($time_array) == 3) {
2847 $sec += (
int) $time_array[0] * 3600;
2848 $sec += (
int) $time_array[1] * 60;
2849 $sec += (
int) $time_array[2];
2856 return json_encode([]);
2859 abstract public function duplicate(
bool $for_test =
true,
string $title =
"",
string $author =
"",
int $owner = -1, $testObjId = null):
int;
2865 return (
bool) $solutionAvailability[
'intermediate'];
2870 if ($pass === null) {
2874 return (
bool) $solutionAvailability[
'authorized'];
2880 return $solutionAvailability[
'authorized'] || $solutionAvailability[
'intermediate'];
2886 $result = $this->db->queryF(
2887 "SELECT MAX(step) max_step FROM tst_solutions WHERE active_fi = %s AND pass = %s AND question_fi = %s",
2888 array(
"integer",
"integer",
"integer"),
2889 array($active_id, $pass, $this->
getId())
2892 $row = $this->db->fetchAssoc($result);
2894 return (
int) $row[
'max_step'];
2905 'authorized' =>
false,
2906 'intermediate' =>
false 2910 SELECT authorized, COUNT(*) cnt 2912 WHERE active_fi = %s 2913 AND question_fi = %s 2917 if ($this->
getStep() !== null) {
2918 $query .=
" AND step = " . $this->db->quote((
int) $this->
getStep(),
'integer') .
" ";
2925 $result = $this->db->queryF($query, array(
'integer',
'integer',
'integer'), array($activeId, $this->
getId(), $pass));
2927 while ($row = $this->db->fetchAssoc($result)) {
2928 if ($row[
'authorized']) {
2929 $return[
'authorized'] = $row[
'cnt'] > 0;
2931 $return[
'intermediate'] = $row[
'cnt'] > 0;
2949 $query =
"DELETE FROM tst_solutions WHERE question_fi = %s";
2950 $this->db->manipulateF($query, array(
'integer'), array($this->
getId()));
2956 DELETE FROM tst_solutions 2957 WHERE active_fi = %s 2958 AND question_fi = %s 2962 if ($this->
getStep() !== null) {
2963 $query .=
" AND step = " . $this->db->quote((
int) $this->
getStep(),
'integer') .
" ";
2966 return $this->db->manipulateF(
2968 array(
'integer',
'integer',
'integer'),
2969 array($activeId, $this->
getId(), $pass)
2978 $this->
log($activeId,
"log_user_solution_willingly_deleted");
2984 $test->updateTestPassResults(
2996 DELETE FROM tst_test_result 2997 WHERE active_fi = %s 2998 AND question_fi = %s 3002 if ($this->
getStep() !== null) {
3003 $query .=
" AND step = " . $this->db->quote((
int) $this->
getStep(),
'integer') .
" ";
3006 return $this->db->manipulateF(
3008 array(
'integer',
'integer',
'integer'),
3009 array($activeId, $this->
getId(), $pass)
3017 foreach ($indexedValues as $value1 => $value2) {
3018 $valuePairs[] = array(
'value1' => $value1,
'value2' => $value2);
3026 $indexedValues = [];
3028 foreach ($valuePairs as $valuePair) {
3029 $indexedValues[ $valuePair[
'value1'] ] = $valuePair[
'value2'];
3032 return $indexedValues;
3047 $this->db->manipulateF(
3048 "UPDATE qpl_questions SET tstamp = %s WHERE question_id = %s",
3049 array(
'integer',
'integer'),
3050 array(time(), $this->
getId())
3064 if ($this->testQuestionConfigInstance === null) {
3085 if (is_null($this->suggestedsolution_repo)) {
3087 $this->suggestedsolution_repo = $dic[
'question.repo.suggestedsolutions'];
3094 $question_id = $this->
getId();
3114 return preg_replace(self::TRIM_PATTERN,
'', $value);
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...
loadFromDb(int $question_id)
getSolutionValues($active_id, $pass=null, bool $authorized=true)
Loads solutions of a given user from the database an returns it.
const ADDITIONAL_CONTENT_EDITING_MODE_IPE
setNrOfTries(int $a_nr_of_tries)
ilTestQuestionConfig $testQuestionConfig
ilAssQuestionFeedback $feedbackOBJ
syncSkillAssignments(int $srcParentId, int $srcQuestionId, int $trgParentId, int $trgQuestionId)
ilGlobalPageTemplate $tpl
static _getManualScoringTypes()
Retrieve the manual scoring settings as type strings.
static getListByQuestionId($questionId)
instantiates a question hint list for the passed question id
deletePageOfQuestion(int $question_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
authorizedOrIntermediateSolutionExists(int $active_id, int $pass)
bool $obligationsToBeConsidered
resolveSuggestedSolutionLinks()
getActiveUserData(int $active_id)
Returns the user id and the test id for a given active id.
static _addLog( $user_id, $object_id, $logtext, $question_id=0, $original_id=0, $test_only=false, $test_ref_id=0)
Add an assessment log entry.
static _getObjectIDFromTestID($test_id)
Returns the ILIAS test object id for a given test id.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
migrateContentForLearningModule(ilAssSelfAssessmentMigrator $migrator)
toXML(bool $a_include_header=true, bool $a_include_binary=true, bool $a_shuffle=false, bool $test_output=false, bool $force_image_references=false)
Returns a QTI xml representation of the question.
static _isWriteable($object_id, $user_id)
Returns true, if the question pool is writeable by a given user.
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
static _getParticipantData($active_id)
Retrieves a participant name from active id.
getSuggestedSolutionPath()
getTitleFilenameCompliant()
txtlng(string $a_module, string $a_topic, string $a_language)
gets the text for a given topic in a given language if the topic is not in the list, the topic itself with "-" will be returned
ILIAS HTTP Services $http
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getQuestionType()
Returns the question type of the question.
removeResultRecord(int $activeId, int $pass)
deleteAdditionalTableData(int $question_id)
deleteAnswers(int $question_id)
static _getSuggestedSolutionOutput(int $question_id)
updateCurrentSolutionsAuthorization(int $activeId, int $pass, bool $authorized, bool $keepTime=false)
buildTestPresentationConfig()
build basic test question configuration instance
resetUsersAnswer(int $activeId, int $pass)
Abstract basic class which is to be extended by the concrete assessment question type classes...
static isFileAvailable(string $file)
setProcessLocker(ilAssQuestionProcessLocker $processLocker)
copyPageOfQuestion(int $a_q_id)
Class ChatMainBarProvider .
static isObligationPossible(int $questionId)
persistWorkingState(int $active_id, $pass, bool $obligationsEnabled=false, bool $authorized=true)
persists the working state for current testactive and testpass
saveWorkingData(int $active_id, int $pass, bool $authorized=true)
Saves the learners input of the question to the database.
static _getAllReferences(int $id)
get all reference ids for object ID
ilAssQuestionProcessLocker $processLocker
static getImagePath(string $img, string $module_path="", string $mode="output", bool $offline=false)
get image path (for images located in a template directory)
ensureHintPageObjectExists($pageObjectId)
setSelfAssessmentEditingMode(bool $selfassessmenteditingmode)
getColumnCoord(int $a_col)
Get column "name" from number.
adjustReachedPointsByScoringOptions($points, $active_id, $pass=null)
Adjust the given reached points by checks for all special scoring options in the test container...
ensureNonNegativePoints($points)
SkillUsageService $skillUsageService
isDummySolutionRecord(array $solutionRecord)
bool $shuffle
Indicates whether the answers will be shuffled or not.
static _getInternalLinkHref(string $target="")
duplicate(bool $for_test=true, string $title="", string $author="", int $owner=-1, $testObjId=null)
__construct(string $title="", string $comment="", string $author="", int $owner=-1, string $question="")
assQuestion constructor
assQuestionSuggestedSolutionsDatabaseRepository $suggestedsolution_repo
static isForcePassResultUpdateEnabled()
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static lookupParentObjId(int $questionId)
getImagePathWeb()
Returns the web 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...
setThumbSize(int $a_size)
savePreviewData(ilAssQuestionPreviewSession $previewSession)
static deleteHintsByQuestionIds(array $questionIds)
Deletes all question hints relating to questions included in given question ids.
static getUsageOfObject(int $a_obj_id, bool $a_include_titles=false)
migrateToLmContent($content)
lmMigrateQuestionTypeSpecificContent(ilAssSelfAssessmentMigrator $migrator)
static getNumExistingSolutionRecords(int $activeId, int $pass, int $questionId)
syncXHTMLMediaObjectsOfQuestion()
duplicateSkillAssignments(int $srcParentId, int $srcQuestionId, int $trgParentId, int $trgQuestionId)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getAdditionalContentEditingMode()
getParticipantsSolution()
static _cleanupMediaObjectUsage(string $a_text, string $a_usage_type, int $a_usage_id)
Synchronises appearances of media objects in $a_text with media object usage table.
getSelfAssessmentEditingMode()
importHint(int $question_id, array $hint_array)
static setTokenMaxLifetimeInSeconds(int $token_max_lifetime_in_seconds)
setPreventRteUsage(bool $prevent_rte_usage)
static makeDirParents(string $a_dir)
Create a new directory and all parent directories.
getSuggestedSolution(int $subquestion_index=0)
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
setComment(string $comment="")
persistPreviewState(ilAssQuestionPreviewSession $previewSession)
persists the preview state for current user and question
static _questionExistsInTest(int $question_id, int $test_id)
string $questionActionCmd
getValidAdditionalContentEditingModes()
float $points
The maximum available points for the question.
Customizing of pimple-DIC for ILIAS.
static _lookupTestObjIdForQuestionId(int $q_id)
Get test Object ID for question ID.
int $obj_id
Object id of the container object.
fetchIndexedValuesFromValuePairs(array $valuePairs)
bool $selfassessmenteditingmode
static implodeKeyValues(array $keyValues)
setExportImagePath(string $path)
static removeTrailingPathSeparators(string $path)
Export internal data service.
static _saveLink(string $a_source_type, int $a_source_id, string $a_target_type, int $a_target_id, int $a_target_inst=0, string $a_source_lang="-")
save internal link information
fixUnavailableSkinImageSources(string $html)
getSuggestedSolutionsRepo()
syncSuggestedSolutions(int $target_question_id, int $target_obj_id)
static _lookupObjId(int $ref_id)
static instantiateQuestionGUI(int $a_question_id)
isAddableAnswerOptionValue(int $qIndex, string $answerOptionValue)
updateCurrentSolution(int $solutionId, $value1, $value2, bool $authorized=true)
setParticipantsSolution($participantSolution)
static getASCIIFilename(string $a_filename)
deleteDummySolutionRecord(int $activeId, int $passIndex)
isPreviewSolutionCorrect(ilAssQuestionPreviewSession $previewSession)
removeIntermediateSolution(int $active_id, int $pass)
setExportDetailsXLSX(ilAssExcelFormatHelper $worksheet, int $startrow, int $col, int $active_id, int $pass)
calculateReachedPoints($active_id, $pass=null, $authorizedSolution=true, $returndetails=false)
Returns the points, a learner has reached answering the question.
static isQuestionObligatory($question_id)
checks wether the question with given id is marked as obligatory or not
static _getUserIdFromActiveId(int $active_id)
static resetOriginalId(int $questionId)
calculateReachedPointsFromPreviewSession(ilAssQuestionPreviewSession $previewSession)
resolveInternalLink(string $internal_link)
getQuestionForHTMLOutput()
static instantiateQuestion(int $question_id)
Interface for html sanitizing functionality.
saveCurrentSolution(int $active_id, int $pass, $value1, $value2, bool $authorized=true, $tstamp=0)
static _needsManualScoring(int $question_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _enabledAssessmentLogging()
purifyAndPrepareTextAreaOutput(string $content)
static http()
Fetches the global http state from ILIAS.
getImagePath($question_id=null, $object_id=null)
Returns the image path for web accessable images of a question.
duplicateComments(int $parent_source_id, int $source_id, int $parent_target_id, int $target_id)
buildHashedImageFilename(string $plain_image_filename, bool $unique=false)
static _lookupTitle(int $obj_id)
areObligationsToBeConsidered()
lookupForExistingSolutions(int $activeId, int $pass)
Lookup if an authorized or intermediate solution exists.
getAdjustedReachedPoints(int $active_id, int $pass, bool $authorizedSolution=true)
returns the reached points ...
static _getScoreCutting($active_id)
Determines if the score of a question should be cut at 0 points or the score of the whole test...
static _exists(string $a_parent_type, int $a_id, string $a_lang="", bool $a_no_cache=false)
Checks whether page exists.
static _deleteAllLinksOfSource(string $a_source_type, int $a_source_id, string $a_lang="-")
Delete all links of a given source.
static logAction(string $logtext, int $active_id, int $question_id)
removeSolutionRecordById(int $solutionId)
static _getReachedPoints(int $active_id, int $question_id, int $pass)
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static _getIdForImportId(string $a_import_id)
get current object id for import id (static)
static _getSolutionMaxPass(int $question_id, int $active_id)
Returns the maximum pass a users question solution.
static _getIdForImportId(string $a_type, string $a_target)
Get current id for an import id.
isComplete()
Returns true, if a question is complete for use.
intermediateSolutionExists(int $active_id, int $pass)
fromXML($item, int $questionpool_id, ?int $tst_id, &$tst_object, int &$question_counter, array $import_mapping, array &$solutionhints=[])
Receives parameters from a QTI parser and creates a valid ILIAS question object.
static _getCountSystem($active_id)
Repository for suggested solutions.
static $forcePassResultsUpdateEnabled
getDescriptionForHTMLOutput()
getHtmlUserSolutionPurifier()
static getInstanceByType(string $type)
static _lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object.
getSuggestedSolutionPathWeb()
string $question
The question text.
Basic GUI class for assessment questions.
log(int $active_id, string $langVar)
removeExistingSolutions(int $activeId, int $pass)
setDefaultNrOfTries(int $defaultnroftries)
cleanupMediaObjectUsage()
deleteSuggestedSolutions()
isNonEmptyItemListPostSubmission(string $postSubmissionFieldname)
static saveOriginalId(int $questionId, int $originalId)
static _updateQuestionCount(int $object_id)
ilAssQuestionLifecycle $lifecycle
ILIAS TestQuestionPool QuestionFilesService $questionFilesService
fetchValuePairsFromIndexedValues(array $indexedValues)
getRTETextWithMediaObjects()
ILIAS Test TestParticipantInfoService $testParticipantInfo
createNewQuestion(bool $a_create_page=true)
Creates a new question without an owner when a new question is created This assures that an ID is giv...
static duplicateListForQuestion($originalQuestionId, $duplicateQuestionId)
duplicates a hint list from given original question id to given duplicate question id and returns an ...
int $test_id
The database id of a test in which the question is contained.
isAdditionalContentEditingModePageObject()
deductHintPointsFromReachedPoints(ilAssQuestionPreviewSession $previewSession, $reachedPoints)
setObligationsToBeConsidered(bool $obligationsToBeConsidered)
onDuplicate(int $originalParentId, int $originalQuestionId, int $duplicateParentId, int $duplicateQuestionId)
duplicateIntermediateSolutionAuthorized(int $activeId, int $passIndex)
const KEY_VALUES_IMPLOSION_SEPARATOR
copySuggestedSolutionFiles(int $source_questionpool_id, int $source_question_id)
saveQuestionDataToDb(int $original_id=-1)
syncSuggestedSolutionFiles(int $target_question_id, int $target_obj_id)
static $imageSourceFixReplaceMap
ilTestQuestionConfig $testQuestionConfigInstance
getSolutionMaxPass(int $active_id)
isValidAdditionalContentEditingMode(string $additionalContentEditingMode)
static extendedTrim(string $value)
Trim non-printable characters from the beginning and end of a string.
removeCurrentSolution(int $active_id, int $pass, bool $authorized=true)
array $suggested_solutions
lmMigrateQuestionTypeGenericContent(ilAssSelfAssessmentMigrator $migrator)
ILIAS TestQuestionPool QuestionInfoService $questioninfo
onCopy(int $sourceParentId, int $sourceQuestionId, int $targetParentId, int $targetQuestionId)
const ADDITIONAL_CONTENT_EDITING_MODE_RTE
setOriginalId(?int $original_id)
getTestPresentationConfig()
setExternalId(?string $external_id)
getRequestStatisticData()
getTestOutputSolutions(int $activeId, int $pass)
setShuffler(Transformation $shuffler)
static convertISO8601FormatH_i_s_ExtendedToSeconds(string $time)
setTitle(string $title="")
deleteSolutionRecordByValues(int $activeId, int $passIndex, bool $authorized, array $matchValues)
setLastChange($lastChange)
static signFile(string $path_to_file)
authorizedSolutionExists(int $active_id, ?int $pass)
setLifecycle(ilAssQuestionLifecycle $lifecycle)
getCurrentSolutionResultSet(int $active_id, int $pass, bool $authorized=true)
static _isWriteable(int $question_id, int $user_id)
calculateResultsFromSolution(int $active_id, int $pass, bool $obligationsEnabled=false)
Calculates the question results from a previously saved question solution.
getReachedPoints(int $active_id, int $pass)
isAnswered(int $active_id, int $pass)
addAnswerOptionValue(int $qIndex, string $answerOptionValue, float $points)
deleteTaxonomyAssignments()
forceExistingIntermediateSolution(int $activeId, int $passIndex, bool $considerDummyRecordCreation)
static _updateObjectiveResult(int $a_user_id, int $a_active_id, int $a_question_id)
const HAS_SPECIFIC_FEEDBACK
ILIAS DI LoggingServices $ilLog
getHtmlQuestionContentPurifier()
lookupMaxStep(int $active_id, int $pass)
setAuthor(string $author="")
duplicateQuestionHints(int $originalQuestionId, int $duplicateQuestionId)
duplicateSuggestedSolutionFiles(int $parent_id, int $question_id)
Duplicates the files of a suggested solution if the question is duplicated.
string $additionalContentEditingMode
afterSyncWithOriginal(int $origQuestionId, int $dupQuestionId, int $origParentObjId, int $dupParentObjId)
copySuggestedSolutions(int $target_question_id)
getSolutionRecordById(int $solutionId)
beforeSyncWithOriginal(int $origQuestionId, int $dupQuestionId, int $origParentObjId, int $dupParentObjId)
static _setReachedPoints(int $active_id, int $question_id, float $points, float $maxpoints, int $pass, bool $manualscoring, bool $obligationsEnabled, ?int $test_id=null)
Sets the points, a learner has reached answering the question Additionally objective results are upda...
setShuffle(?bool $shuffle=true)
setAdditionalContentEditingMode(?string $additionalContentEditingMode)
static explodeKeyValues(string $keyValues)
static getDraftInstance()
getUserSolutionPreferingIntermediate(int $active_id, $pass=null)
removeAllExistingSolutions()
copyXHTMLMediaObjectsOfQuestion(int $a_q_id)
getSuggestedSolutionOutput()
ILIAS Refinery Factory $refinery
getSelfAssessmentFormatter()
static getFeedbackClassNameByQuestionType(string $questionType)
fixSvgToPng(string $imageFilenameContainingString)
setQuestion(string $question="")
string $export_image_path
(Web) Path to images
static setForcePassResultUpdateEnabled(bool $forcePassResultsUpdateEnabled)