19 declare(strict_types=1);
27 require_once
'Modules/Test/classes/inc.AssessmentConstants.php';
123 public function __construct(
int $id = 0,
bool $a_call_by_reference =
true)
129 $this->
ctrl = $DIC[
'ilCtrl'];
131 $this->
settings = $DIC[
'ilSetting'];
132 $this->bench = $DIC[
'ilBench'];
133 $this->testrequest = $DIC->test()->internal()->request();
134 $this->component_repository = $DIC[
'component.repository'];
135 $this->component_factory = $DIC[
'component.factory'];
136 $this->filesystem_web = $DIC->filesystem()->web();
139 $this->participant_access_filter = $local_dic[
'participantAccessFilterFactory'];
140 $this->testManScoringDoneHelper = $local_dic[
'manScoringDoneHelper'];
142 $this->mark_schema =
new ASS_MarkSchema($DIC[
'ilDB'], $DIC[
'lng'], $DIC[
'ilUser']->
getId());
143 $this->mark_schema->createSimpleSchema(
144 $DIC->language()->txt(
"failed_short"),
145 $DIC->language()->txt(
"failed_official"),
148 $DIC->language()->txt(
"passed_short"),
149 $DIC->language()->txt(
"passed_official"),
156 $this->
lng->loadLanguageModule(
"assessment");
157 $this->questioninfo = $DIC->testQuestionPool()->questionInfo();
158 $this->score_settings = null;
165 $this->component_repository,
178 return $this->question_set_config_factory->getQuestionSetConfig();
201 $id = parent::create();
208 if (!parent::update()) {
220 $this->main_settings = null;
221 $this->score_settings = null;
225 public function delete():
bool 228 if (!parent::delete()) {
239 $qsaImportFails->deleteRegisteredImportFails();
241 $sltImportFails->deleteRegisteredImportFails();
249 $participantData->load($this->
getTestId());
252 $this->db->manipulateF(
253 "DELETE FROM tst_mark WHERE test_fi = %s",
258 $this->db->manipulateF(
259 "DELETE FROM tst_tests WHERE test_id = %s",
269 if ($this->main_settings !== null
271 $this->question_set_config_factory->getQuestionSetConfig()->removeQuestionSetRelatedData();
275 $directory = $tst_data_dir .
"/tst_" . $this->
getId();
276 if (is_dir($directory)) {
284 foreach ($mobs as $mob) {
302 if (!is_writable($tst_data_dir)) {
303 $this->
ilias->raiseError(
"Test Data Directory (" . $tst_data_dir
304 .
") not writeable.", $this->
ilias->error_obj->MESSAGE);
308 $tst_dir = $tst_data_dir .
"/tst_" . $this->
getId();
310 if (!@is_dir($tst_dir)) {
311 $this->
ilias->raiseError(
"Creation of Test Directory failed.", $this->
ilias->error_obj->MESSAGE);
314 $export_dir = $tst_dir .
"/export";
316 if (!@is_dir($export_dir)) {
317 $this->
ilias->raiseError(
"Creation of Export Directory failed.", $this->
ilias->error_obj->MESSAGE);
327 public function getExportFiles(
string $dir =
''): array
330 if (!@is_dir($dir) || !is_writable($dir)) {
335 foreach (
new DirectoryIterator($dir) as $file) {
339 if ($file->isDir()) {
343 $files[] = $file->getBasename();
353 if ($a_import_dir !== null) {
392 if (!is_writable($tst_data_dir)) {
394 .
") not writeable.",
$ilias->error_obj->FATAL);
398 $tst_dir = $tst_data_dir .
"/tst_import";
400 if (!@is_dir($tst_dir)) {
412 if (!count($this->mark_schema->mark_steps)) {
426 if ($this->
isComplete($testQuestionSetConfig)) {
430 $this->db->manipulateF(
431 "UPDATE tst_tests SET complete = %s WHERE test_id = %s",
433 [$complete, $this->test_id]
438 public function saveToDb(
bool $properties_only =
false): void
440 if ($this->test_id === -1) {
442 $next_id = $this->db->nextId(
'tst_tests');
447 'test_id' => [
'integer', $next_id],
448 'obj_fi' => [
'integer', $this->
getId()],
449 'author' => [
'text', mb_substr($this->
getAuthor(), 0, 50)],
450 'created' => [
'integer', time()],
451 'tstamp' => [
'integer', time()],
452 'template_id' => [
'integer', $this->
getTemplate()],
457 $this->test_id = $next_id;
466 $result = $this->db->queryF(
467 "SELECT * FROM tst_tests WHERE test_id = %s",
471 if ($result->numRows() == 1) {
472 $oldrow = $this->db->fetchAssoc($result);
479 'author' => [
'text', mb_substr($this->
getAuthor(), 0, 50)],
483 'test_id' => [
'integer', $this->
getTestId()]
488 $logresult = $this->db->queryF(
489 "SELECT * FROM tst_tests WHERE test_id = %s",
494 if ($logresult->numRows() == 1) {
495 $newrow = $this->db->fetchAssoc($logresult);
497 $changed_fields = [];
498 foreach ($oldrow as
$key => $value) {
499 if ($oldrow[
$key] !== $newrow[
$key]) {
500 array_push($changed_fields,
"$key: " . $oldrow[$key] .
" => " . $newrow[$key]);
503 $changes = join(
", ", $changed_fields);
504 if (count($changed_fields) > 0) {
512 $aresult = $this->db->queryF(
513 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
514 [
'integer',
'integer',
'integer'],
517 while ($row = $this->db->fetchAssoc($aresult)) {
518 $this->db->manipulateF(
519 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
520 [
'integer',
'timestamp',
'integer'],
521 [1, date(
'Y-m-d H:i:s'), $row[
"active_id"]]
526 $aresult = $this->db->queryF(
527 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
528 [
'integer',
'integer',
'integer'],
531 while ($row = $this->db->fetchAssoc($aresult)) {
532 $this->db->manipulateF(
533 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
534 [
'integer',
'timestamp',
'integer'],
535 [0, null, $row[
"active_id"]]
540 $aresult = $this->db->queryF(
541 "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
542 [
'integer',
'integer'],
545 while ($row = $this->db->fetchAssoc($aresult)) {
546 $this->db->manipulateF(
547 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
548 [
'integer',
'timestamp',
'integer'],
549 [0, null, $row[
"active_id"]]
563 if (!$properties_only) {
568 $this->mark_schema->saveToDb($this->test_id);
576 $result = $this->db->queryF(
577 "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
581 if ($result->numRows() > 0) {
582 while ($row = $this->db->fetchAssoc($result)) {
583 array_push($oldquestions, $row[
"question_fi"]);
589 $currentQuestionsObligationsQuery =
'SELECT question_fi, obligatory FROM tst_test_question WHERE test_fi = %s';
590 $rset = $this->db->queryF($currentQuestionsObligationsQuery, [
'integer'], [$this->
getTestId()]);
591 while ($row = $this->db->fetchAssoc($rset)) {
592 $obligatoryQuestionState[$row[
'question_fi']] = $row[
'obligatory'];
595 $this->db->manipulateF(
596 "DELETE FROM tst_test_question WHERE test_fi = %s",
601 foreach ($this->questions as
$key => $value) {
603 if (!isset($obligatoryQuestionState[$value]) || is_null($obligatoryQuestionState[$value])) {
604 $obligatoryQuestionState[$value] = 0;
608 $next_id = $this->db->nextId(
'tst_test_question');
609 $this->db->insert(
'tst_test_question', [
610 'test_question_id' => [
'integer', $next_id],
611 'test_fi' => [
'integer', $this->
getTestId()],
612 'question_fi' => [
'integer', $value],
613 'sequence' => [
'integer',
$key],
614 'obligatory' => [
'integer', $obligatoryQuestionState[$value]],
615 'tstamp' => [
'integer', time()]
619 $result = $this->db->queryF(
620 "SELECT question_fi FROM tst_test_question WHERE test_fi = %s ORDER BY sequence",
625 if ($result->numRows() > 0) {
626 while ($row = $this->db->fetchAssoc($result)) {
627 array_push($newquestions, $row[
"question_fi"]);
630 foreach ($oldquestions as $index => $question_id) {
631 if (!isset($newquestions[$index]) || $newquestions[$index] !== $question_id) {
632 $pos = array_search($question_id, $newquestions);
633 if ($pos ===
false) {
640 foreach ($newquestions as $index => $question_id) {
641 if (array_search($question_id, $oldquestions) ===
false) {
653 $result = $this->db->queryF(
654 "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
655 [
'integer',
'integer'],
658 return $result->numRows();
663 $result = $this->db->queryF(
664 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
668 if ($result->numRows() === 1) {
669 $data = $this->db->fetchObject($result);
672 $this->mark_schema->flush();
673 $this->mark_schema->loadFromDb($this->
getTestId());
679 if (isset($this->ref_id)) {
681 switch ($activation[
"timing_type"]) {
702 $this->questions = [];
704 if ($active_id === 0) {
707 if (is_null($pass)) {
708 $pass = self::_getPass($active_id);
710 $result = $this->db->queryF(
711 "SELECT tst_test_rnd_qst.* FROM tst_test_rnd_qst, qpl_questions WHERE tst_test_rnd_qst.active_fi = %s AND qpl_questions.question_id = tst_test_rnd_qst.question_fi AND tst_test_rnd_qst.pass = %s ORDER BY sequence",
712 [
'integer',
'integer'],
719 if ($result->numRows() == 0) {
720 $result = $this->db->queryF(
721 "SELECT tst_test_rnd_qst.* FROM tst_test_rnd_qst, qpl_questions WHERE tst_test_rnd_qst.active_fi = %s AND qpl_questions.question_id = tst_test_rnd_qst.question_fi AND tst_test_rnd_qst.pass = 0 ORDER BY sequence",
727 $result = $this->db->queryF(
728 "SELECT tst_test_question.* FROM tst_test_question, qpl_questions WHERE tst_test_question.test_fi = %s AND qpl_questions.question_id = tst_test_question.question_fi ORDER BY sequence",
734 if ($this->test_id !== -1) {
736 while (
$data = $this->db->fetchAssoc($result)) {
737 $this->questions[$index++] =
$data[
"question_fi"];
744 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
745 if ($page_id !== null) {
749 return $this->
getMainSettings()->getIntroductionSettings()->getIntroductionText();
754 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
755 if ($page_id === null) {
763 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
764 if ($page_id !== null) {
767 return $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksText();
772 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
773 if ($page_id === null) {
782 $page_object->setParentId($this->
getId());
783 $new_page_id = $page_object->createPageWithNextId();
784 (
new ilTestPage($source_page_id))->copy($new_page_id);
802 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getPostponedQuestionsMoveToEnd();
814 return $this->
getScoreSettings()->getResultSummarySettings()->getScoreReporting();
836 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled();
841 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled();
846 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled();
857 $ilDB = $DIC[
'ilDB'];
858 $result =
$ilDB->queryF(
859 "SELECT tst_tests.count_system FROM tst_tests, tst_active WHERE tst_active.active_id = %s AND tst_active.test_fi = tst_tests.test_id",
863 if ($result->numRows()) {
864 $row =
$ilDB->fetchAssoc($result);
865 return $row[
"count_system"];
904 $ilDB = $DIC[
'ilDB'];
905 $result =
$ilDB->queryF(
906 "SELECT tst_tests.pass_scoring FROM tst_tests, tst_active WHERE tst_tests.test_id = tst_active.test_fi AND tst_active.active_id = %s",
910 if ($result->numRows()) {
911 $row =
$ilDB->fetchAssoc($result);
912 return (
int) $row[
"pass_scoring"];
927 $ilDB = $DIC[
'ilDB'];
928 $result =
$ilDB->queryF(
929 "SELECT tst_tests.score_cutting FROM tst_tests, tst_active WHERE tst_active.active_id = %s AND tst_tests.test_id = tst_active.test_fi",
933 if ($result->numRows()) {
934 $row =
$ilDB->fetchAssoc($result);
935 return (
bool) $row[
"score_cutting"];
950 return $this->
getScoreSettings()->getResultSummarySettings()->getReportingDate();
955 return $this->
getMainSettings()->getTestBehaviourSettings()->getNumberOfTries();
960 return $this->
getMainSettings()->getTestBehaviourSettings()->getBlockAfterPassedEnabled();
965 return $this->
getMainSettings()->getTestBehaviourSettings()->getKioskModeEnabled();
970 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowTitleInKioskMode();
974 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowParticipantNameInKioskMode();
979 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed();
984 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getQuestionTitleOutputMode();
989 $result = $this->db->queryF(
990 "SELECT tst_tests.use_previous_answers FROM tst_tests, tst_active WHERE tst_tests.test_id = tst_active.test_fi AND tst_active.active_id = %s",
994 if ($result->numRows()) {
995 $row = $this->db->fetchAssoc($result);
996 $test_allows_reuse = $row[
"use_previous_answers"];
999 if ($test_allows_reuse ===
'1') {
1000 $res = $this->
user->getPref(
"tst_use_previous_answers");
1014 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
1022 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
1023 if ($processing_time && $processing_time !==
'') {
1024 if (preg_match(
"/(\d{2}):(\d{2}):(\d{2})/is", (
string) $processing_time, $matches)) {
1026 'hh' => $matches[1],
1027 'mm' => $matches[2],
1028 'ss' => $matches[3],
1036 if ($this->processing_time !== null) {
1037 if (preg_match(
"/(\d{2}):(\d{2}):(\d{2})/is", (
string) $this->processing_time, $matches)) {
1038 return ($matches[1] * 60) + $matches[2];
1042 return self::DEFAULT_PROCESSING_TIME_MINUTES;
1054 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime() ??
'';
1055 if (preg_match(
"/(\d{2}):(\d{2}):(\d{2})/", (
string) $processing_time, $matches)) {
1057 return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
1065 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTimeEnabled();
1070 return $this->
getMainSettings()->getTestBehaviourSettings()->getResetProcessingTime();
1075 return $this->
getMainSettings()->getAccessSettings()->getStartTimeEnabled();
1080 $start_time = $this->
getMainSettings()->getAccessSettings()->getStartTime();
1081 return $start_time !== null ? $start_time->getTimestamp() : 0;
1086 return $this->
getMainSettings()->getAccessSettings()->getEndTimeEnabled();
1091 $end_time = $this->
getMainSettings()->getAccessSettings()->getEndTime();
1092 return $end_time !== null ? $end_time->getTimestamp() : 0;
1097 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode();
1102 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode() === self::REDIRECT_KIOSK;
1107 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode() === self::REDIRECT_NONE;
1112 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionUrl() ??
'';
1117 return $this->
getMainSettings()->getAccessSettings()->getPasswordEnabled();
1138 foreach ($activeIds as $activeId) {
1140 $passSelector->setActiveId($activeId);
1142 foreach ($passSelector->getExistingPasses() as $pass) {
1143 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($activeId, $pass);
1146 $test_sequence->removeQuestion($questionId, $reindexedSequencePositionMap);
1157 foreach ($removeQuestionIds as $value) {
1167 $question = self::_instanciateQuestion($question_id);
1174 $question->delete($question_id);
1176 $this->log->error($e->getMessage());
1177 $this->log->error($e->getTraceAsString());
1194 $participantData->setUserIdsFilter($userIds);
1195 $participantData->load($this->
getTestId());
1209 if ($test_lp instanceof
ilTestLP) {
1210 $test_lp->setTestObject($this);
1211 $test_lp->resetLPDataForUserIds($participantData->
getUserIds(),
false);
1223 $participantData->setUserIdsFilter($userIds);
1224 $participantData->load($this->
getTestId());
1226 $IN_userIds = $this->db->in(
'usr_id', $participantData->getUserIds(),
false,
'integer');
1227 $this->db->manipulateF(
1228 "DELETE FROM usr_pref WHERE $IN_userIds AND keyword = %s",
1233 if (count($participantData->getActiveIds())) {
1240 $IN_activeIds = $this->db->in(
'active_fi', $activeIds,
false,
'integer');
1242 $this->db->manipulate(
"DELETE FROM tst_solutions WHERE $IN_activeIds");
1243 $this->db->manipulate(
"DELETE FROM tst_qst_solved WHERE $IN_activeIds");
1244 $this->db->manipulate(
"DELETE FROM tst_test_result WHERE $IN_activeIds");
1245 $this->db->manipulate(
"DELETE FROM tst_pass_result WHERE $IN_activeIds");
1246 $this->db->manipulate(
"DELETE FROM tst_result_cache WHERE $IN_activeIds");
1247 $this->db->manipulate(
"DELETE FROM tst_sequence WHERE $IN_activeIds");
1248 $this->db->manipulate(
"DELETE FROM tst_times WHERE $IN_activeIds");
1252 $this->db->manipulate(
"DELETE FROM tst_test_rnd_qst WHERE $IN_activeIds");
1255 foreach ($activeIds as $active_id) {
1271 $IN_activeIds = $this->db->in(
'active_id', $activeIds,
false,
'integer');
1272 $this->db->manipulate(
"DELETE FROM tst_active WHERE $IN_activeIds");
1285 $result = $this->db->queryF(
1286 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1287 [
'integer',
'integer'],
1290 $data = $this->db->fetchObject($result);
1291 if (
$data->sequence > 1) {
1293 $result = $this->db->queryF(
1294 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1295 [
'integer',
'integer'],
1298 $data_previous = $this->db->fetchObject($result);
1300 $this->db->manipulateF(
1301 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1302 [
'integer',
'integer'],
1303 [
$data->sequence, $data_previous->test_question_id]
1306 $this->db->manipulateF(
1307 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1308 [
'integer',
'integer'],
1309 [
$data->sequence - 1,
$data->test_question_id]
1328 $result = $this->db->queryF(
1329 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1330 [
'integer',
'integer'],
1333 $data = $this->db->fetchObject($result);
1334 $result = $this->db->queryF(
1335 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1336 [
'integer',
'integer'],
1339 if ($result->numRows() == 1) {
1341 $data_next = $this->db->fetchObject($result);
1343 $this->db->manipulateF(
1344 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1345 [
'integer',
'integer'],
1346 [
$data->sequence, $data_next->test_question_id]
1349 $this->db->manipulateF(
1350 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1351 [
'integer',
'integer'],
1352 [
$data->sequence + 1,
$data->test_question_id]
1370 $duplicate_id = $question->duplicate(
true,
'',
'', -1, $this->
getId());
1371 return $duplicate_id;
1385 $duplicate_id = $question_id;
1391 $result = $this->db->queryF(
1392 "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
1398 if ($result->numRows() == 1) {
1399 $data = $this->db->fetchObject($result);
1400 $sequence =
$data->seq + 1;
1403 $next_id = $this->db->nextId(
'tst_test_question');
1404 $affectedRows = $this->db->manipulateF(
1405 "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
1406 [
'integer',
'integer',
'integer',
'integer',
'integer'],
1407 [$next_id, $this->
getTestId(), $duplicate_id, $sequence, time()]
1409 if ($affectedRows == 1) {
1415 $affectedRows = $this->db->manipulateF(
1416 "DELETE FROM tst_active WHERE test_fi = %s",
1422 return $duplicate_id;
1436 $result = $this->db->queryF(
1437 "SELECT qpl_questions.title FROM tst_test_question, qpl_questions WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ORDER BY tst_test_question.sequence",
1441 while ($row = $this->db->fetchAssoc($result)) {
1442 array_push($titles, $row[
"title"]);
1459 $result = $this->db->queryF(
1460 "SELECT qpl_questions.title, qpl_questions.question_id FROM tst_test_question, qpl_questions WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ORDER BY tst_test_question.sequence",
1464 while ($row = $this->db->fetchAssoc($result)) {
1465 $titles[$row[
'question_id']] = $row[
"title"];
1490 return $this->
lng->txt(
"ass_question") .
' ' . $nr;
1492 return $this->
lng->txt(
"ass_question");
1496 $txt = $this->
lng->txt(
"ass_question") .
' ' . $nr;
1498 $txt = $this->
lng->txt(
"ass_question");
1500 if ($points !=
'') {
1501 $lngv = $this->
lng->txt(
'points');
1503 $lngv = $this->
lng->txt(
'point');
1505 $txt .=
' - ' . $points .
' ' . $lngv;
1511 return $this->
lng->txt(
"ass_question");
1525 $result = $this->db->queryF(
1526 "SELECT qpl_questions.*, qpl_qst_type.type_tag FROM qpl_questions, qpl_qst_type WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id",
1530 $row = $this->db->fetchObject($result);
1542 $existing_questions = [];
1545 if (is_null($pass)) {
1548 $result = $this->db->queryF(
1549 "SELECT qpl_questions.original_id FROM qpl_questions, tst_test_rnd_qst WHERE tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.question_fi = qpl_questions.question_id AND tst_test_rnd_qst.pass = %s",
1550 [
'integer',
'integer'],
1554 $result = $this->db->queryF(
1555 "SELECT qpl_questions.original_id FROM qpl_questions, tst_test_question WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id",
1560 while (
$data = $this->db->fetchObject($result)) {
1561 if (
$data->original_id === null) {
1565 array_push($existing_questions,
$data->original_id);
1567 return $existing_questions;
1579 if ($question_id < 1) {
1582 $result = $this->db->queryF(
1583 "SELECT type_tag FROM qpl_questions, qpl_qst_type WHERE qpl_questions.question_id = %s AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id",
1587 if ($result->numRows() == 1) {
1588 $data = $this->db->fetchObject($result);
1589 return $data->type_tag;
1603 $next_id = $this->db->nextId(
'tst_times');
1604 $affectedRows = $this->db->manipulateF(
1605 "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
1606 [
'integer',
'integer',
'timestamp',
'timestamp',
'integer',
'integer'],
1607 [$next_id, $active_id, date(
"Y-m-d H:i:s"), date(
"Y-m-d H:i:s"), $pass, time()]
1620 $affectedRows = $this->db->manipulateF(
1621 "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
1622 [
'timestamp',
'integer',
'integer'],
1623 [date(
'Y-m-d H:i:s'), time(), $times_id]
1635 if (is_null($pass)) {
1636 $result = $this->db->queryF(
1637 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1638 [
'integer',
'integer'],
1642 $result = $this->db->queryF(
1643 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1644 [
'integer',
'integer'],
1649 while ($row = $this->db->fetchAssoc($result)) {
1650 array_push($result_array, $row[
"question_fi"]);
1652 return $result_array;
1666 return ((($currentpass > 0) && ($num == 0)) || $this->
isTestFinished($active_id)) ? true :
false;
1681 if (count($this->questions) == 0) {
1682 return $result_array;
1684 if (is_null($pass)) {
1685 $pass = self::_getPass($active_id);
1687 $result = $this->db->queryF(
1688 "SELECT qpl_questions.* FROM qpl_questions, tst_test_rnd_qst WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s AND " . $this->db->in(
'qpl_questions.question_id', $this->questions,
false,
'integer'),
1689 [
'integer',
'integer'],
1693 if (count($this->questions) == 0) {
1694 return $result_array;
1696 $result = $this->db->query(
"SELECT qpl_questions.* FROM qpl_questions, tst_test_question WHERE tst_test_question.question_fi = qpl_questions.question_id AND " . $this->db->in(
'qpl_questions.question_id', $this->questions,
false,
'integer'));
1698 while ($row = $this->db->fetchAssoc($result)) {
1699 $result_array[$row[
"question_id"]] = $row;
1701 return $result_array;
1715 $user_id = $this->
user->getId();
1719 if (is_array($tst_access_code) &&
1721 isset($tst_access_code[$this->
getTestId()]) &&
1722 $tst_access_code[$this->
getTestId()] !==
'') {
1723 $result = $this->db->queryF(
1724 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1725 [
'integer',
'integer',
'text'],
1726 [$user_id, $this->test_id, $tst_access_code[$this->
getTestId()]]
1728 } elseif ((
string) $anonymous_id !==
'') {
1729 $result = $this->db->queryF(
1730 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1731 [
'integer',
'integer',
'text'],
1732 [$user_id, $this->test_id, $anonymous_id]
1738 $result = $this->db->queryF(
1739 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s',
1740 [
'integer',
'integer'],
1741 [$user_id, $this->test_id]
1745 if ($result->numRows()) {
1746 $row = $this->db->fetchAssoc($result);
1747 return (
int) $row[
'active_id'];
1756 $ilDB = $DIC[
'ilDB'];
1757 $ilUser = $DIC[
'ilUser'];
1760 $user_id = $ilUser->id;
1765 $result =
$ilDB->queryF(
1766 "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
1767 [
'integer',
'integer'],
1768 [$user_id, $test_id]
1770 if ($result->numRows()) {
1771 $row =
$ilDB->fetchAssoc($result);
1772 return $row[
"active_id"];
1786 $keys = array_keys($array);
1789 foreach ($keys as
$key) {
1804 bool $ordered_sequence =
false,
1805 bool $considerHiddenQuestions =
true,
1806 bool $considerOptionalQuestions =
true 1810 if ($pass === null) {
1815 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $pass);
1817 $test_sequence->setConsiderHiddenQuestionsEnabled($considerHiddenQuestions);
1818 $test_sequence->setConsiderOptionalQuestionsEnabled($considerOptionalQuestions);
1823 if ($ordered_sequence) {
1833 tst_test_result.question_fi, 1834 tst_test_result.points reached, 1835 tst_test_result.hint_count requested_hints, 1836 tst_test_result.hint_points hint_points, 1837 tst_test_result.answered answered, 1838 tst_manual_fb.finalized_evaluation finalized_evaluation 1840 FROM tst_test_result 1842 LEFT JOIN tst_solutions 1843 ON tst_solutions.active_fi = tst_test_result.active_fi 1844 AND tst_solutions.question_fi = tst_test_result.question_fi 1846 LEFT JOIN tst_manual_fb 1847 ON tst_test_result.active_fi = tst_manual_fb.active_fi 1848 AND tst_test_result.question_fi = tst_manual_fb.question_fi 1850 WHERE tst_test_result.active_fi = %s 1851 AND tst_test_result.pass = %s 1854 $solutionresult = $this->db->queryF(
1856 [
'integer',
'integer'],
1860 while ($row = $this->db->fetchAssoc($solutionresult)) {
1861 $arrResults[ $row[
'question_fi'] ] = $row;
1864 $numWorkedThrough = count($arrResults);
1866 $IN_question_ids = $this->db->in(
'qpl_questions.question_id', $sequence,
false,
'integer');
1869 SELECT qpl_questions.*, 1870 qpl_qst_type.type_tag, 1871 qpl_sol_sug.question_fi has_sug_sol 1876 LEFT JOIN qpl_sol_sug 1877 ON qpl_sol_sug.question_fi = qpl_questions.question_id 1879 WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi 1880 AND $IN_question_ids 1883 $result = $this->db->query($query);
1889 $obligationsAnswered =
true;
1891 while ($row = $this->db->fetchAssoc($result)) {
1892 if (!isset($arrResults[ $row[
'question_id'] ])) {
1893 $percentvalue = 0.0;
1896 $row[
'points'] ? $arrResults[$row[
'question_id']][
'reached'] / $row[
'points'] : 0
1899 if ($percentvalue < 0) {
1900 $percentvalue = 0.0;
1906 "max" => round($row[
'points'], 2),
1907 "reached" => round($arrResults[$row[
'question_id']][
'reached'] ?? 0, 2),
1908 'requested_hints' => $arrResults[$row[
'question_id']][
'requested_hints'] ?? 0,
1909 'hint_points' => $arrResults[$row[
'question_id']][
'hint_points'] ?? 0,
1910 "percent" => sprintf(
"%2.2f ", ($percentvalue) * 100) .
"%",
1912 "type" => $row[
"type_tag"],
1913 "qid" => $row[
'question_id'],
1914 "original_id" => $row[
"original_id"],
1915 "workedthrough" => isset($arrResults[$row[
'question_id']]) ? 1 : 0,
1916 'answered' => $arrResults[$row[
'question_id']][
'answered'] ?? 0,
1917 'finalized_evaluation' => $arrResults[$row[
'question_id']][
'finalized_evaluation'] ?? 0,
1920 if (!isset($arrResults[ $row[
'question_id'] ][
'answered']) || !$arrResults[ $row[
'question_id'] ][
'answered']) {
1921 $obligationsAnswered =
false;
1924 $unordered[ $row[
'question_id'] ] =
$data;
1929 $numQuestionsTotal = count($unordered);
1933 $pass_requested_hints = 0;
1934 $pass_hint_points = 0;
1939 foreach ($sequence as $qid) {
1942 $pass_max += round($unordered[$qid][
'max'], 2);
1943 $pass_reached += round($unordered[$qid][
'reached'], 2);
1944 $pass_requested_hints += $unordered[$qid][
'requested_hints'];
1945 $pass_hint_points += $unordered[$qid][
'hint_points'];
1949 $unordered[$qid][
'nr'] =
$key;
1950 array_push($found, $unordered[$qid]);
1959 if (
$results[
'reached_points'] < 0) {
1963 if ($pass_reached < 0) {
1968 $found[
'pass'][
'total_max_points'] = $pass_max;
1969 $found[
'pass'][
'total_reached_points'] = $pass_reached;
1970 $found[
'pass'][
'total_requested_hints'] = $pass_requested_hints;
1971 $found[
'pass'][
'total_hint_points'] = $pass_hint_points;
1972 $found[
'pass'][
'percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
1973 $found[
'pass'][
'obligationsAnswered'] = $obligationsAnswered;
1974 $found[
'pass'][
'num_workedthrough'] = $numWorkedThrough;
1975 $found[
'pass'][
'num_questions_total'] = $numQuestionsTotal;
1977 $found[
"test"][
"total_max_points"] =
$results[
'max_points'];
1978 $found[
"test"][
"total_reached_points"] =
$results[
'reached_points'];
1979 $found[
"test"][
"total_requested_hints"] =
$results[
'hint_count'];
1980 $found[
"test"][
"total_hint_points"] =
$results[
'hint_points'];
1981 $found[
"test"][
"result_pass"] =
$results[
'pass'];
1982 $found[
'test'][
'result_tstamp'] =
$results[
'tstamp'];
1983 $found[
'test'][
'obligations_answered'] =
$results[
'obligations_answered'];
1985 if ((!$found[
'pass'][
'total_reached_points']) or (!$found[
'pass'][
'total_max_points'])) {
1988 $percentage = ($found[
'pass'][
'total_reached_points'] / $found[
'pass'][
'total_max_points']) * 100.0;
1990 if ($percentage < 0) {
1995 $found[
"test"][
"passed"] =
$results[
'passed'];
2008 $result = $this->db->queryF(
2009 "SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s",
2013 $row = $this->db->fetchAssoc($result);
2014 return $row[
"total"];
2025 $result = $this->db->queryF(
2026 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi AND tst_active.user_fi = %s",
2027 [
'integer',
'integer'],
2031 while ($row = $this->db->fetchAssoc($result)) {
2032 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2041 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2050 $time += ($epoch_2 - $epoch_1);
2075 $result = $this->db->queryF(
2076 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi ORDER BY tst_times.active_fi, tst_times.started",
2082 while ($row = $this->db->fetchAssoc($result)) {
2083 if (!array_key_exists($row[
"active_fi"], $times)) {
2084 $times[$row[
"active_fi"]] = 0;
2086 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2095 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2104 $times[$row[
"active_fi"]] += ($epoch_2 - $epoch_1);
2117 $result = $this->db->queryF(
2118 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi AND tst_active.active_id = %s ORDER BY tst_times.active_fi, tst_times.started",
2119 [
'integer',
'integer'],
2123 while ($row = $this->db->fetchAssoc($result)) {
2124 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2133 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2142 $time += ($epoch_2 - $epoch_1);
2156 $ilDB = $DIC[
'ilDB'];
2158 $result =
$ilDB->queryF(
2159 "SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
2160 [
'integer',
'integer'],
2164 while ($row =
$ilDB->fetchAssoc($result)) {
2165 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2174 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2183 $time += ($epoch_2 - $epoch_1);
2210 $result = $this->db->queryF(
2211 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi AND tst_active.active_id = %s ORDER BY tst_times.started",
2212 [
'integer',
'integer'],
2213 [$test_id, $active_id]
2217 while ($row = $this->db->fetchAssoc($result)) {
2218 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2227 if ($firstvisit == 0 || $epoch_1 < $firstvisit) {
2228 $firstvisit = $epoch_1;
2230 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2239 if ($epoch_2 > $lastvisit) {
2240 $lastvisit = $epoch_2;
2243 return [
"firstvisit" => $firstvisit,
"lastvisit" => $lastvisit];
2253 $result = $this->db->queryF(
2254 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
2261 while ($row = $this->db->fetchObject($result)) {
2262 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2271 if (!$first_visit) {
2272 $first_visit = $epoch_1;
2274 if ($epoch_1 < $first_visit) {
2275 $first_visit = $epoch_1;
2277 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2287 $last_visit = $epoch_2;
2289 if ($epoch_2 > $last_visit) {
2290 $last_visit = $epoch_2;
2292 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2295 foreach ($times as
$key => $value) {
2296 $max_time += $value;
2298 if ((!$test_result[
"test"][
"total_reached_points"]) or (!$test_result[
"test"][
"total_max_points"])) {
2301 $percentage = ($test_result[
"test"][
"total_reached_points"] / $test_result[
"test"][
"total_max_points"]) * 100.0;
2302 if ($percentage < 0) {
2306 $mark_obj = $this->mark_schema->getMatchingMark($percentage);
2307 $first_date = getdate($first_visit);
2308 $last_date = getdate($last_visit);
2309 $qworkedthrough = 0;
2310 foreach ($test_result as
$key => $value) {
2311 if (preg_match(
"/\d+/",
$key)) {
2312 $qworkedthrough += $value[
"workedthrough"];
2315 if (!$qworkedthrough) {
2318 $atimeofwork = $max_time / $qworkedthrough;
2321 $obligationsAnswered = $test_result[
"test"][
"obligations_answered"];
2327 $result_mark = $mark_obj->getShortName();
2329 if ($mark_obj->getPassed() && $obligationsAnswered) {
2335 $percent_worked_through = 0;
2336 if (count($this->questions)) {
2337 $percent_worked_through = $qworkedthrough / count($this->questions);
2340 "qworkedthrough" => $qworkedthrough,
2341 "qmax" => count($this->questions),
2342 "pworkedthrough" => $percent_worked_through,
2343 "timeofwork" => $max_time,
2344 "atimeofwork" => $atimeofwork,
2345 "firstvisit" => $first_date,
2346 "lastvisit" => $last_date,
2347 "resultspoints" => $test_result[
"test"][
"total_reached_points"],
2348 "maxpoints" => $test_result[
"test"][
"total_max_points"],
2349 "resultsmarks" => $result_mark,
2350 "passed" => $passed,
2351 "distancemedian" =>
"0" 2353 foreach ($test_result as
$key => $value) {
2354 if (preg_match(
"/\d+/",
$key)) {
2355 $result_array[
$key] = $value;
2358 return $result_array;
2370 $totalpoints_array = [];
2372 foreach ($all_users as $active_id => $user_name) {
2374 $reached = $test_result[
"test"][
"total_reached_points"];
2375 $total = $test_result[
"test"][
"total_max_points"];
2376 $percentage = $total != 0 ? $reached / $total : 0;
2377 $mark = $this->mark_schema->getMatchingMark($percentage * 100.0);
2379 $obligationsAnswered = $test_result[
"test"][
"obligations_answered"];
2382 if ($mark->getPassed() && $obligationsAnswered) {
2383 array_push($totalpoints_array, $test_result[
"test"][
"total_reached_points"]);
2387 return $totalpoints_array;
2397 $result = $this->db->queryF(
2398 "SELECT tst_active.active_id, usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login FROM tst_active LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id WHERE tst_active.test_fi = %s ORDER BY usr_data.lastname ASC",
2402 $persons_array = [];
2403 while ($row = $this->db->fetchAssoc($result)) {
2404 $name = $this->
lng->txt(
"anonymous");
2405 $fullname = $this->
lng->txt(
"anonymous");
2408 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2409 $name = $this->
lng->txt(
"deleted_user");
2410 $fullname = $this->
lng->txt(
"deleted_user");
2411 $login = $this->
lng->txt(
"unknown");
2413 $login = $row[
"login"];
2415 $name = $this->
lng->txt(
"anonymous");
2416 $fullname = $this->
lng->txt(
"anonymous");
2418 $name = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2419 $fullname = trim($row[
"title"] .
" " . $row[
"firstname"] .
" " . $row[
"lastname"]);
2423 $persons_array[$row[
"active_id"]] = [
2425 "fullname" => $fullname,
2429 return $persons_array;
2440 $result = $this->db->queryF(
2441 "SELECT tst_active.user_fi, tst_active.active_id, usr_data.firstname, usr_data.lastname, usr_data.title FROM tst_active LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id WHERE tst_active.test_fi = %s ORDER BY usr_data.lastname " . strtoupper($name_sort_order),
2445 $persons_array = [];
2446 while ($row = $this->db->fetchAssoc($result)) {
2452 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"anonymous");
2454 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2455 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"deleted_user");
2458 $persons_array[$row[
"active_id"]] = $row[
"lastname"];
2460 $persons_array[$row[
"active_id"]] = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2465 return $persons_array;
2475 $result = $this->db->queryF(
2476 "SELECT tst_active.user_fi, tst_active.active_id, usr_data.login, usr_data.firstname, usr_data.lastname, usr_data.title FROM tst_active LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id WHERE tst_active.test_fi = %s ORDER BY usr_data.lastname " . strtoupper($name_sort_order),
2480 $persons_array = [];
2481 while ($row = $this->db->fetchAssoc($result)) {
2483 $persons_array[$row[
"active_id"]] = [
"name" => $this->
lng->txt(
"anonymous")];
2485 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2486 $persons_array[$row[
"active_id"]] = [
"name" => $this->
lng->txt(
"deleted_user")];
2489 $persons_array[$row[
"active_id"]] = [
"name" => $row[
"lastname"]];
2491 $persons_array[$row[
"active_id"]] = [
"name" => trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]),
"login" => $row[
"login"]];
2496 return $persons_array;
2509 $result = $this->db->queryF(
2510 "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
2511 "tst_test_rnd_qst.pass, qpl_questions.points " .
2512 "FROM tst_test_rnd_qst, qpl_questions " .
2513 "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
2514 "AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence",
2519 $result = $this->db->queryF(
2520 "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
2521 "qpl_questions.points " .
2522 "FROM tst_test_question, tst_active, qpl_questions " .
2523 "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
2524 "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
2530 if ($result->numRows()) {
2531 while ($row = $this->db->fetchAssoc($result)) {
2532 array_push($qtest, $row);
2548 $result = $this->db->queryF(
2549 "SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, " .
2550 "qpl_questions.points " .
2551 "FROM tst_test_rnd_qst, qpl_questions " .
2552 "WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id " .
2553 "AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s " .
2554 "ORDER BY tst_test_rnd_qst.sequence",
2555 [
'integer',
'integer'],
2559 $result = $this->db->queryF(
2560 "SELECT tst_test_question.sequence, tst_test_question.question_fi, " .
2561 "qpl_questions.points " .
2562 "FROM tst_test_question, tst_active, qpl_questions " .
2563 "WHERE tst_test_question.question_fi = qpl_questions.question_id " .
2564 "AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi",
2570 if ($result->numRows()) {
2571 while ($row = $this->db->fetchAssoc($result)) {
2572 array_push($qpass, $row);
2593 return $list->getAccessFilteredList(
2594 $this->participant_access_filter->getAccessStatisticsUserFilter($this->getRefId())
2601 ->getEvaluationData();
2607 $ilDB = $DIC[
'ilDB'];
2611 switch ($questionSetType) {
2616 SELECT tst_test_rnd_qst.pass, 2617 COUNT(tst_test_rnd_qst.question_fi) qcount, 2618 SUM(qpl_questions.points) qsum 2620 FROM tst_test_rnd_qst, 2623 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id 2624 AND tst_test_rnd_qst.active_fi = %s 2627 GROUP BY tst_test_rnd_qst.active_fi, 2628 tst_test_rnd_qst.pass 2630 [
'integer',
'integer'],
2640 SELECT COUNT(tst_test_question.question_fi) qcount, 2641 SUM(qpl_questions.points) qsum 2643 FROM tst_test_question, 2647 WHERE tst_test_question.question_fi = qpl_questions.question_id 2648 AND tst_test_question.test_fi = tst_active.test_fi 2649 AND tst_active.active_id = %s 2651 GROUP BY tst_test_question.test_fi 2661 throw new ilTestException(
"not supported question set type: $questionSetType");
2666 if (is_array($row)) {
2667 return [
"count" => $row[
"qcount"],
"points" => $row[
"qsum"]];
2670 return [
"count" => 0,
"points" => 0];
2676 if ($withStatistics) {
2677 $data->calculateStatistics();
2679 $data->setFilter($filterby, $filtertext);
2702 $result = $this->db->queryF(
2703 "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
2704 "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
2705 "qpl_questions.points maxpoints " .
2706 "FROM tst_test_result, qpl_questions, tst_active " .
2707 "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
2708 "WHERE tst_active.active_id = tst_test_result.active_fi " .
2709 "AND qpl_questions.question_id = tst_test_result.question_fi " .
2710 "AND tst_active.test_fi = %s " .
2711 "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
2716 while ($row = $this->db->fetchAssoc($result)) {
2717 if (!array_key_exists($row[
"active_fi"], $overview)) {
2718 $overview[$row[
"active_fi"]] = [];
2719 $overview[$row[
"active_fi"]][
"firstname"] = $row[
"firstname"];
2720 $overview[$row[
"active_fi"]][
"lastname"] = $row[
"lastname"];
2721 $overview[$row[
"active_fi"]][
"title"] = $row[
"title"];
2722 $overview[$row[
"active_fi"]][
"login"] = $row[
"login"];
2723 $overview[$row[
"active_fi"]][
"usr_id"] = $row[
"usr_id"];
2724 $overview[$row[
"active_fi"]][
"started"] = $row[
"started"];
2725 $overview[$row[
"active_fi"]][
"finished"] = $row[
"finished"];
2727 if (!array_key_exists($row[
"pass"], $overview[$row[
"active_fi"]])) {
2728 $overview[$row[
"active_fi"]][$row[
"pass"]] = [];
2729 $overview[$row[
"active_fi"]][$row[
"pass"]][
"reached"] = 0;
2730 $overview[$row[
"active_fi"]][$row[
"pass"]][
"maxpoints"] = $row[
"maxpoints"];
2732 array_push($overview[$row[
"active_fi"]][$row[
"pass"]], $row);
2733 $overview[$row[
"active_fi"]][$row[
"pass"]][
"reached"] += $row[
"points"];
2747 $result = $this->db->queryF(
2748 "SELECT usr_data.usr_id, usr_data.firstname, usr_data.lastname, usr_data.title, usr_data.login, " .
2749 "tst_test_result.*, qpl_questions.original_id, qpl_questions.title questiontitle, " .
2750 "qpl_questions.points maxpoints " .
2751 "FROM tst_test_result, qpl_questions, tst_active " .
2752 "LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id " .
2753 "WHERE tst_active.active_id = tst_test_result.active_fi " .
2754 "AND qpl_questions.question_id = tst_test_result.question_fi " .
2755 "AND tst_active.test_fi = %s AND tst_active.active_id = %s" .
2756 "ORDER BY tst_active.active_id, tst_test_result.pass, tst_test_result.tstamp",
2757 [
'integer',
'integer'],
2761 while ($row = $this->db->fetchAssoc($result)) {
2762 if (!array_key_exists($row[
"active_fi"], $overview)) {
2763 $overview[$row[
"active_fi"]] = [];
2764 $overview[$row[
"active_fi"]][
"firstname"] = $row[
"firstname"];
2765 $overview[$row[
"active_fi"]][
"lastname"] = $row[
"lastname"];
2766 $overview[$row[
"active_fi"]][
"title"] = $row[
"title"];
2767 $overview[$row[
"active_fi"]][
"login"] = $row[
"login"];
2768 $overview[$row[
"active_fi"]][
"usr_id"] = $row[
"usr_id"];
2769 $overview[$row[
"active_fi"]][
"started"] = $row[
"started"];
2770 $overview[$row[
"active_fi"]][
"finished"] = $row[
"finished"];
2772 if (!array_key_exists($row[
"pass"], $overview[$row[
"active_fi"]])) {
2773 $overview[$row[
"active_fi"]][$row[
"pass"]] = [];
2774 $overview[$row[
"active_fi"]][$row[
"pass"]][
"reached"] = 0;
2775 $overview[$row[
"active_fi"]][$row[
"pass"]][
"maxpoints"] = $row[
"maxpoints"];
2777 array_push($overview[$row[
"active_fi"]][$row[
"pass"]], $row);
2778 $overview[$row[
"active_fi"]][$row[
"pass"]][
"reached"] += $row[
"points"];
2799 if ($user_id === null
2800 || $firstname . $lastname ===
'') {
2801 return $this->
lng->txt(
'deleted_user');
2805 return $this->
lng->txt(
'anonymous');
2812 return trim($lastname .
', ' . $firstname);
2817 $query =
"SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi";
2819 if ($active_ids_to_filter !== null && $active_ids_to_filter !== []) {
2820 $query .=
" AND " . $this->db->in(
'active_id', $active_ids_to_filter,
false,
'integer');
2823 $result = $this->db->queryF($query, [
'integer'], [$this->
getTestId()]);
2825 while ($row = $this->db->fetchObject($result)) {
2826 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2835 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2844 if (isset($times[$row->active_fi])) {
2845 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2847 $times[$row->active_fi] = ($epoch_2 - $epoch_1);
2852 foreach ($times as
$key => $value) {
2853 $max_time += $value;
2857 $average_time = round($max_time / $counter);
2861 return $average_time;
2870 public function getAvailableQuestionpools($use_object_id =
false, $equal_points =
false, $could_be_offline =
false, $show_path =
false, $with_questioncount =
false, $permission =
"read"): array
2912 if ((!$question_type) and ($question_id > 0)) {
2916 if (!strlen($question_type)) {
2920 $question_type_gui = $question_type .
'GUI';
2921 $question =
new $question_type_gui();
2923 if ($question_id > 0) {
2924 $question->object->loadFromDb($question_id);
2927 $question->object->feedbackOBJ =
new $feedbackObjectClassname($question->object, $this->ctrl, $this->db, $this->lng);
2929 $assSettings =
new ilSetting(
'assessment');
2931 $processLockerFactory->setQuestionId($question->object->getId());
2932 $processLockerFactory->setUserId($this->
user->getId());
2934 $question->object->setProcessLocker($processLockerFactory->getLocker());
2948 if (strcmp((
string) $question_id,
"") !== 0) {
2965 $this->questions = array_values($this->questions);
2966 $array_pos = array_search($target_index, $this->questions);
2967 if ($insert_mode == 0) {
2968 $part1 = array_slice($this->questions, 0, $array_pos);
2969 $part2 = array_slice($this->questions, $array_pos);
2970 } elseif ($insert_mode == 1) {
2971 $part1 = array_slice($this->questions, 0, $array_pos + 1);
2972 $part2 = array_slice($this->questions, $array_pos + 1);
2974 foreach ($move_questions as $question_id) {
2975 if (!(array_search($question_id, $part1) ===
false)) {
2976 unset($part1[array_search($question_id, $part1)]);
2978 if (!(array_search($question_id, $part2) ===
false)) {
2979 unset($part2[array_search($question_id, $part2)]);
2982 $part1 = array_values($part1);
2983 $part2 = array_values($part2);
2984 $new_array = array_values(array_merge($part1, $move_questions, $part2));
2985 $this->questions = [];
2987 foreach ($new_array as $question_id) {
2988 $this->questions[$counter] = $question_id;
3040 if (count($available_pools)) {
3041 $available =
" AND " . $this->db->in(
'qpl_questions.obj_fi', $available_pools,
false,
'integer');
3045 if ($completeonly) {
3046 $available .=
" AND qpl_questions.complete = " . $this->db->quote(
"1",
'text');
3050 if (is_array($arr_filter)) {
3051 if (array_key_exists(
'title', $arr_filter) && strlen($arr_filter[
'title'])) {
3052 $where .=
" AND " . $this->db->like(
'qpl_questions.title',
'text',
"%%" . $arr_filter[
'title'] .
"%%");
3054 if (array_key_exists(
'description', $arr_filter) && strlen($arr_filter[
'description'])) {
3055 $where .=
" AND " . $this->db->like(
'qpl_questions.description',
'text',
"%%" . $arr_filter[
'description'] .
"%%");
3057 if (array_key_exists(
'author', $arr_filter) && strlen($arr_filter[
'author'])) {
3058 $where .=
" AND " . $this->db->like(
'qpl_questions.author',
'text',
"%%" . $arr_filter[
'author'] .
"%%");
3060 if (array_key_exists(
'type', $arr_filter) && strlen($arr_filter[
'type'])) {
3061 $where .=
" AND qpl_qst_type.type_tag = " . $this->db->quote($arr_filter[
'type'],
'text');
3063 if (array_key_exists(
'qpl', $arr_filter) && strlen($arr_filter[
'qpl'])) {
3064 $where .=
" AND " . $this->db->like(
'object_data.title',
'text',
"%%" . $arr_filter[
'qpl'] .
"%%");
3069 $original_clause =
" qpl_questions.original_id IS NULL";
3070 if (count($original_ids)) {
3071 $original_clause =
" qpl_questions.original_id IS NULL AND " . $this->db->in(
'qpl_questions.question_id', $original_ids,
true,
'integer');
3074 $query_result = $this->db->query(
" 3075 SELECT qpl_questions.*, qpl_questions.tstamp, 3076 qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name, 3077 object_data.title parent_title 3078 FROM qpl_questions, qpl_qst_type, object_data 3079 WHERE $original_clause $available 3080 AND object_data.obj_id = qpl_questions.obj_fi 3081 AND qpl_questions.tstamp > 0 3082 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id 3087 if ($query_result->numRows()) {
3088 while ($row = $this->db->fetchAssoc($query_result)) {
3091 if (!$row[
'plugin']) {
3092 $row[
'ttype' ] = $this->
lng->txt($row[
"type_tag" ]);
3098 $plugin = $this->component_repository->getPluginByName($row[
'plugin_name']);
3103 $pl = $this->component_factory->getPlugin(
$plugin->getId());
3104 $row[
'ttype' ] = $pl->getQuestionTypeTranslation();
3132 $introduction_settings = $introduction_settings->withIntroductionEnabled(
false);
3133 foreach ($assessment->objectives as
$objectives) {
3134 foreach ($objectives->materials as $material) {
3136 $introduction_settings,
3147 $finishing_settings,
3160 foreach ($assessment->qtimetadata as
$metadata) {
3161 switch ($metadata[
"label"]) {
3162 case "solution_details":
3163 $result_details_settings = $result_details_settings->withShowPassDetails((
bool) $metadata[
"entry"]);
3165 case "show_solution_list_comparison":
3166 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
3168 case "print_bs_with_res":
3169 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
3175 $test_behaviour_settings = $test_behaviour_settings->withNumberOfTries((
int) $metadata[
"entry"]);
3177 case 'block_after_passed':
3178 $test_behaviour_settings = $test_behaviour_settings->withBlockAfterPassedEnabled((
bool) $metadata[
'entry']);
3180 case "pass_waiting":
3181 $test_behaviour_settings = $test_behaviour_settings->withPassWaiting($metadata[
"entry"]);
3184 $test_behaviour_settings = $test_behaviour_settings->withKioskMode((
int) $metadata[
"entry"]);
3186 case 'show_introduction':
3187 $introduction_settings = $introduction_settings->withIntroductionEnabled((
bool) $metadata[
'entry']);
3189 case "showfinalstatement":
3190 case 'show_concluding_remarks':
3191 $finishing_settings = $finishing_settings->withConcludingRemarksEnabled((
bool) $metadata[
"entry"]);
3193 case 'exam_conditions':
3194 $introduction_settings = $introduction_settings->withExamConditionsCheckboxEnabled($metadata[
'entry'] ===
'1');
3196 case "highscore_enabled":
3197 $gamification_settings = $gamification_settings->withHighscoreEnabled((
bool) $metadata[
"entry"]);
3199 case "highscore_anon":
3200 $gamification_settings = $gamification_settings->withHighscoreAnon((
bool) $metadata[
"entry"]);
3202 case "highscore_achieved_ts":
3203 $gamification_settings = $gamification_settings->withHighscoreAchievedTS((
bool) $metadata[
"entry"]);
3205 case "highscore_score":
3206 $gamification_settings = $gamification_settings->withHighscoreScore((
bool) $metadata[
"entry"]);
3208 case "highscore_percentage":
3209 $gamification_settings = $gamification_settings->withHighscorePercentage((
bool) $metadata[
"entry"]);
3211 case "highscore_hints":
3212 $gamification_settings = $gamification_settings->withHighscoreHints((
bool) $metadata[
"entry"]);
3214 case "highscore_wtime":
3215 $gamification_settings = $gamification_settings->withHighscoreWTime((
bool) $metadata[
"entry"]);
3217 case "highscore_own_table":
3218 $gamification_settings = $gamification_settings->withHighscoreOwnTable((
bool) $metadata[
"entry"]);
3220 case "highscore_top_table":
3221 $gamification_settings = $gamification_settings->withHighscoreTopTable((
bool) $metadata[
"entry"]);
3223 case "highscore_top_num":
3224 $gamification_settings = $gamification_settings->withHighscoreTopNum((
int) $metadata[
"entry"]);
3226 case "use_previous_answers":
3227 $participant_functionality_settings = $participant_functionality_settings->withUsePreviousAnswerAllowed((
bool) $metadata[
"entry"]);
3229 case 'question_list_enabled':
3230 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
'entry']);
3232 case "title_output":
3233 $question_behaviour_settings = $question_behaviour_settings->withQuestionTitleOutputMode((
int) $metadata[
"entry"]);
3235 case "question_set_type":
3236 $general_settings = $general_settings->withQuestionSetType($metadata[
"entry"]);
3239 $general_settings = $general_settings->withAnonymity((
bool) $metadata[
"entry"]);
3241 case "results_presentation":
3242 $result_details_settings = $result_details_settings->withResultsPresentation((
int) $metadata[
"entry"]);
3244 case "reset_processing_time":
3245 $test_behaviour_settings = $test_behaviour_settings->withResetProcessingTime($metadata[
"entry"] ===
'1');
3247 case "answer_feedback_points":
3248 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackPointsEnabled((
bool) $metadata[
"entry"]);
3250 case "answer_feedback":
3251 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackGenericEnabled((
bool) $metadata[
"entry"]);
3253 case 'instant_feedback_specific':
3254 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSpecificEnabled((
bool) $metadata[
'entry']);
3256 case "instant_verification":
3257 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSolutionEnabled((
bool) $metadata[
"entry"]);
3259 case "force_instant_feedback":
3260 $question_behaviour_settings = $question_behaviour_settings->withForceInstantFeedbackOnNextQuestion((
bool) $metadata[
"entry"]);
3262 case "follow_qst_answer_fixation":
3263 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnNextQuestionEnabled((
bool) $metadata[
"entry"]);
3265 case "instant_feedback_answer_fixation":
3266 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnInstantFeedbackEnabled((
bool) $metadata[
"entry"]);
3269 case "suspend_test_allowed":
3270 $participant_functionality_settings = $participant_functionality_settings->withSuspendTestAllowed((
bool) $metadata[
"entry"]);
3272 case "sequence_settings":
3273 $participant_functionality_settings = $participant_functionality_settings->withPostponedQuestionsMoveToEnd((
bool) $metadata[
"entry"]);
3276 $participant_functionality_settings = $participant_functionality_settings->withQuestionMarkingEnabled((
bool) $metadata[
"entry"]);
3278 case "fixed_participants":
3279 $access_settings = $access_settings->withFixedParticipants((
bool) $metadata[
"entry"]);
3281 case "score_reporting":
3282 $result_summary_settings = $result_summary_settings->withScoreReporting((
int) $metadata[
"entry"]);
3284 case "shuffle_questions":
3285 $question_behaviour_settings = $question_behaviour_settings->withShuffleQuestions((
bool) $metadata[
"entry"]);
3287 case "count_system":
3288 $scoring_settings = $scoring_settings->withCountSystem((
int) $metadata[
"entry"]);
3290 case "mailnotification":
3291 $finishing_settings = $finishing_settings->withMailNotificationContentType((
int) $metadata[
"entry"]);
3294 $finishing_settings = $finishing_settings->withAlwaysSendMailNotification((
bool) $metadata[
"entry"]);
3296 case "exportsettings":
3297 $result_details_settings = $result_details_settings->withExportSettings((
int) $metadata[
"entry"]);
3299 case "score_cutting":
3300 $scoring_settings = $scoring_settings->withScoreCutting((
int) $metadata[
"entry"]);
3303 $access_settings = $access_settings->withPasswordEnabled(
3304 $metadata[
"entry"] !== null && $metadata[
"entry"] !==
'' 3305 )->withPassword($metadata[
"entry"]);
3307 case "pass_scoring":
3308 $scoring_settings = $scoring_settings->withPassScoring((
int) $metadata[
"entry"]);
3310 case 'pass_deletion_allowed':
3311 $result_summary_settings = $result_summary_settings->withPassDeletionAllowed((
bool) $metadata[
"entry"]);
3313 case "usr_pass_overview_mode":
3314 $participant_functionality_settings = $participant_functionality_settings->withUsrPassOverviewMode((
int) $metadata[
"entry"]);
3316 case "question_list":
3317 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
"entry"]);
3320 case "reporting_date":
3322 if ($reporting_date !== null) {
3323 $result_summary_settings = $result_summary_settings->withReportingDate($reporting_date);
3326 case 'enable_processing_time':
3327 $test_behaviour_settings = $test_behaviour_settings->withProcessingTimeEnabled((
bool) $metadata[
'entry']);
3329 case "processing_time":
3330 $test_behaviour_settings = $test_behaviour_settings->withProcessingTime($metadata[
'entry']);
3332 case "starting_time":
3334 if ($starting_time !== null) {
3335 $access_settings = $access_settings->withStartTime($starting_time)
3336 ->withStartTimeEnabled(
true);
3341 if ($ending_time !== null) {
3342 $access_settings = $access_settings->withEndTime($ending_time)
3343 ->withStartTimeEnabled(
true);
3346 case "enable_examview":
3347 $finishing_settings = $finishing_settings->withShowAnswerOverview((
bool) $metadata[
"entry"]);
3349 case 'redirection_mode':
3350 $finishing_settings = $finishing_settings->withRedirectionMode((
int) $metadata[
'entry']);
3352 case 'redirection_url':
3353 $finishing_settings = $finishing_settings->withRedirectionUrl($metadata[
'entry']);
3355 case 'examid_in_test_pass':
3356 $test_behaviour_settings = $test_behaviour_settings->withExamIdInTestPassEnabled((
bool) $metadata[
'entry']);
3358 case 'examid_in_test_res':
3359 $result_details_settings = $result_details_settings->withShowExamIdInTestResults((
bool) $metadata[
"entry"]);
3361 case 'skill_service':
3362 $additional_settings = $additional_settings->withSkillsServiceEnabled((
bool) $metadata[
'entry']);
3364 case 'show_grading_status':
3365 $result_summary_settings = $result_summary_settings->withShowGradingStatusEnabled((
bool) $metadata[
"entry"]);
3367 case 'show_grading_mark':
3368 $result_summary_settings = $result_summary_settings->withShowGradingMarkEnabled((
bool) $metadata[
"entry"]);
3370 case 'activation_limited':
3373 case 'activation_start_time':
3376 case 'activation_end_time':
3379 case 'activation_visibility':
3383 $question_behaviour_settings = $question_behaviour_settings->withAutosaveEnabled((
bool) $metadata[
'entry']);
3385 case 'autosave_ival':
3386 $question_behaviour_settings = $question_behaviour_settings->withAutosaveInterval((
int) $metadata[
'entry']);
3388 case 'offer_question_hints':
3389 $question_behaviour_settings = $question_behaviour_settings->withQuestionHintsEnabled((
bool) $metadata[
'entry']);
3391 case 'obligations_enabled':
3392 $question_behaviour_settings = $question_behaviour_settings->withCompulsoryQuestionsEnabled((
bool) $metadata[
'entry']);
3394 case 'show_summary':
3395 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled(($metadata[
'entry'] & 1) > 0)
3396 ->withUsrPassOverviewMode((
int) $metadata[
'entry']);
3399 case 'hide_info_tab':
3400 $additional_settings = $additional_settings->withHideInfoTab($metadata[
'entry'] ===
'1');
3402 if (preg_match(
"/mark_step_\d+/", $metadata[
"label"])) {
3403 $xmlmark = $metadata[
"entry"];
3404 preg_match(
"/<short>(.*?)<\/short>/", $xmlmark, $matches);
3405 $mark_short = $matches[1];
3406 preg_match(
"/<official>(.*?)<\/official>/", $xmlmark, $matches);
3407 $mark_official = $matches[1];
3408 preg_match(
"/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
3409 $mark_percentage = (float) $matches[1];
3410 preg_match(
"/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
3411 $mark_passed = (
int) $matches[1];
3412 $this->mark_schema->addMarkStep($mark_short, $mark_official, $mark_percentage, $mark_passed);
3419 ->withTitle($assessment->
getTitle())
3423 $main_settings = $main_settings
3425 ->withIntroductionSettings($introduction_settings)
3426 ->withAccessSettings($access_settings)
3427 ->withParticipantFunctionalitySettings($participant_functionality_settings)
3428 ->withTestBehaviourSettings($test_behaviour_settings)
3429 ->withQuestionBehaviourSettings($question_behaviour_settings)
3430 ->withFinishingSettings($finishing_settings)
3431 ->withAdditionalSettings($additional_settings);
3435 $score_settings = $score_settings
3437 ->withScoringSettings($scoring_settings)
3438 ->withResultDetailsSettings($result_details_settings)
3439 ->withResultSummarySettings($result_summary_settings);
3450 $text = $material[
'text'];
3451 $mobs = $material[
'mobs'];
3452 if (str_starts_with($text,
'<PageObject>')) {
3456 $page_object->setParentId($this->
getId());
3457 $page_object->setXMLContent($text);
3458 $new_page_id = $page_object->createPageWithNextId();
3476 $text = $material[
'text'];
3477 $mobs = $material[
'mobs'];
3478 if (str_starts_with($text,
'<PageObject>')) {
3482 $page_object->setParentId($this->
getId());
3483 $page_object->setXMLContent($text);
3484 $new_page_id = $page_object->createPageWithNextId();
3505 preg_match_all(
'/il_(\d+)_mob_(\d+)/', $text, $matches);
3506 foreach ($matches[0] as $index => $match) {
3507 if (empty($mappings[$matches[2][$index]])) {
3510 $text = str_replace($match,
"il__mob_{$mappings[$matches[2][$index]]}", $text);
3518 preg_match_all(
'/il_(\d+)_file_(\d+)/', $text, $matches);
3519 foreach ($matches[0] as $index => $match) {
3520 if (empty($mappings[$matches[2][$index]])) {
3523 $text = str_replace($match,
"il__file_{$mappings[$matches[2][$index]]}", $text);
3530 foreach ($mobs as $mob) {
3532 if (file_exists($importfile)) {
3537 'src="' . $mob[
'mob'] .
'"',
3538 'src="' .
'il_' .
IL_INST_ID .
'_mob_' . $media_object->getId() .
'"',
3558 $a_xml_writer->xmlHeader();
3559 $a_xml_writer->xmlSetDtdDef(
"<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
3560 $a_xml_writer->xmlStartTag(
"questestinterop");
3566 $a_xml_writer->xmlStartTag(
"assessment", $attrs);
3568 $a_xml_writer->xmlElement(
"qticomment", null, $this->
getDescription());
3573 $a_xml_writer->xmlElement(
3577 "P0Y0M0DT%dH%dM%dS",
3578 $processing_time_array[
'hh'],
3579 $processing_time_array[
'mm'],
3580 $processing_time_array[
'ss']
3586 $a_xml_writer->xmlStartTag(
"qtimetadata");
3587 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3588 $a_xml_writer->xmlElement(
"fieldlabel", null,
"ILIAS_VERSION");
3589 $a_xml_writer->xmlElement(
"fieldentry", null,
ILIAS_VERSION);
3590 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3593 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3594 $a_xml_writer->xmlElement(
"fieldlabel", null,
"anonymity");
3595 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getGeneralSettings()->getAnonymity()));
3596 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3599 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3600 $a_xml_writer->xmlElement(
"fieldlabel", null,
"question_set_type");
3601 $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getGeneralSettings()->getQuestionSetType());
3602 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3605 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3606 $a_xml_writer->xmlElement(
"fieldlabel", null,
"sequence_settings");
3608 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3611 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3612 $a_xml_writer->xmlElement(
"fieldlabel", null,
"author");
3613 $a_xml_writer->xmlElement(
"fieldentry", null, $this->
getAuthor());
3614 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3617 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3618 $a_xml_writer->xmlElement(
"fieldlabel", null,
"reset_processing_time");
3619 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getTestBehaviourSettings()->getResetProcessingTime());
3620 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3623 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3624 $a_xml_writer->xmlElement(
"fieldlabel", null,
"count_system");
3625 $a_xml_writer->xmlElement(
"fieldentry", null, $this->
getCountSystem());
3626 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3629 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3630 $a_xml_writer->xmlElement(
"fieldlabel", null,
"score_cutting");
3631 $a_xml_writer->xmlElement(
"fieldentry", null, $this->
getScoreCutting());
3632 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3635 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3636 $a_xml_writer->xmlElement(
"fieldlabel", null,
"password");
3637 $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getAccessSettings()->getPassword() ??
'');
3638 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3641 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3642 $a_xml_writer->xmlElement(
"fieldlabel", null,
"pass_scoring");
3643 $a_xml_writer->xmlElement(
"fieldentry", null, $this->
getPassScoring());
3644 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3646 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3647 $a_xml_writer->xmlElement(
'fieldlabel', null,
'pass_deletion_allowed');
3649 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3653 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3654 $a_xml_writer->xmlElement(
"fieldlabel", null,
"reporting_date");
3655 $a_xml_writer->xmlElement(
3662 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3665 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3666 $a_xml_writer->xmlElement(
"fieldlabel", null,
"nr_of_tries");
3667 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getNumberOfTries()));
3668 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3671 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3672 $a_xml_writer->xmlElement(
'fieldlabel', null,
'block_after_passed');
3673 $a_xml_writer->xmlElement(
'fieldentry', null, (
int) $main_settings->
getTestBehaviourSettings()->getBlockAfterPassedEnabled());
3674 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3677 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3678 $a_xml_writer->xmlElement(
"fieldlabel", null,
"pass_waiting");
3680 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3683 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3684 $a_xml_writer->xmlElement(
"fieldlabel", null,
"kiosk");
3685 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getKioskMode()));
3686 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3690 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3691 $a_xml_writer->xmlElement(
"fieldlabel", null,
"redirection_mode");
3692 $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getFinishingSettings()->getRedirectionMode());
3693 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3696 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3697 $a_xml_writer->xmlElement(
"fieldlabel", null,
"redirection_url");
3698 $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getFinishingSettings()->getRedirectionUrl());
3699 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3702 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3703 $a_xml_writer->xmlElement(
"fieldlabel", null,
"use_previous_answers");
3705 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3707 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3708 $a_xml_writer->xmlElement(
'fieldlabel', null,
'question_list_enabled');
3710 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3712 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3713 $a_xml_writer->xmlElement(
"fieldlabel", null,
"title_output");
3714 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getQuestionBehaviourSettings()->getQuestionTitleOutputMode()));
3715 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3718 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3719 $a_xml_writer->xmlElement(
"fieldlabel", null,
"results_presentation");
3720 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $this->
getScoreSettings()->getResultDetailsSettings()->getResultsPresentation()));
3721 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3724 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3725 $a_xml_writer->xmlElement(
"fieldlabel", null,
"examid_in_test_pass");
3726 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getExamIdInTestPassEnabled()));
3727 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3730 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3731 $a_xml_writer->xmlElement(
"fieldlabel", null,
"examid_in_test_res");
3732 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", $this->
getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults()));
3733 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3736 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3737 $a_xml_writer->xmlElement(
"fieldlabel", null,
"usr_pass_overview_mode");
3739 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3742 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3743 $a_xml_writer->xmlElement(
"fieldlabel", null,
"score_reporting");
3745 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3747 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3748 $a_xml_writer->xmlElement(
"fieldlabel", null,
"show_solution_list_comparison");
3749 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $this->score_settings->getResultDetailsSettings()->getShowSolutionListComparison());
3750 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3753 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3754 $a_xml_writer->xmlElement(
"fieldlabel", null,
"instant_verification");
3755 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled()));
3756 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3759 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3760 $a_xml_writer->xmlElement(
"fieldlabel", null,
"answer_feedback");
3761 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled()));
3762 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3765 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3766 $a_xml_writer->xmlElement(
"fieldlabel", null,
"instant_feedback_specific");
3767 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled()));
3768 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3771 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3772 $a_xml_writer->xmlElement(
"fieldlabel", null,
"answer_feedback_points");
3773 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled()));
3774 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3777 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3778 $a_xml_writer->xmlElement(
"fieldlabel", null,
"follow_qst_answer_fixation");
3779 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled());
3780 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3783 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3784 $a_xml_writer->xmlElement(
"fieldlabel", null,
"instant_feedback_answer_fixation");
3785 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled());
3786 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3789 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3790 $a_xml_writer->xmlElement(
"fieldlabel", null,
"force_instant_feedback");
3791 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion());
3792 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3796 $highscore_metadata = [
3808 foreach ($highscore_metadata as $label =>
$data) {
3809 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3810 $a_xml_writer->xmlElement(
"fieldlabel", null, $label);
3811 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d",
$data[
'value']));
3812 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3816 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3817 $a_xml_writer->xmlElement(
"fieldlabel", null,
"suspend_test_allowed");
3819 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3822 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3823 $a_xml_writer->xmlElement(
"fieldlabel", null,
"show_marker");
3825 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3828 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3829 $a_xml_writer->xmlElement(
"fieldlabel", null,
"fixed_participants");
3830 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getAccessSettings()->getFixedParticipants()));
3831 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3834 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3835 $a_xml_writer->xmlElement(
"fieldlabel", null,
"show_introduction");
3836 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getIntroductionSettings()->getIntroductionEnabled()));
3837 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3840 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3841 $a_xml_writer->xmlElement(
"fieldlabel", null,
'exam_conditions');
3842 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getIntroductionSettings()->getExamConditionsCheckboxEnabled()));
3843 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3845 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3846 $a_xml_writer->xmlElement(
"fieldlabel", null,
"show_concluding_remarks");
3847 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getFinishingSettings()->getConcludingRemarksEnabled()));
3848 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3851 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3852 $a_xml_writer->xmlElement(
"fieldlabel", null,
"mailnotification");
3853 $a_xml_writer->xmlElement(
"fieldentry", null, $main_settings->
getFinishingSettings()->getMailNotificationContentType());
3854 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3857 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3858 $a_xml_writer->xmlElement(
"fieldlabel", null,
"mailnottype");
3859 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getFinishingSettings()->getAlwaysSendMailNotification());
3860 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3863 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3864 $a_xml_writer->xmlElement(
"fieldlabel", null,
"exportsettings");
3866 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3869 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3870 $a_xml_writer->xmlElement(
"fieldlabel", null,
"shuffle_questions");
3871 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getShuffleQuestions()));
3872 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3875 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3876 $a_xml_writer->xmlElement(
"fieldlabel", null,
"processing_time");
3878 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3881 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3882 $a_xml_writer->xmlElement(
"fieldlabel", null,
"enable_examview");
3883 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getFinishingSettings()->getShowAnswerOverview());
3884 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3888 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3889 $a_xml_writer->xmlElement(
"fieldlabel", null,
"skill_service");
3890 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getAdditionalSettings()->getSkillsServiceEnabled());
3891 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3896 "solutionswitch" =>
"Yes" 3901 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs, null);
3904 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3905 $a_xml_writer->xmlElement(
"fieldlabel", null,
"show_grading_status");
3907 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3910 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3911 $a_xml_writer->xmlElement(
"fieldlabel", null,
"show_grading_mark");
3913 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3915 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3916 $a_xml_writer->xmlElement(
'fieldlabel', null,
'hide_info_tab');
3917 $a_xml_writer->xmlElement(
'fieldentry', null, (
int) $this->
getMainSettings()->getAdditionalSettings()->getHideInfoTab());
3918 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3921 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3922 $a_xml_writer->xmlElement(
"fieldlabel", null,
"starting_time");
3923 $a_xml_writer->xmlElement(
3930 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3934 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3935 $a_xml_writer->xmlElement(
"fieldlabel", null,
"ending_time");
3936 $a_xml_writer->xmlElement(
3943 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3948 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3949 $a_xml_writer->xmlElement(
"fieldlabel", null,
"activation_limited");
3951 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3954 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3955 $a_xml_writer->xmlElement(
"fieldlabel", null,
"activation_start_time");
3957 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3960 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3961 $a_xml_writer->xmlElement(
"fieldlabel", null,
"activation_end_time");
3963 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3966 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3967 $a_xml_writer->xmlElement(
"fieldlabel", null,
"activation_visibility");
3969 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3972 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3973 $a_xml_writer->xmlElement(
"fieldlabel", null,
"autosave");
3975 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3978 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3979 $a_xml_writer->xmlElement(
"fieldlabel", null,
"autosave_ival");
3981 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3984 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3985 $a_xml_writer->xmlElement(
"fieldlabel", null,
"offer_question_hints");
3987 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3990 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3991 $a_xml_writer->xmlElement(
"fieldlabel", null,
"instant_feedback_specific");
3992 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled());
3993 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3996 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3997 $a_xml_writer->xmlElement(
"fieldlabel", null,
"instant_feedback_answer_fixation");
3998 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled());
3999 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
4002 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
4003 $a_xml_writer->xmlElement(
"fieldlabel", null,
"obligations_enabled");
4005 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
4008 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
4009 $a_xml_writer->xmlElement(
"fieldlabel", null,
"enable_processing_time");
4010 $a_xml_writer->xmlElement(
"fieldentry", null, (
int) $main_settings->
getTestBehaviourSettings()->getProcessingTimeEnabled());
4011 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
4013 foreach ($this->mark_schema->mark_steps as $index => $mark) {
4015 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
4016 $a_xml_writer->xmlElement(
"fieldlabel", null,
"mark_step_$index");
4017 $a_xml_writer->xmlElement(
"fieldentry", null, sprintf(
4018 "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
4019 $mark->getShortName(),
4020 $mark->getOfficialName(),
4021 $mark->getMinimumLevel(),
4024 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
4026 $a_xml_writer->xmlEndTag(
"qtimetadata");
4029 $introduction = $page_id !== null
4030 ? (
new ilTestPage($page_id))->getXMLContent()
4034 $a_xml_writer->xmlStartTag(
"objectives");
4036 $a_xml_writer->xmlEndTag(
"objectives");
4041 "solutionswitch" =>
"Yes" 4046 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs, null);
4050 $concluding_remarks = $page_id !== null
4051 ? (
new ilTestPage($page_id))->getXMLContent()
4054 $a_xml_writer->xmlStartTag(
"presentation_material");
4055 $a_xml_writer->xmlStartTag(
"flow_mat");
4056 $this->
addQTIMaterial($a_xml_writer, $page_id, $concluding_remarks);
4057 $a_xml_writer->xmlEndTag(
"flow_mat");
4058 $a_xml_writer->xmlEndTag(
"presentation_material");
4064 $a_xml_writer->xmlElement(
"section", $attrs, null);
4065 $a_xml_writer->xmlEndTag(
"assessment");
4066 $a_xml_writer->xmlEndTag(
"questestinterop");
4068 $xml = $a_xml_writer->xmlDumpMem(
false);
4074 return $date_time->setTimezone(
new DateTimeZone(
'UTC'))->format(
'\PY\Yn\Mj\D\TG\Hi\Ms\S');
4079 if ($period === null) {
4082 if (preg_match(
"/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $period, $matches)) {
4085 "%02d-%02d-%02d %02d:%02d:%02d",
4105 public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog): void
4107 $this->mob_ids = [];
4113 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Page Objects");
4114 $this->bench->start(
"ContentObjectExport",
"exportPageObjects");
4116 $this->bench->stop(
"ContentObjectExport",
"exportPageObjects");
4117 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Page Objects");
4120 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Media Objects");
4121 $this->bench->start(
"ContentObjectExport",
"exportMediaObjects");
4123 $this->bench->stop(
"ContentObjectExport",
"exportMediaObjects");
4124 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Media Objects");
4127 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export File Items");
4128 $this->bench->start(
"ContentObjectExport",
"exportFileItems");
4130 $this->bench->stop(
"ContentObjectExport",
"exportFileItems");
4131 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export File Items");
4143 $md2xml->setExportMode(
true);
4144 $md2xml->startExport();
4145 $a_xml_writer->appendXML($md2xml->getXML());
4155 if ($a_tag ==
"Identifier" && $a_param ==
"Entry") {
4171 foreach ($this->questions as $question_id) {
4172 $this->bench->start(
"ContentObjectExport",
"exportPageObject");
4173 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Page Object " . $question_id);
4176 $a_xml_writer->xmlStartTag(
"PageObject", $attrs);
4180 $this->bench->start(
"ContentObjectExport",
"exportPageObject_XML");
4182 $page_object->buildDom();
4183 $page_object->insertInstIntoIDs((
string) $inst);
4184 $mob_ids = $page_object->collectMediaObjects(
false);
4186 $xml = $page_object->getXMLFromDom(
false,
false,
false,
"",
true);
4187 $xml = str_replace(
"&",
"&", $xml);
4188 $a_xml_writer->appendXML($xml);
4189 $page_object->freeDom();
4190 unset($page_object);
4192 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_XML");
4195 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectMedia");
4197 foreach ($mob_ids as $mob_id) {
4198 $this->mob_ids[$mob_id] = $mob_id;
4200 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectMedia");
4203 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
4205 foreach ($file_ids as $file_id) {
4206 $this->file_ids[$file_id] = $file_id;
4208 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
4210 $a_xml_writer->xmlEndTag(
"PageObject");
4213 $this->bench->stop(
"ContentObjectExport",
"exportPageObject");
4222 foreach ($this->mob_ids as $mob_id) {
4223 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Media Object " . $mob_id);
4226 $media_obj->exportXML($a_xml_writer, (
int) $a_inst);
4227 $media_obj->exportFiles($a_target_dir);
4239 foreach ($this->file_ids as $file_id) {
4240 $expLog->write(date(
"[y-m-d H:i:s] ") .
"File Item " . $file_id);
4241 $file_dir = $target_dir .
'/objects/il_' .
IL_INST_ID .
'_file_' . $file_id;
4243 $file_obj =
new ilObjFile((
int) $file_id,
false);
4244 $source_file = $file_obj->getFile($file_obj->getVersion());
4245 if (!is_file($source_file)) {
4246 $source_file = $file_obj->getFile();
4248 if (is_file($source_file)) {
4249 copy($source_file, $file_dir .
'/' . $file_obj->getFileName());
4269 return $this->mark_schema->checkMarks();
4292 $this->
saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
4305 $results_summary_settings = $this->
getScoreSettings()->getResultSummarySettings();
4307 || $results_summary_settings->getScoreReportingEnabled() ===
false) {
4312 return $results_summary_settings->getReportingDate()
4331 $md_life = $md->getLifecycle();
4333 if (strlen($author) == 0) {
4334 $author = $this->
user->getFullname();
4337 $md_life = $md->addLifecycle();
4339 $con = $md_life->addContribute();
4340 $con->setRole(
"Author");
4342 $ent = $con->addEntity();
4343 $ent->setEntity($author);
4367 $md_life = $md->getLifecycle();
4369 $ids = $md_life->getContributeIds();
4370 foreach ($ids as
$id) {
4371 $md_cont = $md_life->getContribute($id);
4372 if (strcmp($md_cont->getRole(),
"Author") == 0) {
4373 $entids = $md_cont->getEntityIds();
4374 foreach ($entids as $entid) {
4375 $md_ent = $md_cont->getEntity($entid);
4376 array_push($author, $md_ent->getEntity());
4381 return join(
", ", $author);
4394 $md =
new ilMD($obj_id, 0,
"tst");
4395 $md_life = $md->getLifecycle();
4397 $ids = $md_life->getContributeIds();
4398 foreach ($ids as
$id) {
4399 $md_cont = $md_life->getContribute($id);
4400 if (strcmp($md_cont->getRole(),
"Author") == 0) {
4401 $entids = $md_cont->getEntityIds();
4402 foreach ($entids as $entid) {
4403 $md_ent = $md_cont->getEntity($entid);
4404 array_push($author, $md_ent->getEntity());
4409 return join(
",", $author);
4421 $ilUser = $DIC[
'ilUser'];
4424 $tests = array_slice(
4432 if (count($tests)) {
4435 if ($use_object_id) {
4437 $result_array[$obj_id] = $titles[
$ref_id];
4443 return $result_array;
4458 $new_obj = parent::cloneObject($target_id, $copy_id, $omit_tree);
4459 $new_obj->setTmpCopyWizardCopyId($copy_id);
4465 $new_obj->addToNewsOnOnline(
false, $new_obj->getObjectProperties()->getPropertyIsOnline()->getIsOnline());
4469 ->withIntroductionSettings(
4470 $this->
getMainSettings()->getIntroductionSettings()->withIntroductionPageId(
4472 )->withTestId($new_obj->getTestId())
4473 )->withFinishingSettings(
4474 $this->
getMainSettings()->getFinishingSettings()->withConcludingRemarksPageId(
4476 )->withTestId($new_obj->getTestId())
4490 $templateRepository,
4492 $this->filesystem_web,
4496 $cloneAction->cloneCertificate($this, $new_obj);
4498 $this->question_set_config_factory->getQuestionSetConfig()->cloneQuestionSetRelatedData($new_obj);
4499 $new_obj->saveQuestionsToDb();
4502 $skillLevelThresholdList->setTestId($this->
getTestId());
4503 $skillLevelThresholdList->loadFromDb();
4504 $skillLevelThresholdList->cloneListForTest($new_obj->getTestId());
4507 $obj_settings->cloneSettings($new_obj->getId());
4522 $this->component_repository,
4527 $questionSetConfig->loadFromDb();
4529 if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
4536 $sourcePoolDefinitionList->loadDefinitions();
4538 if (is_int($sourcePoolDefinitionList->getQuestionAmount())) {
4539 $num = $sourcePoolDefinitionList->getQuestionAmount();
4541 } elseif (is_int($questionSetConfig->getQuestionAmountPerTest())) {
4542 $num = $questionSetConfig->getQuestionAmountPerTest();
4546 $num = count($this->questions);
4557 return count($this->questions);
4570 if ($question_id !== 0) {
4571 $original_id = $this->questioninfo->getOriginalId($question_id);
4586 $ilDB = $DIC[
'ilDB'];
4588 $result =
$ilDB->queryF(
4589 "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
4593 if ($result->numRows()) {
4594 $row =
$ilDB->fetchAssoc($result);
4595 $object_id = $row[
"obj_fi"];
4610 $ilDB = $DIC[
'ilDB'];
4612 $result =
$ilDB->queryF(
4613 "SELECT tst_tests.obj_fi FROM tst_tests, tst_active WHERE tst_tests.test_id = tst_active.test_fi AND tst_active.active_id = %s",
4617 if ($result->numRows()) {
4618 $row =
$ilDB->fetchAssoc($result);
4619 $object_id = $row[
"obj_fi"];
4634 $ilDB = $DIC[
'ilDB'];
4636 $result =
$ilDB->queryF(
4637 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
4641 if ($result->numRows()) {
4642 $row =
$ilDB->fetchAssoc($result);
4643 $test_id = $row[
"test_id"];
4658 if (($active_id) && ($question_id)) {
4659 if ($pass === null) {
4662 if ($pass === null) {
4665 $query = $this->db->queryF(
4666 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
4667 [
'integer',
'integer',
'integer'],
4668 [$active_id, $question_id, $pass]
4670 $result = $this->db->fetchAll($query);
4671 if (count($result) == 1) {
4672 return $result[0][
"value1"];
4689 $result = $this->db->queryF(
4690 "SELECT question_text FROM qpl_questions WHERE question_id = %s",
4694 if ($result->numRows() == 1) {
4695 $row = $this->db->fetchAssoc($result);
4696 $res = $row[
"question_text"];
4706 return $participant_list;
4714 return $participant_list;
4723 public function &
getInvitedUsers(
int $user_id = 0, $order =
"login, lastname, firstname"): array
4728 if ($user_id !== 0) {
4729 $result = $this->db->queryF(
4730 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
4731 "tst_active.submitted test_finished, matriculation, COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes FROM usr_data, tst_invited_user " .
4732 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4733 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4735 [
'text',
'text',
'text',
'integer',
'integer'],
4736 [
'', $this->
lng->txt(
'anonymous'),
'', $this->
getTestId(), $user_id]
4739 $result = $this->db->queryF(
4740 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, tst_invited_user.clientip, " .
4741 "tst_active.submitted test_finished, matriculation, COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes FROM usr_data, tst_invited_user " .
4742 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4743 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4745 [
'text',
'text',
'text',
'integer'],
4746 [
'', $this->
lng->txt(
'anonymous'),
'', $this->
getTestId()]
4750 if ($user_id !== 0) {
4751 $result = $this->db->queryF(
4752 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
4753 "tst_active.submitted test_finished, matriculation, COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes FROM usr_data, tst_invited_user " .
4754 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4755 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4757 [
'integer',
'integer'],
4761 $result = $this->db->queryF(
4762 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, tst_invited_user.clientip, " .
4763 "tst_active.submitted test_finished, matriculation, COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes FROM usr_data, tst_invited_user " .
4764 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4765 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4773 while ($row = $this->db->fetchAssoc($result)) {
4774 $result_array[$row[
'usr_id']] = $row;
4776 return $result_array;
4783 SELECT tst_active.active_id, 4785 tst_active.user_fi usr_id, 4789 tst_active.submitted test_finished, 4790 usr_data.matriculation, 4792 tst_active.lastindex, 4793 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes 4796 ON tst_active.user_fi = usr_data.usr_id 4797 WHERE tst_active.test_fi = %s 4798 ORDER BY usr_data.lastname 4800 $result = $this->db->queryF(
4802 [
'text',
'text',
'text',
'integer'],
4803 [
'', $this->
lng->txt(
"anonymous"),
"", $this->
getTestId()]
4807 SELECT tst_active.active_id, 4809 tst_active.user_fi usr_id, 4813 tst_active.submitted test_finished, 4814 usr_data.matriculation, 4816 tst_active.lastindex, 4817 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes 4820 ON tst_active.user_fi = usr_data.usr_id 4821 WHERE tst_active.test_fi = %s 4822 ORDER BY usr_data.lastname 4824 $result = $this->db->queryF(
4831 while ($row = $this->db->fetchAssoc($result)) {
4832 $data[$row[
'active_id']] = $row;
4834 foreach (
$data as $index => $participant) {
4835 if (strlen(trim($participant[
"firstname"] . $participant[
"lastname"])) == 0) {
4836 $data[$index][
"lastname"] = $this->
lng->txt(
"deleted_user");
4845 if (count($scoring) == 0) {
4850 $filtered_participants = [];
4851 foreach ($participants as $active_id => $participant) {
4852 if ($participant[
'tries'] > 0) {
4855 if ($this->testManScoringDoneHelper->isDone((
int) $active_id)) {
4856 $filtered_participants[$active_id] = $participant;
4860 if (!$this->testManScoringDoneHelper->isDone((
int) $active_id)) {
4861 $filtered_participants[$active_id] = $participant;
4865 $filtered_participants[$active_id] = $participant;
4869 return $filtered_participants;
4880 if (!is_array($ids) || count($ids) == 0) {
4885 $result = $this->db->queryF(
4886 "SELECT usr_id, %s login, %s lastname, %s firstname, client_ip clientip FROM usr_data WHERE " . $this->db->in(
'usr_id', $ids,
false,
'integer') .
" ORDER BY login",
4887 [
'text',
'text',
'text'],
4888 [
"", $this->
lng->txt(
"anonymous"),
""]
4891 $result = $this->db->query(
"SELECT usr_id, login, lastname, firstname, client_ip clientip FROM usr_data WHERE " . $this->db->in(
'usr_id', $ids,
false,
'integer') .
" ORDER BY login");
4895 while ($row = $this->db->fetchAssoc($result)) {
4896 $result_array[$row[
"usr_id"]] = $row;
4898 return $result_array;
4903 if (!is_array($ids) || count($ids) == 0) {
4916 if (!is_array($ids) || count($ids) == 0) {
4920 foreach ($ids as $obj_id) {
4936 $members = $group->getGroupMemberIds();
4937 foreach ($members as $user_id) {
4950 $members = $this->rbac_review->assignedUsers($role_id);
4951 foreach ($members as $user_id) {
4966 $affectedRows = $this->db->manipulateF(
4967 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
4968 [
'integer',
'integer'],
4981 $this->db->manipulateF(
4982 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
4983 [
'integer',
'integer'],
4986 $this->db->manipulateF(
4987 "INSERT INTO tst_invited_user (test_fi, user_fi, clientip, tstamp) VALUES (%s, %s, %s, %s)",
4988 [
'integer',
'integer',
'text',
'integer'],
4989 [$this->
getTestId(), $user_id, (strlen($client_ip)) ? $client_ip : null, time()]
4996 $this->db->manipulateF(
4997 "UPDATE tst_invited_user SET clientip = %s, tstamp = %s WHERE test_fi=%s and user_fi=%s",
4998 [
'text',
'integer',
'integer',
'integer'],
4999 [(strlen($client_ip)) ? $client_ip : null, time(), $this->
getTestId(), $user_id]
5011 $ilDB = $DIC[
'ilDB'];
5012 if (is_numeric($question_fi)) {
5013 $result =
$ilDB->queryF(
5014 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
5015 [
'integer',
'integer'],
5016 [$active_id, $question_fi]
5019 $result =
$ilDB->queryF(
5020 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
5026 while ($row =
$ilDB->fetchAssoc($result)) {
5027 $result_array[$row[
"question_fi"]] = $row;
5029 return $result_array;
5039 $this->db->manipulateF(
5040 "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
5041 [
'integer',
'integer'],
5042 [$active_id, $question_id]
5044 $this->db->manipulateF(
5045 "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
5046 [
'integer',
'integer',
'integer'],
5047 [$value, $question_id, $active_id]
5056 $result = $this->db->queryF(
5057 "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
5058 [
'integer',
'integer'],
5061 return $result->numRows() == 1;
5069 if (!is_numeric($user_id)) {
5070 $user_id = $this->
user->getId();
5073 $result = $this->db->queryF(
5074 "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
5075 [
'integer',
'integer',
'integer'],
5078 return $result->numRows() == 1;
5113 "user_id" => $this->
lng->txt(
"user_id"),
5114 "matriculation" => $this->
lng->txt(
"matriculation"),
5115 "lastname" => $this->
lng->txt(
"lastname"),
5116 "firstname" => $this->
lng->txt(
"firstname"),
5117 "login" => $this->
lng->txt(
"login"),
5118 "reached_points" => $this->
lng->txt(
"tst_reached_points"),
5119 "max_points" => $this->
lng->txt(
"tst_maximum_points"),
5120 "percent_value" => $this->
lng->txt(
"tst_percent_solved"),
5121 "mark" => $this->
lng->txt(
"tst_mark"),
5122 "passed" => $this->
lng->txt(
"tst_mark_passed"),
5125 if (count($participants)) {
5126 foreach ($participants as $active_id => $user_rec) {
5129 $reached_points = 0;
5133 if (!is_int($pass)) {
5136 foreach ($this->questions as $value) {
5138 if (is_object($question)) {
5139 $max_points += $question->getMaximumPoints();
5140 $reached_points += $question->getReachedPoints($active_id, $pass);
5143 if ($max_points > 0) {
5144 $percentvalue = $reached_points / $max_points;
5145 if ($percentvalue < 0) {
5146 $percentvalue = 0.0;
5151 $mark_obj = $this->mark_schema->getMatchingMark($percentvalue * 100);
5154 $mark = $mark_obj->getOfficialName();
5157 $user_rec[
'firstname'] =
"";
5158 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
5161 "user_id" => $user_rec[
'usr_id'],
5162 "matriculation" => $user_rec[
'matriculation'],
5163 "lastname" => $user_rec[
'lastname'],
5164 "firstname" => $user_rec[
'firstname'],
5165 "login" => $user_rec[
'login'],
5166 "reached_points" => $reached_points,
5167 "max_points" => $max_points,
5168 "percent_value" => $percentvalue,
5170 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
5190 bool $quote_all =
false,
5191 string $separator =
";" 5194 foreach ($row as $rowindex => $entry) {
5199 if (is_string($entry) && strpos($entry,
"\"") !==
false) {
5200 $entry = str_replace(
"\"",
"\"\"", $entry);
5203 if (is_string($entry) && strpos($entry, $separator) !==
false) {
5207 if (is_string($entry)) {
5209 $entry = str_replace(chr(13) . chr(10), chr(10), $entry);
5213 $entry =
"\"" . $entry .
"\"";
5216 $resultarray[$rowindex] = $entry;
5218 return $resultarray;
5232 $ilDB = $DIC[
'ilDB'];
5233 $result =
$ilDB->queryF(
5234 "SELECT tries FROM tst_active WHERE active_id = %s",
5238 if ($result->numRows()) {
5239 $row =
$ilDB->fetchAssoc($result);
5240 return $row[
"tries"];
5258 $ilDB = $DIC[
'ilDB'];
5259 $result =
$ilDB->queryF(
5260 "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
5265 if ($result->numRows()) {
5266 $row =
$ilDB->fetchAssoc($result);
5267 return $row[
"maxpass"];
5281 $ilDB = $DIC[
'ilDB'];
5283 $result =
$ilDB->queryF(
5284 "SELECT * FROM tst_pass_result WHERE active_fi = %s",
5289 if (!$result->numRows()) {
5295 while ($row =
$ilDB->fetchAssoc($result)) {
5296 if ($row[
"maxpoints"] > 0.0) {
5297 $factor = (float) ($row[
"points"] / $row[
"maxpoints"]);
5301 if ($factor === 0.0 && $bestfactor === 0.0
5302 || $factor > $bestfactor) {
5304 $bestfactor = $factor;
5308 if (is_array($bestrow)) {
5309 return $bestrow[
"pass"];
5325 $counted_pass = null;
5331 return $counted_pass;
5349 foreach ($this->questions as $value) {
5350 if ($this->questioninfo->lookupResultRecordExist($active_id, $value, $pass)) {
5351 $workedthrough += 1;
5354 return $workedthrough;
5366 $ilDB = $DIC[
'ilDB'];
5368 if (is_null($pass)) {
5373 SELECT tst_pass_result.tstamp pass_res_tstamp, 5374 tst_test_result.tstamp quest_res_tstamp 5376 FROM tst_pass_result 5378 LEFT JOIN tst_test_result 5379 ON tst_test_result.active_fi = tst_pass_result.active_fi 5380 AND tst_test_result.pass = tst_pass_result.pass 5382 WHERE tst_pass_result.active_fi = %s 5383 AND tst_pass_result.pass = %s 5385 ORDER BY tst_test_result.tstamp DESC 5388 $result =
$ilDB->queryF(
5390 [
'integer',
'integer'],
5394 while ($row =
$ilDB->fetchAssoc($result)) {
5395 if ($row[
'quest_res_tstamp']) {
5396 return $row[
'quest_res_tstamp'];
5399 return $row[
'pass_res_tstamp'];
5413 public function isExecutable($test_session, $user_id, $allow_pass_increase =
false): array
5416 "executable" =>
true,
5417 "errormessage" =>
"" 5421 $result[
"executable"] =
false;
5422 $result[
"errormessage"] = $this->
lng->txt(
'autosave_failed') .
': ' . $this->
lng->txt(
'offline');
5427 $result[
"executable"] =
false;
5432 $result[
"executable"] =
false;
5443 $result[
"executable"] =
false;
5444 $result[
"errormessage"] = $this->
lng->txt(
"detail_max_processing_time_reached");
5449 $testPassesSelector->setActiveId($active_id);
5450 $testPassesSelector->setLastFinishedPass($test_session->getLastFinishedPass());
5453 $closedPasses = $testPassesSelector->getClosedPasses();
5456 $result[
"executable"] =
false;
5457 $result[
"errormessage"] = $this->
lng->txt(
"maximum_nr_of_tries_reached");
5463 $result[
'executable'] =
false;
5464 $result[
'errormessage'] = $this->
lng->txt(
"tst_addit_passes_blocked_after_passed_msg");
5470 $next_pass_allowed_timestamp = 0;
5471 if (!$this->
isNextPassAllowed($testPassesSelector, $next_pass_allowed_timestamp)) {
5474 $result[
'executable'] =
false;
5475 $result[
'errormessage'] = sprintf($this->
lng->txt(
'wait_for_next_pass_hint_msg'), $date);
5483 $waiting_between_passes = $this->
getMainSettings()->getTestBehaviourSettings()->getPassWaiting();
5487 $this->
getMainSettings()->getTestBehaviourSettings()->getPassWaitingEnabled()
5488 && ($waiting_between_passes !==
'')
5490 && ($last_finished_pass_timestamp !== null)
5492 $time_values = explode(
':', $waiting_between_passes);
5493 $next_pass_allowed_timestamp = strtotime(
'+ ' . $time_values[0] .
' Days + ' . $time_values[1] .
' Hours' . $time_values[2] .
' Minutes', $last_finished_pass_timestamp);
5494 return (time() > $next_pass_allowed_timestamp);
5504 $passSelector->setActiveId($test_session->
getActiveId());
5507 return $passSelector->hasReportablePasses();
5514 $passSelector->setActiveId($test_session->
getActiveId());
5517 return $passSelector->hasExistingPasses();
5529 if ($active_id < 1) {
5532 if ($pass === null) {
5535 $result = $this->db->queryF(
5536 "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
5537 [
'integer',
'integer'],
5540 if ($result->numRows()) {
5541 $row = $this->db->fetchAssoc($result);
5542 if (preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches)) {
5573 if ($now > ($starting_time + $processing_time)) {
5582 $tags_trafo = $this->
refinery->string()->stripTags();
5586 questtypes.type_tag, 5588 tstquest.obligatory, 5589 origquest.obj_fi orig_obj_fi 5591 FROM qpl_questions questions 5593 INNER JOIN qpl_qst_type questtypes 5594 ON questtypes.question_type_id = questions.question_type_fi 5596 INNER JOIN tst_test_question tstquest 5597 ON tstquest.question_fi = questions.question_id 5599 LEFT JOIN qpl_questions origquest 5600 ON origquest.question_id = questions.original_id 5602 WHERE tstquest.test_fi = %s 5604 ORDER BY tstquest.sequence 5607 $query_result = $this->db->queryF(
5615 while ($row = $this->db->fetchAssoc($query_result)) {
5616 $row[
'title'] = $tags_trafo->transform($row[
'title']);
5617 $row[
'description'] = $tags_trafo->transform($row[
'description'] !==
'' && $row[
'description'] !== null ? $row[
'description'] :
' ');
5618 $row[
'author'] = $tags_trafo->transform($row[
'author']);
5619 $row[
'obligationPossible'] = self::isQuestionObligationPossible($row[
'question_id']);
5621 $questions[] = $row;
5634 if ($questionData[
'question_id'] != $questionId) {
5646 $row = $this->db->fetchAssoc($this->db->queryF(
5647 "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
5648 [
'integer',
'integer'],
5649 [$questionId, $this->getId()]
5652 return (
bool) $row[
'cnt'];
5660 $points += $question_data[
'points'];
5673 questtypes.type_tag, 5674 origquest.obj_fi orig_obj_fi 5676 FROM qpl_questions questions 5678 INNER JOIN qpl_qst_type questtypes 5679 ON questtypes.question_type_id = questions.question_type_fi 5681 INNER JOIN tst_rnd_cpy tstquest 5682 ON tstquest.qst_fi = questions.question_id 5684 LEFT JOIN qpl_questions origquest 5685 ON origquest.question_id = questions.original_id 5687 WHERE tstquest.tst_fi = %s 5690 $query_result = $this->db->queryF(
5698 while ($row = $this->db->fetchAssoc($query_result)) {
5701 $question[
'obligationPossible'] = self::isQuestionObligationPossible($row[
'question_id']);
5703 $questions[] = $question;
5711 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getShuffleQuestions();
5727 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewMode();
5732 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getQuestionListEnabled();
5737 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewEnabled();
5742 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtBeginning();
5747 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtEnd();
5752 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShowDescriptionInQuestionList();
5760 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowPassDetails();
5768 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionPrintview();
5783 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionFeedback();
5791 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionAnswersOnly();
5799 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionSignature();
5807 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionSuggested();
5816 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionListComparison();
5821 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionListOwnAnswers();
5830 $ilDB = $DIC[
'ilDB'];
5831 $result =
$ilDB->queryF(
5832 "SELECT user_fi FROM tst_active WHERE active_id = %s",
5836 if ($result->numRows()) {
5837 $row =
$ilDB->fetchAssoc($result);
5838 return $row[
"user_fi"];
5846 $result = $this->db->queryF(
5847 "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
5851 if ($result->numRows()) {
5852 $row = $this->db->fetchAssoc($result);
5853 return $row[
"finished"];
5858 public static function lookupLastTestPassAccess(
int $active_id,
int $pass_index): ?
int 5862 $ilDB = $DIC[
'ilDB'];
5865 SELECT MAX(tst_times.tstamp) as last_pass_access 5867 WHERE active_fi = %s 5873 [
'integer',
'integer'],
5874 [$active_id, $pass_index]
5877 while ($row =
$ilDB->fetchAssoc(
$res)) {
5878 return $row[
'last_pass_access'];
5893 if (preg_match(
"/<[^>]*?>/", $a_text)) {
5910 for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
5911 $material = $a_material->getMaterial($i);
5912 if ($material[
'type'] ===
'mattext') {
5913 $result .= $material[
'material']->getContent();
5915 if ($material[
'type'] ===
'matimage') {
5916 $matimage = $material[
'material'];
5917 if (preg_match(
'/(il_([0-9]+)_mob_([0-9]+))/', $matimage->getLabel(), $matches)) {
5919 'mob' => $matimage->getLabel(),
5920 'uri' => $matimage->getUri()
5926 $decoded_result = base64_decode($result);
5927 if (str_starts_with($decoded_result,
'<PageObject>')) {
5928 $result = $decoded_result;
5931 $this->log->write(print_r(
ilSession::get(
'import_mob_xhtml'),
true));
5942 'texttype' =>
'text/plain' 5946 if ($page_id !== null) {
5947 $attrs[
'texttype'] =
'text/xml';
5950 $page_object->buildDom();
5951 $page_object->insertInstIntoIDs((
string)
IL_INST_ID);
5952 $material = base64_encode($page_object->getXMLFromDom());
5954 foreach ($file_ids as $file_id) {
5955 $this->file_ids[] = (
int) $file_id;
5957 $mob_string =
'il_' . IL_INST_ID .
'_mob_';
5958 } elseif ($this->
isHTML($material)) {
5959 $attrs[
'texttype'] =
'text/xhtml';
5961 $mob_string =
'mm_';
5964 $xml_writer->
xmlElement(
'mattext', $attrs, $material);
5965 foreach ($mobs as $mob) {
5966 $mob_id_string = (string) $mob;
5967 $moblabel =
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string;
5968 if (strpos($material, $mob_string . $mob_id_string) !==
false) {
5972 'label' => $moblabel,
5973 'uri' =>
'objects/' .
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string .
'/' . $mob_obj->getTitle()
5976 $xml_writer->
xmlElement(
'matimage', $imgattrs, null);
5990 if ($txt_output == null) {
5995 $prepare_for_latex_output,
5996 $omitNl2BrWhenTextArea
6002 return $this->
getMainSettings()->getGeneralSettings()->getAnonymity();
6009 $ilDB = $DIC[
'ilDB'];
6011 $result =
$ilDB->queryF(
6012 "SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
6016 while ($row =
$ilDB->fetchAssoc($result)) {
6017 return (
int) $row[
'anonymity'];
6024 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getSuspendTestAllowed();
6029 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getQuestionMarkingEnabled();
6034 return $this->
getMainSettings()->getAccessSettings()->getFixedParticipants();
6046 $ilDB = $DIC[
'ilDB'];
6049 SELECT tst_tests.question_set_type 6051 INNER JOIN tst_tests 6052 ON tst_active.test_fi = tst_tests.test_id 6053 WHERE tst_active.active_id = %s 6056 $res =
$ilDB->queryF($query, [
'integer'], [$active_id]);
6058 while ($row =
$ilDB->fetchAssoc(
$res)) {
6059 return $row[
'question_set_type'];
6075 public function userLookupFullName($user_id, $overwrite_anonymity =
false, $sorted_order =
false, $suffix =
""): string
6078 return $this->
lng->txt(
"anonymous") . $suffix;
6081 if (strlen($uname[
"firstname"] . $uname[
"lastname"]) == 0) {
6082 $uname[
"firstname"] = $this->
lng->txt(
"deleted_user");
6084 if ($sorted_order) {
6085 return trim($uname[
"lastname"] .
", " . $uname[
"firstname"]) . $suffix;
6087 return trim($uname[
"firstname"] .
" " . $uname[
"lastname"]) . $suffix;
6099 $result = $this->db->queryF(
6100 "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
6102 [$this->
user->getId()]
6105 while ($row = $this->db->fetchAssoc($result)) {
6106 $defaults[$row[
"test_defaults_id"]] = $row;
6113 $result = $this->db->queryF(
6114 "SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
6118 if ($result->numRows() == 1) {
6119 $row = $this->db->fetchAssoc($result);
6128 $this->db->manipulateF(
6129 "DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
6198 'mailnotification' => $main_settings->
getFinishingSettings()->getMailNotificationContentType(),
6231 $next_id = $this->db->nextId(
'tst_test_defaults');
6233 'tst_test_defaults',
6235 'test_defaults_id' => [
'integer', $next_id],
6236 'name' => [
'text', $a_name],
6237 'user_fi' => [
'integer', $this->
user->getId()],
6238 'defaults' => [
'clob', serialize($testsettings)],
6239 'marks' => [
'clob', serialize($this->mark_schema->getMarkSteps())],
6240 'tstamp' => [
'integer', time()]
6254 $testsettings = unserialize($test_defaults[
'defaults']);
6255 $activation_starting_time = is_numeric($testsettings[
'activation_starting_time'] ??
false)
6256 ? (
int) $testsettings[
'activation_starting_time']
6258 $activation_ending_time = is_numeric($testsettings[
'activation_ending_time'] ??
false)
6259 ? (
int) $testsettings[
'activation_ending_time']
6261 $unserialized_marks = unserialize($test_defaults[
'marks']);
6264 $unserialized_marks = $unserialized_marks->getMarkSteps();
6267 $this->mark_schema->setMarkSteps($unserialized_marks);
6270 (
bool) ($testsettings[
'is_activation_limited'] ??
false),
6271 $activation_starting_time,
6272 $activation_ending_time,
6273 (
bool) ($testsettings[
'activation_visibility'] ??
false),
6279 ->withAnonymity((
bool) $testsettings[
'Anonymity']);
6280 if (isset($testsettings[
'questionSetType'])) {
6281 $general_settings = $general_settings->withQuestionSetType($testsettings[
'questionSetType']);
6284 $main_settings = $main_settings
6286 ->withIntroductionSettings(
6288 ->withIntroductionEnabled((
bool) $testsettings[
'IntroEnabled'])
6289 ->withExamConditionsCheckboxEnabled((
bool) ($testsettings[
'ExamConditionsCheckboxEnabled'] ??
false))
6291 ->withAccessSettings(
6293 ->withStartTimeEnabled((
bool) $testsettings[
'StartingTimeEnabled'])
6295 ->withEndTimeEnabled((
bool) $testsettings[
'EndingTimeEnabled'])
6297 ->withPasswordEnabled((
bool) $testsettings[
'password_enabled'])
6298 ->withPassword($testsettings[
'password'])
6299 ->withFixedParticipants((
bool) $testsettings[
'fixed_participants'])
6301 ->withTestBehaviourSettings(
6303 ->withNumberOfTries((
int) $testsettings[
'NrOfTries'])
6304 ->withBlockAfterPassedEnabled((
bool) $testsettings[
'BlockAfterPassed'])
6305 ->withPassWaiting($testsettings[
'pass_waiting'])
6306 ->withKioskMode($testsettings[
'Kiosk'])
6307 ->withProcessingTimeEnabled((
bool) $testsettings[
'EnableProcessingTime'])
6308 ->withProcessingTime($testsettings[
'ProcessingTime'])
6309 ->withResetProcessingTime((
bool) $testsettings[
'ResetProcessingTime'])
6310 ->withExamIdInTestPassEnabled((
bool) ($testsettings[
'examid_in_test_pass'] ?? 0))
6312 ->withQuestionBehaviourSettings(
6314 ->withQuestionTitleOutputMode($testsettings[
'TitleOutput'])
6315 ->withAutosaveEnabled((
bool) $testsettings[
'autosave'])
6316 ->withAutosaveInterval($testsettings[
'autosave_ival'])
6317 ->withShuffleQuestions((
bool) $testsettings[
'Shuffle'])
6318 ->withQuestionHintsEnabled((
bool) $testsettings[
'offer_question_hints'])
6319 ->withInstantFeedbackPointsEnabled((
bool) $testsettings[
'AnswerFeedbackPoints'])
6320 ->withInstantFeedbackGenericEnabled((
bool) $testsettings[
'AnswerFeedback'])
6321 ->withInstantFeedbackSpecificEnabled((
bool) $testsettings[
'SpecificAnswerFeedback'])
6322 ->withInstantFeedbackSolutionEnabled((
bool) $testsettings[
'InstantFeedbackSolution'])
6323 ->withForceInstantFeedbackOnNextQuestion((
bool) $testsettings[
'force_inst_fb'])
6324 ->withLockAnswerOnInstantFeedbackEnabled((
bool) $testsettings[
'inst_fb_answer_fixation'])
6325 ->withLockAnswerOnNextQuestionEnabled((
bool) $testsettings[
'follow_qst_answer_fixation'])
6326 ->withCompulsoryQuestionsEnabled((
bool) $testsettings[
'obligations_enabled'])
6328 ->withParticipantFunctionalitySettings(
6330 ->withUsePreviousAnswerAllowed((
bool) $testsettings[
'use_previous_answers'])
6331 ->withSuspendTestAllowed((
bool) $testsettings[
'ShowCancel'])
6332 ->withPostponedQuestionsMoveToEnd((
bool) $testsettings[
'SequenceSettings'])
6333 ->withUsrPassOverviewMode((
int) $testsettings[
'ListOfQuestionsSettings'])
6334 ->withQuestionMarkingEnabled((
bool) $testsettings[
'ShowMarker'])
6336 ->withFinishingSettings(
6338 ->withShowAnswerOverview((
bool) $testsettings[
'enable_examview'])
6339 ->withConcludingRemarksEnabled((
bool) $testsettings[
'ShowFinalStatement'])
6340 ->withRedirectionMode((
int) $testsettings[
'redirection_mode'])
6341 ->withRedirectionUrl($testsettings[
'redirection_url'])
6342 ->withMailNotificationContentType((
int) $testsettings[
'mailnotification'])
6343 ->withAlwaysSendMailNotification((
bool) $testsettings[
'mailnottype'])
6345 ->withAdditionalSettings(
6347 ->withSkillsServiceEnabled((
bool) $testsettings[
'skill_service'])
6348 ->withHideInfoTab((
bool) ($testsettings[
'HideInfoTab'] ??
false))
6353 $reporting_date = $testsettings[
'ReportingDate'];
6354 if (is_string($reporting_date)) {
6359 $score_settings = $score_settings
6362 ->withPassScoring($testsettings[
'PassScoring'])
6363 ->withScoreCutting($testsettings[
'ScoreCutting'])
6364 ->withCountSystem($testsettings[
'CountSystem'])
6366 ->withResultSummarySettings(
6368 ->withPassDeletionAllowed((
bool) $testsettings[
'pass_deletion_allowed'])
6369 ->withShowGradingStatusEnabled((
bool) $testsettings[
'show_grading_status'])
6370 ->withShowGradingMarkEnabled((
bool) $testsettings[
'show_grading_mark'])
6371 ->withScoreReporting((
int) $testsettings[
'ScoreReporting'])
6372 ->withReportingDate($reporting_date)
6374 ->withResultDetailsSettings(
6376 ->withResultsPresentation((
int) $testsettings[
'ResultsPresentation'])
6377 ->withShowSolutionListComparison((
bool) ($testsettings[
'show_solution_list_comparison'] ?? 0))
6378 ->withShowExamIdInTestResults((
bool) $testsettings[
'examid_in_test_res'])
6380 ->withGamificationSettings(
6382 ->withHighscoreEnabled((
bool) $testsettings[
'highscore_enabled'])
6383 ->withHighscoreAnon((
bool) $testsettings[
'highscore_anon'])
6384 ->withHighscoreAchievedTS($testsettings[
'highscore_achieved_ts'])
6385 ->withHighscoreScore((
bool) $testsettings[
'highscore_score'])
6386 ->withHighscorePercentage($testsettings[
'highscore_percentage'])
6387 ->withHighscoreHints((
bool) $testsettings[
'highscore_hints'])
6388 ->withHighscoreWTime((
bool) $testsettings[
'highscore_wtime'])
6389 ->withHighscoreOwnTable((
bool) $testsettings[
'highscore_own_table'])
6390 ->withHighscoreTopTable((
bool) $testsettings[
'highscore_top_table'])
6391 ->withHighscoreTopNum($testsettings[
'highscore_top_num'])
6407 return DateTimeImmutable::createFromFormat(
'U', (
string) $date_time);
6419 if (extension_loaded(
"tidy")) {
6422 "output-xml" =>
true,
6423 "numeric-entities" => true
6426 $tidy->parseString($print_output, $config,
'utf8');
6427 $tidy->cleanRepair();
6428 $print_output = tidy_get_output($tidy);
6429 $print_output = preg_replace(
"/^.*?(<html)/",
"\\1", $print_output);
6431 $print_output = str_replace(
" ",
" ", $print_output);
6432 $print_output = str_replace(
"⊗",
"X", $print_output);
6434 $xsl = file_get_contents(
"./Modules/Test/xml/question2fo.xsl");
6439 'font-family="Helvetica, unifont"',
6440 'font-family="' . $this->
settings->get(
'rpc_pdf_font',
'Helvetica, unifont') .
'"',
6444 $args = [
'/_xml' => $print_output,
'/_xsl' => $xsl ];
6447 $output = xslt_process($xh,
"arg:/_xml",
"arg:/_xsl", null, $args,
$params);
6461 $content = preg_replace(
"/href=\".*?\"/",
"", $content);
6462 $printbody =
new ilTemplate(
"tpl.il_as_tst_print_body.html",
true,
true,
"Modules/Test");
6464 $printbody->setVariable(
"ADM_CONTENT", $content);
6465 $printbody->setCurrentBlock(
"css_file");
6467 $printbody->parseCurrentBlock();
6468 $printoutput = $printbody->get();
6469 $html = str_replace(
"href=\"./",
"href=\"" . ILIAS_HTTP_PATH .
"/", $printoutput);
6470 $html = preg_replace(
"/<div id=\"dontprint\">.*?<\\/div>/ims",
"", $html);
6471 if (extension_loaded(
"tidy")) {
6474 "output-xml" =>
true,
6475 "numeric-entities" => true
6478 $tidy->parseString($html, $config,
'utf8');
6479 $tidy->cleanRepair();
6480 $html = tidy_get_output($tidy);
6481 $html = preg_replace(
"/^.*?(<html)/",
"\\1", $html);
6483 $html = str_replace(
" ",
" ", $html);
6484 $html = str_replace(
"⊗",
"X", $html);
6486 $html = preg_replace(
"/src=\".\\//ims",
"src=\"" . ILIAS_HTTP_PATH .
"/", $html);
6498 $fp = fopen($fo_file,
"w");
6507 $pdf_base64->scalar,
6513 $this->log->write(__METHOD__ .
': ' . $e->getMessage());
6529 if ($pass === null) {
6533 $row = self::getSingleManualFeedback((
int) $active_id, (
int) $question_id, (
int) $pass);
6536 $feedback = $row[
'feedback'] ??
'';
6545 $ilDB = $DIC[
'ilDB'];
6547 $result =
$ilDB->queryF(
6548 "SELECT * FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
6549 [
'integer',
'integer',
'integer'],
6550 [$active_id, $question_id, $pass]
6553 if (
$ilDB->numRows($result) === 1) {
6554 $row =
$ilDB->fetchAssoc($result);
6556 } elseif (
$ilDB->numRows($result) > 1) {
6557 $DIC->logger()->root()->warning(
6558 "WARNING: Multiple feedback entries on tst_manual_fb for " .
6559 "active_fi = $active_id , question_fi = $question_id and pass = $pass" 6576 $ilDB = $DIC[
'ilDB'];
6579 $result =
$ilDB->queryF(
6580 "SELECT * FROM tst_manual_fb WHERE question_fi = %s",
6585 while ($row =
$ilDB->fetchAssoc($result)) {
6586 $active = $row[
'active_fi'];
6587 $pass = $row[
'pass'];
6588 $question = $row[
'question_fi'];
6592 $feedback[$active][$pass][$question] = $row;
6603 bool $finalized =
false,
6604 bool $is_single_feedback =
false 6606 $feedback_old = self::getSingleManualFeedback($active_id, $question_id, $pass);
6608 $finalized_record = (
int) ($feedback_old[
'finalized_evaluation'] ?? 0);
6609 if ($finalized_record === 0 || ($is_single_feedback && $finalized_record === 1)) {
6610 $this->db->manipulateF(
6611 "DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
6612 [
'integer',
'integer',
'integer'],
6613 [$active_id, $question_id, $pass]
6616 $this->
insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old);
6634 $next_id = $this->db->nextId(
'tst_manual_fb');
6636 $finalized_time = time();
6639 'manual_feedback_id' => [
'integer', $next_id],
6640 'active_fi' => [
'integer', $active_id],
6641 'question_fi' => [
'integer', $question_id],
6642 'pass' => [
'integer', $pass],
6644 'tstamp' => [
'integer', time()]
6647 if ($feedback_old !== [] && (
int) $feedback_old[
'finalized_evaluation'] === 1) {
6648 $user = $feedback_old[
'finalized_by_usr_id'];
6649 $finalized_time = $feedback_old[
'finalized_tstamp'];
6652 if ($finalized ===
false) {
6653 $update_default[
'finalized_evaluation'] = [
'integer', 0];
6654 $update_default[
'finalized_by_usr_id'] = [
'integer', 0];
6655 $update_default[
'finalized_tstamp'] = [
'integer', 0];
6656 } elseif ($finalized ===
true) {
6657 $update_default[
'finalized_evaluation'] = [
'integer', 1];
6658 $update_default[
'finalized_by_usr_id'] = [
'integer',
$user];
6659 $update_default[
'finalized_tstamp'] = [
'integer', $finalized_time];
6662 $this->db->insert(
'tst_manual_fb', $update_default);
6679 $this->
user->getFullname() .
' (' . $this->
user->getLogin() .
')',
6681 $this->questioninfo->getQuestionTitle($question_id),
6711 $this->test_id = $a_id;
6725 if (count($participants)) {
6726 foreach ($participants as $active_id => $user_rec) {
6728 $reached_points = 0;
6731 foreach ($this->questions as $value) {
6733 if (is_object($question)) {
6734 $max_points += $question->getMaximumPoints();
6735 $reached_points += $question->getReachedPoints($active_id, $pass);
6736 if ($max_points > 0) {
6737 $percentvalue = $reached_points / $max_points;
6738 if ($percentvalue < 0) {
6739 $percentvalue = 0.0;
6745 $user_rec[
'firstname'] =
"";
6746 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
6749 "user_id" => $user_rec[
'usr_id'],
6750 "matriculation" => $user_rec[
'matriculation'],
6751 "lastname" => $user_rec[
'lastname'],
6752 "firstname" => $user_rec[
'firstname'],
6753 "login" => $user_rec[
'login'],
6754 "question_id" => $question->getId(),
6755 "question_title" => $question->getTitle(),
6756 "reached_points" => $reached_points,
6757 "max_points" => $max_points,
6758 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
6774 $ilDB = $DIC[
'ilDB'];
6776 $result =
$ilDB->queryF(
6777 'SELECT t.obj_fi obj_id FROM tst_test_question q, tst_tests t WHERE q.test_fi = t.test_id AND q.question_fi = %s',
6781 $rec =
$ilDB->fetchAssoc($result);
6782 return $rec[
'obj_id'] ?? null;
6793 if (!$this->component_repository->getComponentByTypeAndName(
6796 )->getPluginSlotById(
'qst')->hasPluginName($a_pname)) {
6800 return $this->component_repository
6801 ->getComponentByTypeAndName(
6805 ->getPluginSlotById(
6815 $result = $this->db->queryF(
6816 "SELECT passed FROM tst_result_cache WHERE active_fi = %s",
6820 if ($result->numRows()) {
6821 $row = $this->db->fetchAssoc($result);
6822 return $row[
'passed'];
6825 $result_array = &$this->
getTestResult($active_id, $counted_pass);
6826 return $result_array[
"test"][
"passed"];
6836 SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass 6837 FROM tst_test_result 6838 INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s 6839 INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi 6840 LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi 6841 WHERE tst_test_result.question_fi = %s 6842 ORDER BY usr_data.lastname ASC, usr_data.firstname ASC 6845 $result = $this->db->queryF(
6847 [
'integer',
'integer'],
6848 [$test_id, $question_id]
6852 while ($row = $this->db->fetchAssoc($result)) {
6857 if (!array_key_exists($row[
"active_fi"], $foundusers)) {
6858 $foundusers[$row[
"active_fi"]] = [];
6860 array_push($foundusers[$row[
"active_fi"]], [
"pass" => $row[
"pass"],
"qid" => $row[
"question_fi"]]);
6873 $foundParticipants =
$data->getParticipants();
6874 $results = [
"overview" => [],
"questions" => []];
6875 if (count($foundParticipants)) {
6876 $results[
"overview"][$this->
lng->txt(
"tst_eval_total_persons")] = count($foundParticipants);
6877 $total_finished =
$data->getTotalFinishedParticipants();
6878 $results[
"overview"][$this->
lng->txt(
"tst_eval_total_finished")] = $total_finished;
6880 $diff_seconds = $average_time;
6881 $diff_hours = floor($diff_seconds / 3600);
6882 $diff_seconds -= $diff_hours * 3600;
6883 $diff_minutes = floor($diff_seconds / 60);
6884 $diff_seconds -= $diff_minutes * 60;
6885 $results[
"overview"][$this->
lng->txt(
"tst_eval_total_finished_average_time")] = sprintf(
"%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
6887 $total_passed_reached = 0;
6888 $total_passed_max = 0;
6889 $total_passed_time = 0;
6890 foreach ($foundParticipants as $userdata) {
6891 if ($userdata->getPassed()) {
6893 $total_passed_reached += $userdata->getReached();
6894 $total_passed_max += $userdata->getMaxpoints();
6895 $total_passed_time += $userdata->getTimeOfWork();
6898 $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
6899 $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
6900 $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
6901 $results[
"overview"][$this->
lng->txt(
"tst_eval_total_passed")] = $total_passed;
6902 $results[
"overview"][$this->
lng->txt(
"tst_eval_total_passed_average_points")] = sprintf(
"%2.2f", $average_passed_reached) .
" " . strtolower($this->
lng->txt(
"of")) .
" " . sprintf(
"%2.2f", $average_passed_max);
6903 $average_time = $average_passed_time;
6904 $diff_seconds = $average_time;
6905 $diff_hours = floor($diff_seconds / 3600);
6906 $diff_seconds -= $diff_hours * 3600;
6907 $diff_minutes = floor($diff_seconds / 60);
6908 $diff_seconds -= $diff_minutes * 60;
6909 $results[
"overview"][$this->
lng->txt(
"tst_eval_total_passed_average_time")] = sprintf(
"%02d:%02d:%02d", $diff_hours, $diff_minutes, $diff_seconds);
6912 foreach (
$data->getQuestionTitles() as $question_id => $question_title) {
6916 foreach ($foundParticipants as $userdata) {
6917 for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
6918 if (is_object($userdata->getPass($i))) {
6919 $question = $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
6920 if (is_array($question)) {
6922 $reached += $question[
"reached"];
6923 $max += $question[
"points"];
6928 $percent = $max ? $reached / $max * 100.0 : 0;
6929 $results[
"questions"][$question_id] = [
6931 sprintf(
"%.2f", $answered ? $reached / $answered : 0) .
" " . strtolower($this->
lng->txt(
"of")) .
" " . sprintf(
"%.2f", $answered ? $max / $answered : 0),
6932 sprintf(
"%.2f", $percent) .
"%",
6934 sprintf(
"%.2f", $answered ? $reached / $answered : 0),
6935 sprintf(
"%.2f", $answered ? $max / $answered : 0),
6947 $expFactory =
new ilTestExportFactory($this, $this->
lng, $this->log, $this->tree, $this->component_repository, $this->questioninfo);
6948 $test_exp = $expFactory->getExporter(
'xml');
6949 return $test_exp->buildExportFile();
6954 return $this->
getMainSettings()->getFinishingSettings()->getMailNotificationContentType();
6962 $mail->sendSimpleNotification($owner_id, $this->
getTitle(), $usr_data);
6978 return $table_gui->getSelectedColumns();
6992 $delivered_file_name =
'result_' . $active_id .
'.xlsx';
6993 $worksheet->writeToFile($temp_file_path);
6995 $fd->copyAttachmentFile($temp_file_path .
'.xlsx', $delivered_file_name);
6996 $file_names[] = $delivered_file_name;
6998 $mail->sendAdvancedNotification($owner_id, $this->
getTitle(), $usr_data, $file_names);
7000 if (count($file_names)) {
7001 $fd->unlinkFiles($file_names);
7003 @unlink($file .
'xlsx');
7011 FROM tst_result_cache 7012 WHERE active_fi = %s 7015 $result = $this->db->queryF(
7021 if (!$result->numRows()) {
7026 FROM tst_result_cache 7027 WHERE active_fi = %s 7030 $result = $this->db->queryF(
7037 $row = $this->db->fetchAssoc($result);
7044 return $this->
getMainSettings()->getFinishingSettings()->getAlwaysSendMailNotification();
7049 return $this->
getScoreSettings()->getResultDetailsSettings()->getExportSettings();
7067 $query =
'SELECT question_fi FROM tst_test_question WHERE test_fi = %s';
7068 $types = [
'integer'];
7071 $new_question_id += 1;
7074 $res = $this->db->queryF($query, $types, $values);
7075 while ($row = $this->db->fetchAssoc(
$res)) {
7076 $qid = $row[
'question_fi'];
7078 if ($qid == $new_question_id) {
7080 } elseif ($qid == $previous_question_id) {
7081 $new_array[$position++] = $qid;
7082 $new_array[$position++] = $new_question_id;
7085 $new_array[$position++] = $qid;
7089 $update_query =
'UPDATE tst_test_question SET sequence = %s WHERE test_fi = %s AND question_fi = %s';
7090 $update_types = [
'integer',
'integer',
'integer'];
7092 foreach ($new_array as $position => $qid) {
7093 $this->db->manipulateF(
7107 $question_set_config = $this->question_set_config_factory->getQuestionSetConfig();
7108 $reindexed_sequence_position_map = $question_set_config->reindexQuestionOrdering();
7112 return $reindexed_sequence_position_map;
7121 foreach ($orders as
$id => $position) {
7125 isset($obligations[
$id]) && $obligations[
$id] ? 1 : 0
7129 UPDATE tst_test_question 7132 WHERE question_fi = %s 7135 $this->db->manipulateF(
7137 [
'integer',
'integer',
'integer'],
7138 [$i, $obligatory, $id]
7147 if ($question_before) {
7148 $query =
'SELECT sequence, test_fi FROM tst_test_question WHERE question_fi = %s';
7149 $types = [
'integer'];
7150 $values = [$question_before];
7151 $rset = $this->db->queryF($query, $types, $values);
7154 if (!$question_before || ($rset && !($row = $this->db->fetchAssoc($rset)))) {
7161 $update =
'UPDATE tst_test_question SET sequence = sequence + 1 WHERE sequence > %s AND test_fi = %s';
7162 $types = [
'integer',
'integer'];
7163 $values = [$row[
'sequence'], $row[
'test_fi']];
7164 $this->db->manipulateF($update, $types, $values);
7166 $update =
'UPDATE tst_test_question SET sequence = %s WHERE question_fi = %s';
7167 $types = [
'integer',
'integer'];
7168 $values = [$row[
'sequence'] + 1, $question_to_move];
7169 $this->db->manipulateF($update, $types, $values);
7178 $IN_questions = $this->db->in(
'q1.question_id', array_keys($questions),
false,
'integer');
7181 SELECT count(q1.question_id) cnt 7183 FROM qpl_questions q1 7185 INNER JOIN qpl_questions q2 7186 ON q2.question_id = q1.original_id 7189 AND q1.obj_fi = q2.obj_fi 7191 $rset = $this->db->query($query);
7192 $row = $this->db->fetchAssoc($rset);
7194 return $row[
'cnt'] > 0;
7206 $ilDB = $DIC[
'ilDB'];
7208 $result =
$ilDB->queryF(
7209 "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
7210 " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
7211 " WHERE user_fi=%s" .
7212 " GROUP BY test_fi",
7213 [
'integer',
'integer'],
7217 while ($row =
$ilDB->fetchAssoc($result)) {
7218 $obj_id = self::_getObjectIDFromTestID($row[
"test_fi"]);
7219 $all[$obj_id] = (bool) $row[
"pass"];
7235 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getQuestionHintsEnabled();
7240 $this->activation_visibility = (bool) $a_value;
7255 $this->activation_limited = (bool) $a_value;
7259 ?
bool $is_activation_limited =
false,
7260 ?
int $activation_starting_time = null,
7261 ?
int $activation_ending_time = null,
7262 bool $activation_visibility =
false,
7264 if (!$this->ref_id) {
7269 $is_activation_limited ??=
false;
7271 if (!$is_activation_limited) {
7275 $item->setTimingStart($activation_starting_time);
7276 $item->setTimingEnd($activation_ending_time);
7277 $item->toggleVisible($activation_visibility);
7280 $item->update($this->ref_id);
7290 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
7291 if ($page_id !== null) {
7296 $page_object->setParentId($this->
getId());
7297 $new_page_id = $page_object->createPageWithNextId();
7299 ->withIntroductionPageId($new_page_id);
7303 return $new_page_id;
7308 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
7309 if ($page_id !== null) {
7314 $page_object->setParentId($this->
getId());
7315 $new_page_id = $page_object->createPageWithNextId();
7317 ->withConcludingRemarksPageId($new_page_id);
7321 return $new_page_id;
7326 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreEnabled();
7340 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreAnon();
7361 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreAchievedTS();
7369 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreScore();
7377 return $this->
getScoreSettings()->getGamificationSettings()->getHighscorePercentage();
7385 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreHints();
7393 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreWTime();
7401 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreOwnTable();
7409 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreTopTable();
7418 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreTopNum();
7423 return $this->
getScoreSettings()->getGamificationSettings()->getHighScoreMode();
7428 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled();
7433 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getCompulsoryQuestionsEnabled();
7439 $question_info = $DIC->testQuestionPool()->questionInfo();
7440 $class = $question_info->getQuestionType($question_id);
7441 return call_user_func([$class,
'isObligationPossible'], $question_id);
7453 $ilDB = $DIC[
'ilDB'];
7455 $rset =
$ilDB->queryF(
'SELECT obligatory FROM tst_test_question WHERE question_fi = %s', [
'integer'], [$question_id]);
7457 if ($row =
$ilDB->fetchAssoc($rset)) {
7458 return (
bool) $row[
'obligatory'];
7482 if ($this->current_user_all_obliations_answered === null) {
7484 $rset = $this->db->queryF(
7485 'SELECT obligations_answered FROM tst_pass_result WHERE active_fi = %s AND pass = %s',
7486 [
'integer',
'integer'],
7487 [$active_id, self::_getPass($active_id)]
7490 if ($row = $this->db->fetchAssoc($rset)) {
7491 $this->current_user_all_obliations_answered = (bool) ($row[
'obligations_answered'] ?? 0);
7500 if ($this->has_obligations === null) {
7501 $rset = $this->db->queryF(
7502 'SELECT count(*) cnt FROM tst_test_question WHERE test_fi = %s AND obligatory = 1',
7506 $row = $this->db->fetchAssoc($rset);
7507 $this->has_obligations = $row[
'cnt'] > 0;
7515 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getAutosaveEnabled();
7520 return $this->
getScoreSettings()->getResultSummarySettings()->getPassDeletionAllowed();
7525 return $this->
getMainSettings()->getFinishingSettings()->getShowAnswerOverview();
7530 $this->activation_starting_time = $starting_time;
7535 $this->activation_ending_time = $ending_time;
7557 $result = $this->db->queryF(
7558 "SELECT tst_times.active_fi, tst_times.started FROM tst_times, tst_active WHERE tst_times.active_fi = tst_active.active_id AND tst_active.test_fi = %s ORDER BY tst_times.tstamp DESC",
7562 while ($row = $this->db->fetchAssoc($result)) {
7563 $times[$row[
'active_fi']] = $row[
'started'];
7571 $result = $this->db->queryF(
7572 "SELECT tst_addtime.active_fi, tst_addtime.additionaltime FROM tst_addtime, tst_active WHERE tst_addtime.active_fi = tst_active.active_id AND tst_active.test_fi = %s",
7576 while ($row = $this->db->fetchAssoc($result)) {
7577 $times[$row[
'active_fi']] = $row[
'additionaltime'];
7584 $result = $this->db->queryF(
7585 "SELECT additionaltime FROM tst_addtime WHERE active_fi = %s",
7589 if ($result->numRows() > 0) {
7590 $row = $this->db->fetchAssoc($result);
7591 return $row[
'additionaltime'];
7599 $participantData->setParticipantAccessFilter(
7600 $this->participant_access_filter->getManageParticipantsUserFilter($this->getRefId())
7604 $participantData->setActiveIdsFilter([$active_id]);
7607 $participantData->load($this->
getTestId());
7609 foreach ($participantData->getActiveIds() as $active_fi) {
7610 $result = $this->db->queryF(
7611 "SELECT active_fi FROM tst_addtime WHERE active_fi = %s",
7616 if ($result->numRows() > 0) {
7617 $this->db->manipulateF(
7618 "DELETE FROM tst_addtime WHERE active_fi = %s",
7624 $this->db->manipulateF(
7625 "INSERT INTO tst_addtime (active_fi, additionaltime, tstamp) VALUES (%s, %s, %s)",
7626 [
'integer',
'integer',
'integer'],
7627 [$active_fi, $minutes, time()]
7639 SELECT MAX(tst_pass_result.pass) + 1 max_res 7640 FROM tst_pass_result 7641 INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi 7642 WHERE test_fi = ' . $this->db->quote($this->
getTestId(),
'integer') .
' 7644 $res = $this->db->query($query);
7646 return (
int)
$data[
'max_res'];
7652 $ilDB = $DIC[
'ilDB'];
7654 $exam_id_query =
'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
7655 $exam_id_result =
$ilDB->queryF($exam_id_query, [
'integer',
'integer' ], [ $active_id, $pass ]);
7656 if (
$ilDB->numRows($exam_id_result) == 1) {
7657 $exam_id_row =
$ilDB->fetchAssoc($exam_id_result);
7659 if ($exam_id_row[
'exam_id'] != null) {
7660 return $exam_id_row[
'exam_id'];
7667 public static function buildExamId($active_id, $pass, $test_obj_id = null): string
7674 if ($test_obj_id === null) {
7675 $obj_id = self::_getObjectIDFromActiveID($active_id);
7677 $obj_id = $test_obj_id;
7680 $examId =
'I' . $inst_id .
'_T' . $obj_id .
'_A' . $active_id .
'_P' . $pass;
7687 return $this->
getMainSettings()->getTestBehaviourSettings()->getExamIdInTestPassEnabled();
7692 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults();
7700 ->withQuestionSetType($question_set_type)
7706 return $this->
getMainSettings()->getGeneralSettings()->getQuestionSetType();
7719 $ilDB = $DIC[
'ilDB'];
7721 $query =
"SELECT question_set_type FROM tst_tests WHERE obj_fi = %s";
7725 $questionSetType = null;
7727 while ($row =
$ilDB->fetchAssoc(
$res)) {
7728 $questionSetType = $row[
'question_set_type'];
7731 return $questionSetType;
7763 return self::lookupQuestionSetType($a_obj_id) == self::QUESTION_SET_TYPE_RANDOM;
7768 switch ($questionSetType) {
7770 return $lng->
txt(
'tst_question_set_type_fixed');
7773 return $lng->
txt(
'tst_question_set_type_random');
7776 throw new ilTestException(
'invalid question set type value given: ' . $questionSetType);
7791 $scoring->setPreserveManualScores($preserve_manscoring);
7792 $scoring->recalculateSolutions();
7798 $ilDB = $DIC[
'ilDB'];
7803 INNER JOIN tst_tests 7804 ON test_id = test_fi 7808 $res =
$ilDB->queryF($query, [
'integer'], [$userId]);
7812 while ($row =
$ilDB->fetchAssoc(
$res)) {
7813 $objIds[] = (
int) $row[
'obj_fi'];
7821 return $this->
getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled();
7837 if (!$this->
getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled()) {
7841 if (!self::isSkillManagementGloballyActivated()) {
7852 if (self::$isSkillManagementGloballyActivated === null) {
7855 self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
7858 return self::$isSkillManagementGloballyActivated;
7863 return $this->
getScoreSettings()->getResultSummarySettings()->getShowGradingStatusEnabled();
7868 return $this->
getScoreSettings()->getResultSummarySettings()->getShowGradingMarkEnabled();
7873 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled();
7878 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled();
7883 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion();
7889 $ilDB = $DIC[
'ilDB'];
7890 $ilUser = $DIC[
'ilUser'];
7894 $active_id = $test_obj->getActiveIdOfUser($user_id);
7899 $test_session_factory->reset();
7903 $test_session = $test_session_factory->getSession($active_id);
7904 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $test_session->getPass());
7921 SELECT COUNT(test_question_id) cnt 7922 FROM tst_test_question 7927 $questRes = $this->db->queryF($query, [
'integer'], [$this->
getTestId()]);
7929 $row = $this->db->fetchAssoc($questRes);
7930 $questCount = $row[
'cnt'];
7936 INNER JOIN tst_sequence tseq 7937 ON tseq.active_fi = tac.active_id 7938 WHERE tac.test_fi = %s 7941 $partRes = $this->db->queryF(
7947 while ($row = $this->db->fetchAssoc($partRes)) {
7948 $sequence = @unserialize($row[
'sequence']);
7954 $sequence = array_filter($sequence,
function ($value) use ($questCount) {
7955 return $value <= $questCount;
7958 $num_seq = count($sequence);
7959 if ($questCount > $num_seq) {
7960 $diff = $questCount - $num_seq;
7961 for ($i = 1; $i <= $diff; $i++) {
7962 $sequence[$num_seq + $i - 1] = $num_seq + $i;
7966 $new_sequence = serialize($sequence);
7968 $this->db->update(
'tst_sequence', [
7969 'sequence' => [
'clob', $new_sequence]
7971 'active_fi' => [
'integer', $row[
'active_fi']],
7972 'pass' => [
'integer', $row[
'pass']]
7976 $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : []);
7981 INNER JOIN tst_sequence tseq 7982 ON tseq.active_fi = tac.active_id 7983 WHERE tac.test_fi = %s 7986 $part_rest = $this->db->queryF(
7992 while ($row = $this->db->fetchAssoc($part_rest)) {
7993 $this->db->update(
'tst_sequence', [
7994 'sequence' => [
'clob', $new_sequence]
7996 'active_fi' => [
'integer', $row[
'active_fi']],
7997 'pass' => [
'integer', $row[
'pass']]
8013 if (!$this->score_settings) {
8022 if (!$this->score_settings_repo) {
8030 if (!$this->main_settings) {
8039 if (!$this->main_settings_repo) {
8049 if ($pass !== null) {
8051 SELECT tst_pass_result.*, 8052 tst_active.last_finished_pass 8053 FROM tst_pass_result 8054 INNER JOIN tst_active 8055 on tst_pass_result.active_fi = tst_active.active_id 8056 WHERE active_fi = %s 8060 $result = $this->db->queryF(
8062 [
'integer',
'integer'],
8066 $test_pass_result_row = $this->db->fetchAssoc($result);
8068 if (!is_array($test_pass_result_row)) {
8069 $test_pass_result_row = [];
8071 $max = (float) ($test_pass_result_row[
'maxpoints'] ?? 0);
8072 $reached = (float) ($test_pass_result_row[
'points'] ?? 0);
8073 $percentage = ($max <= 0.0 || $reached <= 0.0) ? 0 : ($reached / $max) * 100.0;
8074 $obligations_answered = (
int) ($test_pass_result_row[
'obligations_answered'] ?? 1);
8076 $mark = $this->mark_schema->getMatchingMark($percentage);
8077 $is_passed = $test_pass_result_row[
'last_finished_pass'] !== null
8078 && $pass <= $test_pass_result_row[
'last_finished_pass']
8079 && $mark->getPassed();
8081 $hint_count = $test_pass_result_row[
'hint_count'] ?? 0;
8082 $hint_points = $test_pass_result_row[
'hint_points'] ?? 0.0;
8084 $user_test_result_update_callback =
function () use ($active_id, $pass, $max, $reached, $is_passed, $obligations_answered, $hint_count, $hint_points, $mark) {
8085 $passed_once_before = 0;
8086 $query =
'SELECT passed_once FROM tst_result_cache WHERE active_fi = %s';
8087 $res = $this->db->queryF($query, [
'integer'], [$active_id]);
8088 while ($passed_once_result_row = $this->db->fetchAssoc(
$res)) {
8089 $passed_once_before = (
int) $passed_once_result_row[
'passed_once'];
8092 $passed_once = (
int) ($is_passed || $passed_once_before);
8094 $this->db->manipulateF(
8095 'DELETE FROM tst_result_cache WHERE active_fi = %s',
8100 if ($reached < 0.0) {
8104 $mark_short_name = $mark->getShortName();
8105 if ($mark_short_name ===
'') {
8106 $mark_short_name =
' ';
8109 $mark_official_name = $mark->getOfficialName();
8110 if ($mark_official_name ===
'') {
8111 $mark_official_name =
' ';
8117 'active_fi' => [
'integer', $active_id],
8118 'pass' => [
'integer', $pass ?? 0],
8119 'max_points' => [
'float', $max],
8120 'reached_points' => [
'float', $reached],
8121 'mark_short' => [
'text', $mark_short_name],
8122 'mark_official' => [
'text', $mark_official_name],
8123 'passed_once' => [
'integer', $passed_once],
8124 'passed' => [
'integer', (
int) $is_passed],
8125 'failed' => [
'integer', (
int) !$is_passed],
8126 'tstamp' => [
'integer', time()],
8127 'hint_count' => [
'integer', $hint_count],
8128 'hint_points' => [
'float', $hint_points],
8129 'obligations_answered' => [
'integer', $obligations_answered]
8134 if (is_object($process_locker)) {
8135 $process_locker->executeUserTestResultUpdateLockOperation($user_test_result_update_callback);
8137 $user_test_result_update_callback();
8145 bool $obligations_enabled =
false,
8147 int $test_obj_id = null
8152 $result = $this->db->queryF(
8154 SELECT SUM(points) reachedpoints, 8155 SUM(hint_count) hint_count, 8156 SUM(hint_points) hint_points, 8157 COUNT(DISTINCT(question_fi)) answeredquestions 8158 FROM tst_test_result 8159 WHERE active_fi = %s 8162 [
'integer',
'integer'],
8166 if ($result->numRows() > 0) {
8167 if ($obligations_enabled) {
8169 SELECT answered answ 8170 FROM tst_test_question 8171 INNER JOIN tst_active 8173 AND tst_test_question.test_fi = tst_active.test_fi 8174 LEFT JOIN tst_test_result 8175 ON tst_test_result.active_fi = %s 8176 AND tst_test_result.pass = %s 8177 AND tst_test_question.question_fi = tst_test_result.question_fi 8178 WHERE obligatory = 1';
8180 $result_obligatory = $this->db->queryF(
8182 [
'integer',
'integer',
'integer'],
8183 [$active_id, $active_id, $pass]
8186 $obligations_answered = 1;
8188 while ($row_obligatory = $this->db->fetchAssoc($result_obligatory)) {
8189 if (!(
int) $row_obligatory[
'answ']) {
8190 $obligations_answered = 0;
8195 $obligations_answered = 1;
8198 $row = $this->db->fetchAssoc($result);
8200 if ($row[
'reachedpoints'] === null
8201 || $row[
'reachedpoints'] < 0.0) {
8202 $row[
'reachedpoints'] = 0.0;
8204 if ($row[
'hint_count'] === null) {
8205 $row[
'hint_count'] = 0;
8207 if ($row[
'hint_points'] === null) {
8208 $row[
'hint_points'] = 0.0;
8213 $update_pass_result_callback =
function () use (
$data, $active_id, $pass, $row, $time, $obligations_answered, $exam_identifier) {
8217 'active_fi' => [
'integer', $active_id],
8218 'pass' => [
'integer', $pass]
8221 'points' => [
'float', $row[
'reachedpoints']],
8222 'maxpoints' => [
'float',
$data[
'points']],
8223 'questioncount' => [
'integer',
$data[
'count']],
8224 'answeredquestions' => [
'integer', $row[
'answeredquestions']],
8225 'workingtime' => [
'integer', $time],
8226 'tstamp' => [
'integer', time()],
8227 'hint_count' => [
'integer', $row[
'hint_count']],
8228 'hint_points' => [
'float', $row[
'hint_points']],
8229 'obligations_answered' => [
'integer', $obligations_answered],
8230 'exam_id' => [
'text', $exam_identifier]
8236 $process_locker->executeUserPassResultUpdateLockOperation($update_pass_result_callback);
8238 $update_pass_result_callback();
8245 'active_fi' => $active_id,
8247 'points' => $row[
'reachedpoints'],
8248 'maxpoints' =>
$data[
'points'],
8249 'questioncount' =>
$data[
'count'],
8250 'answeredquestions' => $row[
'answeredquestions'],
8251 'workingtime' => $time,
8253 'hint_count' => $row[
'hint_count'],
8254 'hint_points' => $row[
'hint_points'],
8255 'obligations_answered' => $obligations_answered,
8256 'exam_id' => $exam_identifier
8262 $this->mark_schema->flush();
8266 bool $old_online_status,
8267 bool $new_online_status
8269 if (!$old_online_status && $new_online_status) {
8271 $newsItem->setContext($this->
getId(),
'tst');
8273 $newsItem->setTitle(
'new_test_online');
8274 $newsItem->setContentIsLangVar(
true);
8275 $newsItem->setContent(
'');
8276 $newsItem->setUserId($this->
user->getId());
8278 $newsItem->create();
8282 if ($old_online_status && !$new_online_status) {
8288 if (!$new_online_status && $newsId > 0) {
8290 $newsItem->setTitle(
'new_test_online');
8291 $newsItem->setContentIsLangVar(
true);
8292 $newsItem->setContent(
'');
8293 $newsItem->update();
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...
withScoringSettings(ilObjTestSettingsScoring $settings)
isShowGradingMarkEnabled()
static isParticipantsLastPassActive(int $test_ref_id, int $user_id)
setQuestionSetType(string $question_set_type)
& getWorkedQuestions($active_id, $pass=null)
Gets the id's of all questions a user already worked through.
addConcludingRemarksToSettingsFromImport(ilObjTestSettingsFinishing $settings, array $material, array $mappings)
isNextPassAllowed(ilTestPassesSelector $testPassesSelector, int &$next_pass_allowed_timestamp)
getListOfQuestionsDescription()
raiseError(string $a_msg, int $a_err_obj)
wrapper for downward compability
static get(string $a_var)
buildStatisticsAccessFilteredParticipantList()
getScoreReporting()
Gets the score reporting of the ilObjTest object.
getTimeExtensionsOfParticipants()
isHTML($a_text)
Checks if a given string contains HTML or not.
inviteRole($role_id)
Invites all users of a role to a test.
static _getWorkingTimeOfParticipantForPass($active_id, $pass)
Returns the complete working time in seconds for a test participant.
ilObjTestScoreSettings $score_settings
isBlockPassesAfterPassedEnabled()
isTestFinished($active_id)
returns if the active for user_id has been submitted
MainSettingsRepository $main_settings_repo
Readable part of repository interface to ilComponentDataDB.
getActivationVisibility()
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
int $activation_starting_time
getHighscoreTopNum(int $a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
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.
exportFileItems($target_dir, &$expLog)
export files of file itmes
static _getObjectIDFromTestID($test_id)
Returns the ILIAS test object id for a given test id.
deliverPDFfromFO($fo, $title=null)
Delivers a PDF file from a XSL-FO string.
getReportingDate()
Gets the reporting date of the ilObjTest object.
evalTotalPersonsArray($name_sort_order="asc")
Returns all persons who started the test.
ilComponentRepository $component_repository
getProcessingTimeAsMinutes()
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
bool $current_user_all_obliations_answered
evalTotalParticipantsArray($name_sort_order="asc")
Returns all participants who started the test.
static _getParticipantData($active_id)
Retrieves a participant name from active id.
removeTestResultsByUserIds($userIds)
& getTestResult(int $active_id, ?int $pass=null, bool $ordered_sequence=false, bool $considerHiddenQuestions=true, bool $considerOptionalQuestions=true)
Calculates the results of a test for a given user and returns an array with all test results...
static isQuestionObligationPossible(int $question_id)
exportXMLPageObjects(&$a_xml_writer, $inst, &$expLog)
export page objects to xml (see ilias_co.dtd)
getUnfilteredEvaluationData()
isShowExamIdInTestPassEnabled()
setQuestionOrderAndObligations($orders, $obligations)
processPrintoutput2FO($print_output)
Convert a print output to XSL-FO.
static deleteNewsOfContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="")
Delete all news of a context.
checkQuestionParent($questionId)
saveCompleteStatus(ilTestQuestionSetConfig $testQuestionSetConfig)
static completeMissingPluginName($question_type_data)
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...
withGamificationSettings(ilObjTestSettingsGamification $settings)
getEnableProcessingTime()
getProcessingTimeAsArray()
const QUESTION_SET_TYPE_RANDOM
static _getSuggestedSolutionOutput(int $question_id)
getListOfQuestionsStart()
static _lookupRandomTest($a_obj_id)
Returns the fact wether the test with passed obj id is a random questions test or not...
& getParticipants()
Returns all persons who started the test.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getCompleteWorkingTimeOfParticipant($active_id)
Returns the complete working time in seconds for a test participant.
This class handles all operations on files (attachments) in directory ilias_data/mail.
setActivationStartingTime(?int $starting_time=null)
qtiMaterialToArray($a_material)
Reads an QTI material tag and creates a text string.
static _getAvailableQuestionpools( $use_object_id=false, $equal_points=false, $could_be_offline=false, $showPath=false, $with_questioncount=false, $permission='read', $usr_id='')
Returns the available question pools for the active user.
const SCORE_REPORTING_AFTER_PASSED
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
Abstract basic class which is to be extended by the concrete assessment question type classes...
getShowSolutionListOwnAnswers()
getPresentationMaterial()
getShowSolutionFeedback()
Returns if the feedback should be presented to the solution or not.
Class ChatMainBarProvider .
InternalRequestService $testrequest
static _getPassScoring($active_id)
Gets the pass scoring type.
static lookupPassResultsUpdateTimestamp($active_id, $pass)
& getExistingQuestions($pass=null)
Get the id's of the questions which are already part of the test.
bool $print_best_solution_with_result
isExecutable($test_session, $user_id, $allow_pass_increase=false)
Checks if the test is executable by the given user.
loadQuestions(int $active_id=0, ?int $pass=null)
Load the test question id's from the database.
getShowKioskModeParticipant()
static $isSkillManagementGloballyActivated
buildDateTimeImmutableFromPeriod(?string $period)
insertQuestion(ilTestQuestionSetConfig $testQuestionSetConfig, $question_id, $linkOnly=false)
Insert a question in the list of questions.
getQuestionSetTypeTranslation(ilLanguage $lng, $questionSetType)
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
getTestId()
Gets the database id of the additional test data.
const FILTER_BY_ACTIVE_ID
static factory(string $a_package, int $a_timeout=0)
Creates an ilRpcClient instance to our ilServer.
Class ilTestMailNotification.
getListOfQuestionsSettings()
Returns the settings for the list of questions options in the test properties This could contain one ...
getAvailableQuestionpools($use_object_id=false, $equal_points=false, $could_be_offline=false, $show_path=false, $with_questioncount=false, $permission="read")
Returns the available question pools for the active user.
createQuestionGUI($question_type, $question_id=-1)
Creates a question GUI instance of a given question type.
& getQuestionTitlesAndIndexes()
Returns the titles of the test questions in question sequence.
getMailNotificationType()
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false)
logManualFeedback($active_id, $question_id, $feedback)
Creates a log for the manual feedback.
getJavaScriptOutput()
Returns if Javascript should be chosen for drag & drop actions for the active user.
const TIMINGS_DEACTIVATED
getShowSolutionAnswersOnly()
Returns if the full solution (including ILIAS content) should be presented to the solution or not...
static _lookupName(int $a_user_id)
lookup user name
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
& createTestSequence($active_id, $pass, $shuffle)
getQuestionTitle($title, $nr=null, $points=null)
Returns the title of a test question and checks if the title output is allowed.
& _evalResultsOverview($test_id)
Creates an associated array with the results of all participants of a test.
& getQuestionsOfTest($active_id)
Retrieves all the assigned questions for all test passes of a test participant.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$test_sequence
contains the test sequence data
getXMLZip()
Get zipped xml file for test.
inviteUser($user_id, $client_ip="")
Invites a user to a test.
& getInvitedUsers(int $user_id=0, $order="login, lastname, firstname")
Returns a list of all invited users in a test.
toXML()
Returns a QTI xml representation of the test.
setTemplate(int $template_id)
setActivationLimited($a_value)
TableGUI class for evaluation of all users.
static isManScoringDone(int $active_id)
setActivationEndingTime(?int $ending_time=null)
setTestId($a_id)
Sets the test ID.
getUsrPassOverviewEnabled()
isShowExamIdInTestResultsEnabled()
_getVisitTimeOfParticipant($test_id, $active_id)
Returns the first and last visit of a participant.
static deliverData(string $a_data, string $a_filename, string $mime="application/octet-stream")
getCompleteWorkingTime($user_id)
Returns the complete working time in seconds a user worked on the test.
getImagePathWeb()
Returns the web image path for web accessable images of a test The image path is under the web access...
startingTimeReached()
Returns true if the starting time of a test is reached A starting time is not available for self asse...
getQuestionBehaviourSettings()
questionMoveDown($question_id)
Moves a question down in order.
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
hasAnyTestResult(ilTestSession $test_session)
static getStyleSheetLocation(string $mode="output", string $a_css_name="", string $a_css_location="")
get full style sheet file name (path inclusive) of current user
getActiveIdOfUser($user_id="", $anonymous_id="")
Gets the active id of a given user.
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
$participantDataExist
holds the fact wether participant data exists or not DO NOT USE TIS PROPERTY DRIRECTLY ALWAYS USE ilO...
getActiveParticipantList()
addIntroductionToSettingsFromImport(ilObjTestSettingsIntroduction $settings, array $material, array $mappings)
static _isPassed($user_id, $a_obj_id)
Returns TRUE if the user with the user id $user_id passed the test with the object id $a_obj_id...
buildName(?int $user_id, ?string $firstname, ?string $lastname)
Builds a user name for the output depending on test type and existence of the user.
static _getBestPass($active_id)
Retrieves the best pass of a given user for a given test.
evalTotalStartedAverageTime(?array $active_ids_to_filter=null)
replaceFilesInPageImports(string $text, $mappings)
saveToDb(bool $properties_only=false)
static _lookupTestObjIdForQuestionId(int $q_id)
Get test Object ID for question ID.
static _lookupAnonymity($a_obj_id)
getPotentialRandomTestQuestions()
getShowSolutionListComparison()
setQuestionSetSolved($value, $question_id, $user_id)
sets question solved state to value for given user_id
Base Exception for all Exceptions relating to Modules/Test.
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
startWorkingTime($active_id, $pass)
Write the initial entry for the tests working time to the database.
static removeTrailingPathSeparators(string $path)
isTestQuestion($questionId)
disinviteUser($user_id)
Disinvites a user from a test.
$evaluation_data
Contains the evaluation data settings the tutor defines for the user.
& getQuestionTitles()
Returns the titles of the test questions in question sequence.
static _lookupObjId(int $ref_id)
& evalResultsOverview()
Creates an associated array with the results of all participants of a test.
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
& _getCompleteWorkingTimeOfParticipants($test_id)
Returns the complete working time in seconds for all test participants.
isRandomTest()
Returns the fact wether this test is a random questions test or not.
static getASCIIFilename(string $a_filename)
getHighscorePercentage()
Gets if the percentage column should be shown.
xmlEndTag(string $tag)
Writes an endtag.
isFixedTest()
Returns the fact wether this test is a fixed question set test or not.
checkMarks()
{boolean|string True or an error string which can be used for display purposes}
const SCORE_REPORTING_FINISHED
static isQuestionObligatory($question_id)
checks wether the question with given id is marked as obligatory or not
static _getUserIdFromActiveId(int $active_id)
TestManScoringDoneHelper $testManScoringDoneHelper
saveManualFeedback(int $active_id, int $question_id, int $pass, ?string $feedback, bool $finalized=false, bool $is_single_feedback=false)
updateWorkingTime($times_id)
Update the working time of a test when a question is answered.
getFixedQuestionSetTotalPoints()
getHtmlQuestionContentPurifier()
ilTestParticipantList $access_filtered_participant_list
getSpecificAnswerFeedback()
getImportMapping()
get array of (two) new created questions for import id
static _getMaxPass($active_id)
Retrieves the maximum pass of a given user for a given test in which the user answered at least one q...
updateTestPassResults(int $active_id, int $pass, bool $obligations_enabled=false, ilAssQuestionProcessLocker $process_locker=null, int $test_obj_id=null)
addDefaults($a_name)
Adds the defaults of this test to the test defaults.
cloneObject(int $target_id, int $copy_id=0, bool $omit_tree=false)
Clone object.
getMarkSchemaForeignId()
{int}
static collectFileItems(ilPageObject $a_page, DOMDocument $a_domdoc)
Get all file items that are used within the page.
static instantiateQuestion(int $question_id)
$metadata
A reference to an IMS compatible matadata set.
removeTestResults(ilTestParticipantData $participantData)
Interface for html sanitizing functionality.
removeQuestions(array $removeQuestionIds)
evalStatistical($active_id)
Returns the statistical evaluation of the test for a specified user.
static getSingleManualFeedback(int $active_id, int $question_id, int $pass)
getHighscoreHints()
Gets, if the column with the number of requested hints should be shown.
static _enabledAssessmentLogging()
cloneMetaData(ilObject $target_obj)
Copy meta data.
getAccessFilteredParticipantList()
getQuestiontext($question_id)
Returns the question text for a given question.
replaceMobsInPageImports(string $text, array $mappings)
getVisitTimeOfParticipant($active_id)
Returns the first and last visit of a participant.
static _lookupClientIP(int $a_user_id)
static _lookupTitle(int $obj_id)
getAllTestResults($participants, $prepareForCSV=true)
returns all test results for all participants
getHighscoreAnon()
Gets if the highscores should be anonymized per setting.
sendAdvancedNotification(int $active_id)
getTestParticipantsForManualScoring($filter=null)
static _getQuestionCountAndPointsForPassOfParticipant($active_id, $pass)
fromXML(ilQTIAssessment $assessment, array $mappings)
Receives parameters from a QTI parser and creates a valid ILIAS test object.
static _prepareCloneSelection(array $ref_ids, string $new_type, bool $show_path=true)
Prepare copy wizard object selection.
setActivationVisibility($a_value)
hasQuestionsWithoutQuestionpool()
evalTotalPersons()
Returns the number of persons who started the test.
static _getScoreCutting($active_id)
Determines if the score of a question should be cut at 0 points or the score of the whole test...
getStartingTimeOfUser($active_id, $pass=null)
Returns the unix timestamp of the time a user started a test.
sendSimpleNotification($active_id)
getShowSolutionPrintview()
Returns if the solution printview should be presented to the user or not.
updateTestResultCache(int $active_id, ilAssQuestionProcessLocker $process_locker=null)
hasNrOfTriesRestriction()
returns if the numbers of tries have to be checked
addExtraTime($active_id, $minutes)
getAuthor()
Gets the authors name of the ilObjTest object.
static _getResultPass($active_id)
Retrieves the pass number that should be counted for a given user.
getTestDefaults($test_defaults_id)
const SCORE_REPORTING_DISABLED
getShowPassDetails()
Returns if the pass details should be shown when a test is not finished.
ilTestPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI ilTestPageGUI: ilPublicUserProfile...
removeQuestion(int $question_id)
isTestFinishedToViewResults($active_id, $currentpass)
Returns true if an active user completed a test pass and did not start a new pass.
getUserData($ids)
Returns a data of all users specified by id list.
questionMoveUp($question_id)
Moves a question up in order.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
const NEWS_NOTICE
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
getEvaluationAdditionalFields()
Gets additional user fields that should be shown in the user evaluation.
static _getSolutionMaxPass(int $question_id, int $active_id)
Returns the maximum pass a users question solution.
getShowSolutionSuggested()
& getAllQuestions($pass=null)
Returns all questions of a test in test order.
isSkillServiceToBeConsidered()
Returns whether this test must consider skills, usually by providing appropriate extensions in the us...
exportXMLMetaData(&$a_xml_writer)
export content objects meta data to xml (see ilias_co.dtd)
static _getCountSystem($active_id)
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions
getResultsForActiveId(int $active_id)
const SCORE_REPORTING_DATE
ilTestEditPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI ilTestEditPageGUI: ilPublicUse...
applyDefaults($test_defaults)
Applies given test defaults to this test.
isOfferingQuestionHintsEnabled()
removeTestActives($activeIds)
Filesystem $filesystem_web
exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export media objects to xml (see ilias_co.dtd)
header include for all ilias files.
getAnsweredQuestionCount($active_id, $pass=null)
Retrieves the number of answered questions for a given user in a given test.
getAvailableDefaults()
Returns the available test defaults for the active user.
convertTimeToDateTimeImmutableIfNecessary(DateTimeImmutable|int|null $date_time)
static getInstanceByType(string $type)
static isSkillManagementGloballyActivated()
getAnswerFeedbackPoints()
canShowTestResults(ilTestSession $test_session)
createExportDirectory()
creates data directory for export files (data_dir/tst_data/tst_<id>/export, depending on data directo...
allObligationsAnswered()
checks wether all questions marked as obligatory were answered within the test pass with given testId...
removeTestResultsFromSoapLpAdministration($userIds)
getMarkSchema()
{ASS_MarkSchema}
getAggregatedResultsData()
Returns the aggregated test results.
static _lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object.
static _getObjectsByOperations( $a_obj_type, string $a_operation, int $a_usr_id=0, int $limit=0)
Get all objects of a specific type and check access This function is not recursive, instead it parses the serialized rbac_pa entries.
logAction($logtext="", $question_id=0)
Logs an action into the Test&Assessment log.
getStartingTimeOfParticipants()
Note, this function should only be used if absolutely necessary, since it perform joins on tables tha...
static getDataDir()
get data directory (outside webspace)
getLastFinishedPassTimestamp()
getShowSolutionSignature()
Returns if the signature field should be shown in the test results.
Basic GUI class for assessment questions.
static _lookupFinishedUserTests($a_user_id)
Gather all finished tests for user.
pcArrayShuffle($array)
Shuffles the values of a given array.
ilTestQuestionSetConfigFactory $question_set_config_factory
getMainSettingsRepository()
static _lookupDescription(int $obj_id)
getGamificationSettings()
static _getTestIDFromObjectID($object_id)
Returns the ILIAS test id for a given object id.
getInstantFeedbackSolution()
ASS_MarkSchema $mark_schema
removeQuestionFromSequences($questionId, $activeIds, ilTestReindexedSequencePositionMap $reindexedSequencePositionMap)
isHighscoreAnon()
Gets if the highscores should be displayed anonymized.
inviteGroup($group_id)
Invites all users of a group to a test.
isInstantFeedbackAnswerFixationEnabled()
prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output in tests.
storeActivationSettings(?bool $is_activation_limited=false, ?int $activation_starting_time=null, ?int $activation_ending_time=null, bool $activation_visibility=false,)
static _createImportDirectory()
creates data directory for import files (data_dir/tst_data/tst_<id>/import, depending on data directo...
duplicateQuestionForTest($question_id)
Takes a question and creates a copy of the question for use in the test.
isScoreReportingEnabled()
getAvailableQuestions($arr_filter, $completeonly=0)
Calculates the available questions for a test.
isForceInstantFeedbackEnabled()
& getTotalPointsPassedArray()
Returns an array with the total points of all users who passed the test This array could be used for ...
getQuestionDataset($question_id)
Returns the dataset for a given question id.
static ilTempnam(?string $a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
processCSVRow(mixed $row, bool $quote_all=false, string $separator=";")
Processes an array as a CSV row and converts the array values to correct CSV values.
getIntroductionSettings()
A news item can be created by different sources.
getGenericAnswerFeedback()
addToNewsOnOnline(bool $old_online_status, bool $new_online_status)
static getItem(int $ref_id)
buildIso8601PeriodForExportCompatibility(DateTimeImmutable $date_time)
isQuestionSetConfigured()
getActivationStartingTime()
int $activation_ending_time
getTextAnswer($active_id, $question_id, $pass=null)
Returns the text answer of a given user for a given question.
getScoreCutting()
Determines if the score of a question should be cut at 0 points or the score of the whole test...
getResultDetailsSettings()
getTitleFilenameCompliant()
returns the object title prepared to be used as a filename
bool $activation_visibility
getParticipantsForTestAndQuestion($test_id, $question_id)
Creates an associated array with all active id's for a given test and original question id...
setTmpCopyWizardCopyId(int $tmpCopyWizardCopyId)
static _getManualScoring()
Retrieve the manual scoring settings.
static _getAvailableTests($use_object_id=false)
Returns the available tests for the active user.
getInvitedParticipantList()
moveQuestions($move_questions, $target_index, $insert_mode)
Move questions to another position.
static getFirstNewsIdForContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="")
Get first new id of news set related to a certain context.
static getCompleteManualFeedback(int $question_id)
Retrieves the manual feedback for a question in a test.
exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export pages of test to xml (see ilias_co.dtd)
recalculateScores($preserve_manscoring=false)
clonePage(int $source_page_id)
ScoreSettingsRepository $score_settings_repo
deleteDefaults($test_default_id)
endingTimeReached()
Returns true if the ending time of a test is reached An ending time is not available for self assessm...
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
getActivationEndingTime()
const QUESTION_SET_TYPE_FIXED
getConcludingRemarksPageId()
withConcludingRemarksPageId(?int $concluding_remarks_page_id)
isActiveTestSubmitted($user_id=null)
returns if the active for user_id has been submitted
modifyExportIdentifier($a_tag, $a_param, $a_value)
Returns the installation id for a given identifier.
getQuestionType($question_id)
Returns the question type of a question with a given id.
const SCORE_REPORTING_IMMIDIATLY
static buildExamId($active_id, $pass, $test_obj_id=null)
xmlStartTag(string $tag, ?array $attrs=null, bool $empty=false, bool $encode=true, bool $escape=true)
Writes a starttag.
removeTestResultsByActiveIds($activeIds)
ilObjTestMainSettings $main_settings
& getCompleteWorkingTimeOfParticipants()
Returns the complete working time in seconds for all test participants.
& getCompleteEvaluationData($withStatistics=true, $filterby="", $filtertext="")
getProcessingTimeInSeconds($active_id="")
Returns the processing time for the test in seconds.
getNrOfResultsForPass($active_id, $pass)
Calculates the number of user results for a specific test pass.
ilComponentFactory $component_factory
setClientIP($user_id, $client_ip)
addQTIMaterial(ilXmlWriter &$xml_writer, ?int $page_id, string $material='')
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content)
isShowGradingStatusEnabled()
A class defining mark schemas for assessment test objects.
canShowSolutionPrintview($user_id=null)
getQuestionCountWithoutReloading()
getHighscoreScore()
Gets if the score column should be shown.
ILIAS TestQuestionPool QuestionInfoService $questioninfo
static getTestObjIdsWithActiveForUserId($userId)
isPluginActive($a_pname)
Checks wheather or not a question plugin with a given name is active.
isFollowupQuestionAnswerFixationEnabled()
& evalResultsOverviewOfParticipant($active_id)
Creates an associated array with the results for a given participant of a test.
saveAuthorToMetadata($author="")
Saves an authors name into the lifecycle metadata if no lifecycle metadata exists This will only be c...
moveQuestionAfterOLD($previous_question_id, $new_question_id)
static getManualFeedback(int $active_id, int $question_id, ?int $pass)
Retrieves the feedback comment for a question in a test if it is finalized.
moveQuestionAfter($question_to_move, $question_before)
getScoreSettingsRepository()
static insertInstIntoID(string $a_value)
inserts installation id into ILIAS id
retrieveMobsFromLegacyImports(string $text, array $mobs)
static lookupQuestionSetType($objId)
lookup-er for question set type
static lookupQuestionSetTypeByActiveId($active_id)
returns the question set type of test relating to passed active id
deliverPDFfromHTML($content, $title=null)
Delivers a PDF file from XHTML.
getDetailedTestResults($participants)
returns all test results for all participants
static getInstance(int $obj_id)
static clear(string $a_var)
isNrOfTriesReached($tries)
returns if number of tries are reached
& getQuestionsOfPass($active_id, $pass)
Retrieves all the assigned questions for a test participant in a given test pass. ...
getResultSummarySettings()
Class ilObjectActivation.
getMailNotificationContentType()
_getLastAccess(int $active_id)
isComplete(ilTestQuestionSetConfig $testQuestionSetConfig)
setAccessFilteredParticipantList(ilTestParticipantList $access_filtered_participant_list)
static set(string $a_var, $a_val)
Set a value.
withIntroductionPageId(?int $introduction_page_id)
static deleteRequestsByActiveIds($activeIds)
Deletes all hint requests relating to a testactive included in given active ids.
insertManualFeedback(int $active_id, int $question_id, int $pass, ?string $feedback, bool $finalized, array $feedback_old)
withGeneralSettings(ilObjTestSettingsGeneral $settings)
reindexFixedQuestionOrdering()
static _setImportDirectory($a_import_dir=null)
ilTestParticipantAccessFilterFactory $participant_access_filter
userLookupFullName($user_id, $overwrite_anonymity=false, $sorted_order=false, $suffix="")
Returns the full name of a test user according to the anonymity status.
getTestBehaviourSettings()
static _getActiveIdOfUser($user_id="", $test_id="")
static makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
isMaxProcessingTimeReached(int $starting_time, int $active_id)
Returns whether the maximum processing time for a test is reached or not.
static _getImportDirectory()
Get the import directory location of the test.
isPreviousSolutionReuseEnabled($active_id)
getAlwaysSendMailNotification()
getImagePath()
Returns the image path for web accessable images of a test The image path is under the CLIENT_WEB_DIR...
static getFeedbackClassNameByQuestionType(string $questionType)
static lookupExamId($active_id, $pass)
getParticipantFunctionalitySettings()
getPassScoring()
Gets the pass scoring type.