19declare(strict_types=1);
156 public function __construct(
int $id = 0,
bool $a_call_by_reference =
true)
162 $this->
ctrl = $DIC[
'ilCtrl'];
164 $this->
settings = $DIC[
'ilSetting'];
165 $this->bench =
$DIC[
'ilBench'];
166 $this->component_repository =
$DIC[
'component.repository'];
167 $this->component_factory =
$DIC[
'component.factory'];
168 $this->filesystem_web =
$DIC->filesystem()->web();
169 $this->lo_metadata =
$DIC->learningObjectMetadata();
172 $this->participant_access_filter = $local_dic[
'participant.access_filter.factory'];
173 $this->test_man_scoring_done_helper = $local_dic[
'scoring.manual.done_helper'];
174 $this->
logger = $local_dic[
'logging.logger'];
175 $this->log_viewer = $local_dic[
'logging.viewer'];
176 $this->global_settings_repo = $local_dic[
'settings.global.repository'];
177 $this->marks_repository = $local_dic[
'marks.repository'];
178 $this->questionrepository = $local_dic[
'question.general_properties.repository'];
179 $this->testrequest = $local_dic[
'request_data_collector'];
180 $this->participant_repository = $local_dic[
'participant.repository'];
181 $this->export_factory = $local_dic[
'exportimport.factory'];
182 $this->test_result_repository = $local_dic[
'results.data.repository'];
186 $this->
lng->loadLanguageModule(
"assessment");
187 $this->score_settings =
null;
194 $this->component_repository,
196 $this->questionrepository
202 return TestDIC::dic();
217 return $this->question_set_config_factory->getQuestionSetConfig();
240 $id = parent::create();
247 if (!parent::update()) {
259 $this->main_settings =
null;
260 $this->score_settings =
null;
261 $this->mark_schema =
null;
265 public function delete():
bool
268 if (!parent::delete()) {
279 $qsaImportFails->deleteRegisteredImportFails();
281 $sltImportFails->deleteRegisteredImportFails();
283 if ($this->
logger->isLoggingEnabled()) {
284 $this->
logger->logTestAdministrationInteraction(
285 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
287 $this->user->getId(),
290 AdditionalInformationGenerator::KEY_TEST_TITLE => $test_title = $this->title
302 $participantData->load($this->
getTestId());
305 $this->db->manipulateF(
306 "DELETE FROM tst_mark WHERE test_fi = %s",
311 $this->db->manipulateF(
312 "DELETE FROM tst_tests WHERE test_id = %s",
318 $directory = $tst_data_dir .
"/tst_" . $this->
getId();
319 if (is_dir($directory)) {
327 foreach ($mobs as $mob) {
345 if (!is_writable($tst_data_dir)) {
346 $this->
ilias->raiseError(
"Test Data Directory (" . $tst_data_dir
347 .
") not writeable.", $this->
ilias->error_obj->MESSAGE);
351 $tst_dir = $tst_data_dir .
"/tst_" . $this->
getId();
353 if (!@is_dir($tst_dir)) {
354 $this->
ilias->raiseError(
"Creation of Test Directory failed.", $this->
ilias->error_obj->MESSAGE);
357 $export_dir = $tst_dir .
"/export";
359 if (!@is_dir($export_dir)) {
360 $this->
ilias->raiseError(
"Creation of Export Directory failed.", $this->
ilias->error_obj->MESSAGE);
370 public function getExportFiles(
string $dir =
''): array
373 if (!@is_dir($dir) || !is_writable($dir)) {
378 foreach (
new DirectoryIterator($dir) as $file) {
382 if ($file->isDir()) {
386 $files[] = $file->getBasename();
406 if (!is_writable($tst_data_dir)) {
408 .
") not writeable.",
$ilias->error_obj->FATAL);
412 $tst_dir = $tst_data_dir .
"/tst_import";
414 if (!@is_dir($tst_dir)) {
441 if ($this->
isComplete($test_question_set_config)) {
445 $this->db->manipulateF(
446 'UPDATE tst_tests SET complete = %s WHERE test_id = %s',
448 [$complete, $this->test_id]
453 public function saveToDb(
bool $properties_only =
false): void
455 if ($this->test_id === -1) {
457 $next_id = $this->db->nextId(
'tst_tests');
462 'test_id' => [
'integer', $next_id],
463 'obj_fi' => [
'integer', $this->
getId()],
464 'created' => [
'integer', time()],
465 'tstamp' => [
'integer', time()],
470 $this->test_id = $next_id;
476 $aresult = $this->db->queryF(
477 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
478 [
'integer',
'integer',
'integer'],
481 while ($row = $this->db->fetchAssoc($aresult)) {
482 $this->db->manipulateF(
483 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
484 [
'integer',
'timestamp',
'integer'],
485 [1, date(
'Y-m-d H:i:s'), $row[
"active_id"]]
490 $aresult = $this->db->queryF(
491 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
492 [
'integer',
'integer',
'integer'],
495 while ($row = $this->db->fetchAssoc($aresult)) {
496 $this->db->manipulateF(
497 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
498 [
'integer',
'timestamp',
'integer'],
499 [0,
null, $row[
"active_id"]]
504 $aresult = $this->db->queryF(
505 "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
506 [
'integer',
'integer'],
509 while ($row = $this->db->fetchAssoc($aresult)) {
510 $this->db->manipulateF(
511 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
512 [
'integer',
'timestamp',
'integer'],
513 [0,
null, $row[
"active_id"]]
520 if ($properties_only) {
528 $this->marks_repository->storeMarkSchema($this->
getMarkSchema());
533 $this->db->manipulateF(
534 'DELETE FROM tst_test_question WHERE test_fi = %s',
538 foreach ($this->questions as $key => $value) {
539 $next_id = $this->db->nextId(
'tst_test_question');
540 $this->db->insert(
'tst_test_question', [
541 'test_question_id' => [
'integer', $next_id],
542 'test_fi' => [
'integer', $this->
getTestId()],
543 'question_fi' => [
'integer', $value],
544 'sequence' => [
'integer', $key],
545 'tstamp' => [
'integer', time()]
558 foreach ($question_ids as
$id) {
559 $question = assQuestion::instantiateQuestionGUI(
$id);
561 $title = $question->getObject()->getTitle();
563 while (in_array(
$title .
' (' . $i .
')', $question_titles)) {
567 $title .=
' (' . $i .
')';
569 $question_titles[] =
$title;
571 $new_id = $question->getObject()->duplicate(
false,
$title);
573 $clone = assQuestion::instantiateQuestionGUI($new_id);
574 $question = $clone->getObject();
575 $question->setObjId($this->
getId());
576 $clone->setObject($question);
577 $clone->getObject()->saveToDb();
591 $result = $this->db->queryF(
592 "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
593 [
'integer',
'integer'],
596 return $result->numRows();
601 $result = $this->db->queryF(
602 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
606 if ($result->numRows() === 1) {
607 $data = $this->db->fetchObject($result);
619 $this->questions = [];
621 if ($active_id === 0) {
624 if (is_null($pass)) {
627 $result = $this->db->queryF(
628 'SELECT tst_test_rnd_qst.* '
629 .
'FROM tst_test_rnd_qst, qpl_questions '
630 .
'WHERE tst_test_rnd_qst.active_fi = %s '
631 .
'AND qpl_questions.question_id = tst_test_rnd_qst.question_fi '
632 .
'AND tst_test_rnd_qst.pass = %s '
633 .
'ORDER BY sequence',
634 [
'integer',
'integer'],
638 $result = $this->db->queryF(
639 'SELECT tst_test_question.* '
640 .
'FROM tst_test_question, qpl_questions '
641 .
'WHERE tst_test_question.test_fi = %s '
642 .
'AND qpl_questions.question_id = tst_test_question.question_fi '
643 .
'ORDER BY sequence',
649 if ($this->test_id !== -1) {
651 while (
$data = $this->db->fetchAssoc($result)) {
652 $this->questions[$index++] =
$data[
"question_fi"];
659 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
660 if ($page_id !==
null) {
665 $this->
getMainSettings()->getIntroductionSettings()->getIntroductionText(),
672 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
673 if ($page_id ===
null) {
681 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
682 if ($page_id !==
null) {
686 $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksText()
692 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
693 if ($page_id ===
null) {
702 $page_object->setParentId($this->
getId());
703 $new_page_id = $page_object->createPageWithNextId();
704 (
new ilTestPage($source_page_id))->copy($new_page_id);
718 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getPostponedQuestionsMoveToEnd();
723 return $this->
getScoreSettings()->getResultSummarySettings()->getScoreReporting()->isReportingEnabled();
728 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled();
733 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled();
738 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled();
750 $result =
$ilDB->queryF(
751 "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",
755 if ($result->numRows()) {
756 $row =
$ilDB->fetchAssoc($result);
757 return $row[
"count_system"];
785 $result =
$ilDB->queryF(
786 "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",
790 if ($result->numRows()) {
791 $row =
$ilDB->fetchAssoc($result);
792 return (
int) $row[
"pass_scoring"];
804 $result =
$ilDB->queryF(
805 "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",
809 if ($result->numRows()) {
810 $row =
$ilDB->fetchAssoc($result);
811 return (
bool) $row[
"score_cutting"];
818 if ($this->mark_schema ===
null) {
819 $this->mark_schema = $this->marks_repository->getMarkSchemaFor($this->
getTestId());
828 $this->mark_schema =
null;
833 return $this->
getMainSettings()->getTestBehaviourSettings()->getNumberOfTries();
838 return $this->
getMainSettings()->getTestBehaviourSettings()->getBlockAfterPassedEnabled();
843 return $this->
getMainSettings()->getTestBehaviourSettings()->getKioskModeEnabled();
848 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowTitleInKioskMode();
852 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowParticipantNameInKioskMode();
857 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed();
862 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getQuestionTitleOutputMode();
867 $result = $this->db->queryF(
868 "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",
872 if ($result->numRows()) {
873 $row = $this->db->fetchAssoc($result);
874 $test_allows_reuse = $row[
"use_previous_answers"];
877 if ($test_allows_reuse ===
'1') {
878 $res = $this->
user->getPref(
"tst_use_previous_answers");
888 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
893 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
894 if ($processing_time ===
null
895 || $processing_time ===
''
896 || !preg_match(
'/(\d{2}):(\d{2}):(\d{2})/is', $processing_time, $matches)
911 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime() ??
'';
912 if (preg_match(
"/(\d{2}):(\d{2}):(\d{2})/", (
string) $processing_time, $matches)) {
914 return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
922 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTimeEnabled();
927 return $this->
getMainSettings()->getTestBehaviourSettings()->getResetProcessingTime();
932 return $this->
getMainSettings()->getAccessSettings()->getStartTimeEnabled();
937 $start_time = $this->
getMainSettings()->getAccessSettings()->getStartTime();
938 return $start_time !==
null ? $start_time->getTimestamp() : 0;
943 return $this->
getMainSettings()->getAccessSettings()->getEndTimeEnabled();
948 $end_time = $this->
getMainSettings()->getAccessSettings()->getEndTime();
949 return $end_time !==
null ? $end_time->getTimestamp() : 0;
954 return $this->
getMainSettings()->getAccessSettings()->getPasswordEnabled();
968 $this->test_result_repository
982 $participant_data->load($this->test_id);
984 $question->removeAllExistingSolutions();
991 $participant_data->getActiveIds(),
992 $this->reindexFixedQuestionOrdering()
998 $question->delete($question_id);
1007 if ($this->
logger->isLoggingEnabled()) {
1008 $this->
logger->logTestAdministrationInteraction(
1009 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1011 $this->user->getId(),
1012 TestAdministrationInteractionTypes::QUESTION_REMOVED_IN_CORRECTIONS,
1014 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question->getTitleForHTMLOutput(),
1015 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $question->getQuestion(),
1016 AdditionalInformationGenerator::KEY_QUESTION_ID => $question->getId(),
1017 AdditionalInformationGenerator::KEY_QUESTION_TYPE => $question->getQuestionType()
1035 $this->questionrepository
1038 foreach ($active_ids as $active_id) {
1040 $passSelector->setActiveId($active_id);
1042 foreach ($passSelector->getExistingPasses() as $pass) {
1043 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $pass);
1046 $test_sequence->removeQuestion($question_id, $reindexed_sequence_position_map);
1057 foreach ($question_ids as $question_id) {
1058 $this->removeQuestion((
int) $question_id);
1061 $this->reindexFixedQuestionOrdering();
1067 $question = self::_instanciateQuestion($question_id);
1068 $question_title = $question->getTitleForHTMLOutput();
1069 $question->delete($question_id);
1070 if ($this->
logger->isLoggingEnabled()) {
1071 $this->
logger->logTestAdministrationInteraction(
1072 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1074 $this->user->getId(),
1075 TestAdministrationInteractionTypes::QUESTION_REMOVED,
1077 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question_title
1082 }
catch (InvalidArgumentException
$e) {
1083 $this->
logger->error($e->getMessage());
1084 $this->
logger->error($e->getTraceAsString());
1098 $this->removeTestResultsByUserIds($user_ids);
1101 $participantData->setUserIdsFilter($user_ids);
1102 $participantData->load($this->getTestId());
1104 $this->removeTestActives($participantData->getActiveIds());
1107 if ($this->
logger->isLoggingEnabled()) {
1108 $this->
logger->logTestAdministrationInteraction(
1109 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1111 $this->user->getId(),
1112 TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
1114 AdditionalInformationGenerator::KEY_USERS => $participantData->getUserIds()
1126 $user_ids = array_map(
1130 $this->participant_repository->removeExtraTimeByUserId($this->getTestId(), $user_ids);
1133 if ($participant_data->
getUserIds() !== []) {
1136 if ($test_lp instanceof
ilTestLP) {
1137 $test_lp->setTestObject($this);
1138 $test_lp->resetLPDataForUserIds($participant_data->
getUserIds(),
false);
1141 $this->participant_repository->removeExtraTimeByUserId($this->getTestId(), $participant_data->
getUserIds());
1145 $this->removeTestActives($participant_data->
getActiveIds());
1147 $user_ids = array_map(
1151 $this->participant_repository->removeExtraTimeByUserId($this->getTestId(), $user_ids);
1154 if ($this->
logger->isLoggingEnabled()) {
1155 $this->
logger->logTestAdministrationInteraction(
1156 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1158 $this->user->getId(),
1159 TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
1161 AdditionalInformationGenerator::KEY_USERS => $participant_data->
getUserIds(),
1172 $participantData->setUserIdsFilter($user_ids);
1173 $participantData->load($this->getTestId());
1175 $in_user_ids = $this->db->in(
'usr_id', $participantData->getUserIds(),
false,
'integer');
1176 $this->db->manipulateF(
1177 "DELETE FROM usr_pref WHERE {$in_user_ids} AND keyword = %s",
1179 [
'tst_password_' . $this->getTestId()]
1182 if ($participantData->getActiveIds() !== []) {
1183 $this->removeTestResultsByActiveIds($participantData->getActiveIds());
1189 $in_active_ids = $this->db->in(
'active_fi', $active_ids,
false,
'integer');
1191 $this->db->manipulate(
"DELETE FROM tst_solutions WHERE {$in_active_ids}");
1192 $this->db->manipulate(
"DELETE FROM tst_qst_solved WHERE {$in_active_ids}");
1193 $this->db->manipulate(
"DELETE FROM tst_test_result WHERE {$in_active_ids}");
1194 $this->db->manipulate(
"DELETE FROM tst_pass_result WHERE {$in_active_ids}");
1195 $this->db->manipulate(
"DELETE FROM tst_result_cache WHERE {$in_active_ids}");
1196 $this->db->manipulate(
"DELETE FROM tst_sequence WHERE {$in_active_ids}");
1197 $this->db->manipulate(
"DELETE FROM tst_times WHERE {$in_active_ids}");
1198 $this->db->manipulate(
1200 .
' WHERE ' . $this->db->in(
'active_id', $active_ids,
false,
'integer')
1203 if ($this->isRandomTest()) {
1204 $this->db->manipulate(
"DELETE FROM tst_test_rnd_qst WHERE {$in_active_ids}");
1207 $this->test_result_repository->removeTestResults($active_ids, $this->
getId());
1209 foreach ($active_ids as $active_id) {
1211 if (is_dir(
CLIENT_WEB_DIR .
"/assessment/tst_" . $this->getTestId() .
"/$active_id")) {
1222 $IN_activeIds = $this->db->in(
'active_id', $active_ids,
false,
'integer');
1223 $this->db->manipulate(
"DELETE FROM tst_active WHERE $IN_activeIds");
1236 $result = $this->db->queryF(
1237 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1238 [
'integer',
'integer'],
1239 [$this->getTestId(), $question_id]
1241 $data = $this->db->fetchObject($result);
1242 if (
$data->sequence > 1) {
1244 $result = $this->db->queryF(
1245 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1246 [
'integer',
'integer'],
1247 [$this->getTestId(),
$data->sequence - 1]
1249 $data_previous = $this->db->fetchObject($result);
1251 $this->db->manipulateF(
1252 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1253 [
'integer',
'integer'],
1254 [
$data->sequence, $data_previous->test_question_id]
1257 $this->db->manipulateF(
1258 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1259 [
'integer',
'integer'],
1260 [
$data->sequence - 1,
$data->test_question_id]
1263 $this->loadQuestions();
1275 $current_question_result = $this->db->queryF(
1276 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1277 [
'integer',
'integer'],
1278 [$this->getTestId(), $question_id]
1280 $current_question_data = $this->db->fetchObject($current_question_result);
1281 $next_question_result = $this->db->queryF(
1282 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1283 [
'integer',
'integer'],
1284 [$this->getTestId(), $current_question_data->sequence + 1]
1286 if ($this->db->numRows($next_question_result) === 1) {
1288 $next_question_data = $this->db->fetchObject($next_question_result);
1290 $this->db->manipulateF(
1291 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1292 [
'integer',
'integer'],
1293 [$current_question_data->sequence, $next_question_data->test_question_id]
1296 $this->db->manipulateF(
1297 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1298 [
'integer',
'integer'],
1299 [$current_question_data->sequence + 1, $current_question_data->test_question_id]
1302 $this->loadQuestions();
1314 $duplicate_id = $question->duplicate(
true,
'',
'', -1, $this->
getId());
1315 return $duplicate_id;
1321 $duplicate_id = $question_id;
1323 $duplicate_id = $this->duplicateQuestionForTest($question_id);
1327 $result = $this->db->queryF(
1328 "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
1330 [$this->getTestId()]
1334 if ($result->numRows() == 1) {
1335 $data = $this->db->fetchObject($result);
1336 $sequence =
$data->seq + 1;
1339 $next_id = $this->db->nextId(
'tst_test_question');
1340 $this->db->manipulateF(
1341 "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
1342 [
'integer',
'integer',
'integer',
'integer',
'integer'],
1343 [$next_id, $this->getTestId(), $duplicate_id, $sequence, time()]
1346 $this->db->manipulateF(
1347 "DELETE FROM tst_active WHERE test_fi = %s",
1349 [$this->getTestId()]
1351 $this->loadQuestions();
1352 $this->saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
1354 if ($this->
logger->isLoggingEnabled()) {
1355 $this->
logger->logTestAdministrationInteraction(
1356 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1358 $this->user->getId(),
1359 TestAdministrationInteractionTypes::QUESTION_ADDED,
1361 AdditionalInformationGenerator::KEY_QUESTION_ID => $question_id
1363 ->toLog($this->logger->getAdditionalInformationGenerator())
1368 return $duplicate_id;
1374 if ($this->getQuestionSetType() === self::QUESTION_SET_TYPE_FIXED) {
1375 $result = $this->db->queryF(
1376 'SELECT qpl_questions.title FROM tst_test_question, qpl_questions '
1377 .
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id '
1378 .
'ORDER BY tst_test_question.sequence',
1380 [$this->getTestId()]
1382 while ($row = $this->db->fetchAssoc($result)) {
1383 array_push($titles, $row[
'title']);
1399 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
1400 $result = $this->db->queryF(
1401 'SELECT qpl_questions.title, qpl_questions.question_id '
1402 .
'FROM tst_test_question, qpl_questions '
1403 .
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id '
1404 .
'ORDER BY tst_test_question.sequence',
1406 [$this->getTestId()]
1408 while ($row = $this->db->fetchAssoc($result)) {
1409 $titles[$row[
'question_id']] = $row[
"title"];
1427 switch ($this->getTitleOutput()) {
1434 return $this->
lng->txt(
"ass_question") .
' ' . $nr;
1436 return $this->
lng->txt(
"ass_question");
1440 $txt = $this->
lng->txt(
"ass_question") .
' ' . $nr;
1442 $txt = $this->
lng->txt(
"ass_question");
1444 if ($points !=
'') {
1445 $lngv = $this->
lng->txt(
'points');
1447 $lngv = $this->
lng->txt(
'point');
1449 $txt .=
' - ' . $points .
' ' . $lngv;
1455 return $this->
lng->txt(
"ass_question");
1469 $result = $this->db->queryF(
1470 "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",
1474 $row = $this->db->fetchObject($result);
1486 $existing_questions = [];
1487 $active_id = $this->getActiveIdOfUser($this->
user->getId());
1488 if ($this->isRandomTest()) {
1489 if (is_null($pass)) {
1492 $result = $this->db->queryF(
1493 "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",
1494 [
'integer',
'integer'],
1498 $result = $this->db->queryF(
1499 "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",
1501 [$this->getTestId()]
1504 while (
$data = $this->db->fetchObject($result)) {
1505 if (
$data->original_id ===
null) {
1509 array_push($existing_questions,
$data->original_id);
1511 return $existing_questions;
1523 if ($question_id < 1) {
1526 $result = $this->db->queryF(
1527 "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",
1531 if ($result->numRows() == 1) {
1532 $data = $this->db->fetchObject($result);
1533 return $data->type_tag;
1547 $next_id = $this->db->nextId(
'tst_times');
1548 $affectedRows = $this->db->manipulateF(
1549 "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
1550 [
'integer',
'integer',
'timestamp',
'timestamp',
'integer',
'integer'],
1551 [$next_id, $active_id, date(
"Y-m-d H:i:s"), date(
"Y-m-d H:i:s"), $pass, time()]
1564 $affectedRows = $this->db->manipulateF(
1565 "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
1566 [
'timestamp',
'integer',
'integer'],
1567 [date(
'Y-m-d H:i:s'), time(), $times_id]
1579 if (is_null($pass)) {
1580 $result = $this->db->queryF(
1581 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1582 [
'integer',
'integer'],
1586 $result = $this->db->queryF(
1587 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1588 [
'integer',
'integer'],
1593 while ($row = $this->db->fetchAssoc($result)) {
1594 array_push($result_array, $row[
"question_fi"]);
1596 return $result_array;
1610 return ((($currentpass > 0) && ($num == 0)) || $this->isTestFinished($active_id)) ?
true :
false;
1621 if ($this->isRandomTest()) {
1622 $active_id = $this->getActiveIdOfUser($this->
user->getId());
1623 if ($active_id ===
null) {
1626 $this->loadQuestions($active_id, $pass);
1627 if (count($this->questions) === 0) {
1630 if (is_null($pass)) {
1631 $pass = self::_getPass($active_id);
1633 $result = $this->db->queryF(
1634 "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'),
1635 [
'integer',
'integer'],
1639 if (count($this->questions) === 0) {
1642 $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'));
1645 while ($row = $this->db->fetchAssoc($result)) {
1646 $result_array[$row[
"question_id"]] = $row;
1648 return $result_array;
1666 if (is_array($tst_access_code) &&
1668 isset($tst_access_code[$this->getTestId()]) &&
1669 $tst_access_code[$this->getTestId()] !==
'') {
1670 $result = $this->db->queryF(
1671 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1672 [
'integer',
'integer',
'text'],
1673 [
$user_id, $this->test_id, $tst_access_code[$this->getTestId()]]
1675 } elseif ((
string) $anonymous_id !==
'') {
1676 $result = $this->db->queryF(
1677 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1678 [
'integer',
'integer',
'text'],
1679 [
$user_id, $this->test_id, $anonymous_id]
1685 $result = $this->db->queryF(
1686 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s',
1687 [
'integer',
'integer'],
1692 if ($result->numRows()) {
1693 $row = $this->db->fetchAssoc($result);
1694 return (
int) $row[
'active_id'];
1704 $ilUser =
$DIC[
'ilUser'];
1712 $result =
$ilDB->queryF(
1713 "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
1714 [
'integer',
'integer'],
1717 if ($result->numRows()) {
1718 $row =
$ilDB->fetchAssoc($result);
1719 return $row[
"active_id"];
1733 $keys = array_keys($array);
1736 foreach ($keys as $key) {
1737 $result[$key] = $array[$key];
1750 ?
int $attempt =
null,
1751 bool $ordered_sequence =
false,
1752 bool $consider_hidden_questions =
true,
1753 bool $consider_optional_questions =
true
1755 $test_result = $this->test_result_repository->getTestResult($active_id);
1757 if ($test_result ===
null) {
1758 $test_result = $this->test_result_repository->updateTestResultCache($active_id);
1761 if ($attempt ===
null) {
1762 $attempt = $test_result->getAttempt();
1766 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $attempt);
1768 $test_sequence->setConsiderHiddenQuestionsEnabled($consider_hidden_questions);
1769 $test_sequence->setConsiderOptionalQuestionsEnabled($consider_optional_questions);
1771 $test_sequence->loadFromDb();
1772 $test_sequence->loadQuestions();
1774 if ($ordered_sequence) {
1775 $sequence = $test_sequence->getOrderedSequenceQuestions();
1777 $sequence = $test_sequence->getUserSequenceQuestions();
1784 tst_test_result.question_fi,
1785 tst_test_result.points reached,
1786 tst_test_result.answered answered,
1787 tst_manual_fb.finalized_evaluation finalized_evaluation
1789 FROM tst_test_result
1791 LEFT JOIN tst_solutions
1792 ON tst_solutions.active_fi = tst_test_result.active_fi
1793 AND tst_solutions.question_fi = tst_test_result.question_fi
1795 LEFT JOIN tst_manual_fb
1796 ON tst_test_result.active_fi = tst_manual_fb.active_fi
1797 AND tst_test_result.question_fi = tst_manual_fb.question_fi
1799 WHERE tst_test_result.active_fi = %s
1800 AND tst_test_result.pass = %s
1803 $solutionresult = $this->db->queryF(
1805 [
'integer',
'integer'],
1806 [$active_id, $attempt]
1809 while ($row = $this->db->fetchAssoc($solutionresult)) {
1810 $arr_results[ $row[
'question_fi'] ] = $row;
1813 $result = $this->db->query(
1814 'SELECT qpl_questions.*, qpl_qst_type.type_tag, qpl_sol_sug.question_fi has_sug_sol' . PHP_EOL
1815 .
'FROM qpl_qst_type, qpl_questions' . PHP_EOL
1816 .
'LEFT JOIN qpl_sol_sug' . PHP_EOL
1817 .
'ON qpl_sol_sug.question_fi = qpl_questions.question_id' . PHP_EOL
1818 .
'WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi' . PHP_EOL
1819 .
'AND ' . $this->db->in(
'qpl_questions.question_id', $sequence,
false,
'integer')
1824 while ($row = $this->db->fetchAssoc($result)) {
1825 if (!isset($arr_results[ $row[
'question_id'] ])) {
1826 $percentvalue = 0.0;
1829 $row[
'points'] ? $arr_results[$row[
'question_id']][
'reached'] / $row[
'points'] : 0
1832 if ($percentvalue < 0) {
1833 $percentvalue = 0.0;
1839 'max' => round($row[
'points'], 2),
1840 'reached' => round($arr_results[$row[
'question_id']][
'reached'] ?? 0, 2),
1841 'percent' => sprintf(
'%2.2f ', ($percentvalue) * 100) .
'%',
1843 'type' => $row[
'type_tag'],
1844 'qid' => $row[
'question_id'],
1845 'original_id' => $row[
'original_id'],
1846 'workedthrough' => isset($arr_results[$row[
'question_id']]) ? 1 : 0,
1847 'answered' => $arr_results[$row[
'question_id']][
'answered'] ?? 0,
1848 'finalized_evaluation' => $arr_results[$row[
'question_id']][
'finalized_evaluation'] ?? 0,
1851 $unordered[ $row[
'question_id'] ] =
$data;
1859 foreach ($sequence as $qid) {
1862 $pass_max += round($unordered[$qid][
'max'], 2);
1863 $pass_reached += round($unordered[$qid][
'reached'], 2);
1864 $found[] = $unordered[$qid];
1867 if ($this->getScoreCutting() == 1) {
1868 if ($pass_reached < 0) {
1873 $found[
'pass'][
'total_max_points'] = $pass_max;
1874 $found[
'pass'][
'total_reached_points'] = $pass_reached;
1875 $found[
'pass'][
'percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
1876 $found[
'pass'][
'num_workedthrough'] = count($arr_results);
1877 $found[
'pass'][
'num_questions_total'] = count($unordered);
1879 $found[
'test'][
'total_max_points'] = $test_result->getMaxPoints();
1880 $found[
'test'][
'total_reached_points'] = $test_result->getReachedPoints();
1881 $found[
'test'][
'result_pass'] = $attempt;
1882 $found[
'test'][
'result_tstamp'] = $test_result->getTimestamp();
1883 $found[
'test'][
'passed'] = $test_result->isPassed();
1896 $result = $this->db->queryF(
1897 'SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s',
1899 [$this->getTestId()]
1901 $row = $this->db->fetchAssoc($result);
1902 return $row[
'total'];
1913 $result = $this->db->queryF(
1914 "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",
1915 [
'integer',
'integer'],
1919 while ($row = $this->db->fetchAssoc($result)) {
1920 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
1929 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
1938 $time += ($epoch_2 - $epoch_1);
1951 return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
1963 $result = $this->db->queryF(
1964 "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",
1970 while ($row = $this->db->fetchAssoc($result)) {
1971 if (!array_key_exists($row[
"active_fi"], $times)) {
1972 $times[$row[
"active_fi"]] = 0;
1974 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
1983 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
1992 $times[$row[
"active_fi"]] += ($epoch_2 - $epoch_1);
2005 $result = $this->db->queryF(
2006 "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",
2007 [
'integer',
'integer'],
2008 [$this->getTestId(), $active_id]
2011 while ($row = $this->db->fetchAssoc($result)) {
2012 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2021 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2030 $time += ($epoch_2 - $epoch_1);
2040 return $this->test_result_repository->fetchWorkingTime($active_id, $pass);
2049 $test_result = &$this->getTestResult($active_id, $pass);
2050 $result = $this->db->queryF(
2051 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
2058 while ($row = $this->db->fetchObject($result)) {
2059 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2068 if (!$first_visit) {
2069 $first_visit = $epoch_1;
2071 if ($epoch_1 < $first_visit) {
2072 $first_visit = $epoch_1;
2074 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2084 $last_visit = $epoch_2;
2086 if ($epoch_2 > $last_visit) {
2087 $last_visit = $epoch_2;
2089 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2092 foreach ($times as $key => $value) {
2093 $max_time += $value;
2095 if ((!$test_result[
"test"][
"total_reached_points"]) or (!$test_result[
"test"][
"total_max_points"])) {
2098 $percentage = ($test_result[
"test"][
"total_reached_points"] / $test_result[
"test"][
"total_max_points"]) * 100.0;
2099 if ($percentage < 0) {
2103 $mark_obj = $this->getMarkSchema()->getMatchingMark($percentage);
2104 $first_date = getdate($first_visit);
2105 $last_date = getdate($last_visit);
2106 $qworkedthrough = 0;
2107 foreach ($test_result as $key => $value) {
2108 if (preg_match(
"/\d+/", $key)) {
2109 $qworkedthrough += $value[
"workedthrough"];
2112 if (!$qworkedthrough) {
2115 $atimeofwork = $max_time / $qworkedthrough;
2121 if ($mark_obj !==
null) {
2122 $result_mark = $mark_obj->getShortName();
2124 if ($mark_obj->getPassed()) {
2130 $percent_worked_through = 0;
2131 if (count($this->questions)) {
2132 $percent_worked_through = $qworkedthrough / count($this->questions);
2135 "qworkedthrough" => $qworkedthrough,
2136 "qmax" => count($this->questions),
2137 "pworkedthrough" => $percent_worked_through,
2138 "timeofwork" => $max_time,
2139 "atimeofwork" => $atimeofwork,
2140 "firstvisit" => $first_date,
2141 "lastvisit" => $last_date,
2142 "resultspoints" => $test_result[
"test"][
"total_reached_points"],
2143 "maxpoints" => $test_result[
"test"][
"total_max_points"],
2144 "resultsmarks" => $result_mark,
2145 "passed" => $passed,
2146 "distancemedian" =>
"0"
2148 foreach ($test_result as $key => $value) {
2149 if (preg_match(
"/\d+/", $key)) {
2150 $result_array[$key] = $value;
2153 return $result_array;
2165 $totalpoints_array = [];
2166 $all_users = $this->evalTotalParticipantsArray();
2167 foreach ($all_users as $active_id => $user_name) {
2168 $test_result = &$this->getTestResult($active_id);
2169 $reached = $test_result[
"test"][
"total_reached_points"];
2170 $total = $test_result[
"test"][
"total_max_points"];
2171 $percentage = $total != 0 ? $reached / $total : 0;
2172 $mark = $this->getMarkSchema()->getMatchingMark($percentage * 100.0);
2174 if ($mark !==
null && $mark->getPassed()) {
2175 array_push($totalpoints_array, $test_result[
"test"][
"total_reached_points"]);
2178 return $totalpoints_array;
2188 $result = $this->db->queryF(
2189 "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",
2191 [$this->getTestId()]
2193 $persons_array = [];
2194 while ($row = $this->db->fetchAssoc($result)) {
2195 $name = $this->
lng->txt(
"anonymous");
2196 $fullname = $this->
lng->txt(
"anonymous");
2198 if (!$this->getAnonymity()) {
2199 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2200 $name = $this->
lng->txt(
"deleted_user");
2201 $fullname = $this->
lng->txt(
"deleted_user");
2202 $login = $this->
lng->txt(
"unknown");
2204 $login = $row[
"login"];
2206 $name = $this->
lng->txt(
"anonymous");
2207 $fullname = $this->
lng->txt(
"anonymous");
2209 $name = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2210 $fullname = trim($row[
"title"] .
" " . $row[
"firstname"] .
" " . $row[
"lastname"]);
2214 $persons_array[$row[
"active_id"]] = [
2216 "fullname" => $fullname,
2220 return $persons_array;
2225 $result = $this->db->queryF(
2226 "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),
2228 [$this->getTestId()]
2230 $persons_array = [];
2231 while ($row = $this->db->fetchAssoc($result)) {
2232 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row[
"active_id"])) {
2236 if ($this->getAnonymity()) {
2237 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"anonymous");
2239 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2240 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"deleted_user");
2243 $persons_array[$row[
"active_id"]] = $row[
"lastname"];
2245 $persons_array[$row[
"active_id"]] = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2250 return $persons_array;
2255 $result = $this->db->queryF(
2256 'SELECT tst_active.user_fi, tst_active.active_id, usr_data.login, '
2257 .
'usr_data.firstname, usr_data.lastname, usr_data.title FROM tst_active '
2258 .
'LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id '
2259 .
'WHERE tst_active.test_fi = %s '
2260 .
'ORDER BY usr_data.lastname ' . strtoupper($name_sort_order),
2262 [$this->getTestId()]
2264 $persons_array = [];
2265 while ($row = $this->db->fetchAssoc($result)) {
2266 if ($this->getAnonymity()) {
2267 $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
"anonymous")];
2269 if (strlen($row[
'firstname'] . $row[
'lastname'] . $row[
"title"]) == 0) {
2270 $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
'deleted_user')];
2273 $persons_array[$row[
'active_id']] = [
'name' => $row[
'lastname']];
2275 $persons_array[$row[
'active_id']] = [
2276 'name' => trim($row[
'lastname'] .
', ' . $row[
'firstname']
2277 .
' ' . $row[
'title']),
2278 'login' => $row[
'login']
2284 return $persons_array;
2289 if ($this->isRandomTest()) {
2290 $this->db->setLimit($this->getQuestionCount(), 0);
2291 $result = $this->db->queryF(
2292 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, '
2293 .
'tst_test_rnd_qst.pass, qpl_questions.points '
2294 .
'FROM tst_test_rnd_qst, qpl_questions '
2295 .
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id '
2296 .
'AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence',
2301 $result = $this->db->queryF(
2302 'SELECT tst_test_question.sequence, tst_test_question.question_fi, '
2303 .
'qpl_questions.points '
2304 .
'FROM tst_test_question, tst_active, qpl_questions '
2305 .
'WHERE tst_test_question.question_fi = qpl_questions.question_id '
2306 .
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
2312 if ($result->numRows()) {
2313 while ($row = $this->db->fetchAssoc($result)) {
2314 array_push($qtest, $row);
2322 if ($this->isRandomTest()) {
2323 $this->db->setLimit($this->getQuestionCount(), 0);
2324 $result = $this->db->queryF(
2325 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, '
2326 .
'qpl_questions.points '
2327 .
'FROM tst_test_rnd_qst, qpl_questions '
2328 .
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id '
2329 .
'AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s '
2330 .
'ORDER BY tst_test_rnd_qst.sequence',
2331 [
'integer',
'integer'],
2335 $result = $this->db->queryF(
2336 'SELECT tst_test_question.sequence, tst_test_question.question_fi, '
2337 .
'qpl_questions.points '
2338 .
'FROM tst_test_question, tst_active, qpl_questions '
2339 .
'WHERE tst_test_question.question_fi = qpl_questions.question_id '
2340 .
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
2346 if ($result->numRows()) {
2347 while ($row = $this->db->fetchAssoc($result)) {
2348 array_push($qpass, $row);
2356 return $this->access_filtered_participant_list;
2361 $this->access_filtered_participant_list = $access_filtered_participant_list;
2367 $list->initializeFromDbRows($this->getTestParticipants());
2369 return $list->getAccessFilteredList(
2370 $this->participant_access_filter->getAccessStatisticsUserFilter($this->getRefId())
2380 $list->initializeFromDbRows($this->getTestParticipants());
2381 if ($this->getAnonymity()) {
2382 return $list->getAllUserIds();
2384 return $list->getAccessFilteredList(
2385 $this->participant_access_filter->getAnonOnlyParticipantsUserFilter($this->getRefId())
2392 ->getEvaluationData();
2397 $question_set_type = $this->lookupQuestionSetTypeByActiveId($active_id);
2399 switch ($question_set_type) {
2401 $res = $this->db->queryF(
2403 SELECT tst_test_rnd_qst.pass,
2404 COUNT(tst_test_rnd_qst.question_fi) qcount,
2405 SUM(qpl_questions.points) qsum
2407 FROM tst_test_rnd_qst,
2410 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
2411 AND tst_test_rnd_qst.active_fi = %s
2414 GROUP BY tst_test_rnd_qst.active_fi,
2415 tst_test_rnd_qst.pass
2417 [
'integer',
'integer'],
2423 $res = $this->db->queryF(
2425 SELECT COUNT(tst_test_question.question_fi) qcount,
2426 SUM(qpl_questions.points) qsum
2428 FROM tst_test_question,
2432 WHERE tst_test_question.question_fi = qpl_questions.question_id
2433 AND tst_test_question.test_fi = tst_active.test_fi
2434 AND tst_active.active_id = %s
2436 GROUP BY tst_test_question.test_fi
2444 throw new ilTestException(
"not supported question set type: $question_set_type");
2447 $row = $this->db->fetchAssoc(
$res);
2449 if (is_array($row)) {
2450 return [
"count" => $row[
"qcount"],
"points" => $row[
"qsum"]];
2453 return [
"count" => 0,
"points" => 0];
2458 $data = $this->getUnfilteredEvaluationData();
2459 $data->setFilter($filterby, $filtertext);
2480 || $firstname . $lastname ===
'') {
2481 return $this->
lng->txt(
'deleted_user');
2484 if ($this->getAnonymity()) {
2485 return $this->
lng->txt(
'anonymous');
2492 return trim($lastname .
', ' . $firstname);
2497 $query =
"SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi";
2499 if ($active_ids_to_filter !==
null && $active_ids_to_filter !== []) {
2500 $query .=
" AND " . $this->db->in(
'active_id', $active_ids_to_filter,
false,
'integer');
2503 $result = $this->db->queryF($query, [
'integer'], [$this->getTestId()]);
2505 while ($row = $this->db->fetchObject($result)) {
2506 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2515 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2524 if (isset($times[$row->active_fi])) {
2525 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2527 $times[$row->active_fi] = ($epoch_2 - $epoch_1);
2532 foreach ($times as $value) {
2533 $max_time += $value;
2539 return (
int) round($max_time /
$counter);
2549 bool $use_object_id =
false,
2550 ?
bool $equal_points =
false,
2551 bool $could_be_offline =
false,
2552 bool $show_path =
false,
2553 bool $with_questioncount =
false,
2554 string $permission =
'read'
2558 $equal_points ?? false,
2561 $with_questioncount,
2603 if ((!$question_type) and ($question_id > 0)) {
2604 $question_type = $this->getQuestionType($question_id);
2607 if (!strlen($question_type)) {
2611 if ($question_id > 0) {
2612 $question_gui = assQuestion::instantiateQuestionGUI($question_id);
2614 $question_type_gui = $question_type .
'GUI';
2615 $question_gui =
new $question_type_gui();
2618 return $question_gui;
2629 if (strcmp((
string) $question_id,
"") !== 0) {
2640 public function moveQuestions(array $move_questions,
int $target_index,
int $insert_mode): void
2642 $this->questions = array_values($this->questions);
2643 $array_pos = array_search($target_index, $this->questions);
2644 if ($insert_mode == 0) {
2645 $part1 = array_slice($this->questions, 0, $array_pos);
2646 $part2 = array_slice($this->questions, $array_pos);
2647 } elseif ($insert_mode == 1) {
2648 $part1 = array_slice($this->questions, 0, $array_pos + 1);
2649 $part2 = array_slice($this->questions, $array_pos + 1);
2651 foreach ($move_questions as $question_id) {
2652 if (!(array_search($question_id, $part1) ===
false)) {
2653 unset($part1[array_search($question_id, $part1)]);
2655 if (!(array_search($question_id, $part2) ===
false)) {
2656 unset($part2[array_search($question_id, $part2)]);
2659 $part1 = array_values($part1);
2660 $part2 = array_values($part2);
2661 $new_array = array_values(array_merge($part1, $move_questions, $part2));
2662 $this->questions = [];
2664 foreach ($new_array as $question_id) {
2665 $this->questions[
$counter] = $question_id;
2668 $this->saveQuestionsToDb();
2670 if ($this->
logger->isLoggingEnabled()) {
2671 $this->
logger->logTestAdministrationInteraction(
2672 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
2674 $this->user->getId(),
2675 TestAdministrationInteractionTypes::QUESTION_MOVED,
2677 AdditionalInformationGenerator::KEY_QUESTION_ORDER => $this->questions
2694 if ($this->isStartingTimeEnabled() && $this->getStartingTime() != 0) {
2696 if ($now < $this->getStartingTime()) {
2712 if ($this->isEndingTimeEnabled() && $this->getEndingTime() != 0) {
2714 if ($now > $this->getEndingTime()) {
2730 if (count($available_pools)) {
2731 $available =
" AND " . $this->db->in(
'qpl_questions.obj_fi', $available_pools,
false,
'integer');
2735 if ($completeonly) {
2736 $available .=
" AND qpl_questions.complete = " . $this->db->quote(
"1",
'text');
2740 if (is_array($arr_filter)) {
2741 if (array_key_exists(
'title', $arr_filter) && strlen($arr_filter[
'title'])) {
2742 $where .=
" AND " . $this->db->like(
'qpl_questions.title',
'text',
"%%" . $arr_filter[
'title'] .
"%%");
2744 if (array_key_exists(
'description', $arr_filter) && strlen($arr_filter[
'description'])) {
2745 $where .=
" AND " . $this->db->like(
'qpl_questions.description',
'text',
"%%" . $arr_filter[
'description'] .
"%%");
2747 if (array_key_exists(
'author', $arr_filter) && strlen($arr_filter[
'author'])) {
2748 $where .=
" AND " . $this->db->like(
'qpl_questions.author',
'text',
"%%" . $arr_filter[
'author'] .
"%%");
2750 if (array_key_exists(
'type', $arr_filter) && strlen($arr_filter[
'type'])) {
2751 $where .=
" AND qpl_qst_type.type_tag = " . $this->db->quote($arr_filter[
'type'],
'text');
2753 if (array_key_exists(
'qpl', $arr_filter) && strlen($arr_filter[
'qpl'])) {
2754 $where .=
" AND " . $this->db->like(
'object_data.title',
'text',
"%%" . $arr_filter[
'qpl'] .
"%%");
2758 $original_ids = &$this->getExistingQuestions();
2759 $original_clause =
" qpl_questions.original_id IS NULL";
2760 if (count($original_ids)) {
2761 $original_clause =
" qpl_questions.original_id IS NULL AND " . $this->db->in(
'qpl_questions.question_id', $original_ids,
true,
'integer');
2764 $query_result = $this->db->query(
"
2765 SELECT qpl_questions.*, qpl_questions.tstamp,
2766 qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name,
2767 object_data.title parent_title
2768 FROM qpl_questions, qpl_qst_type, object_data
2769 WHERE $original_clause $available
2770 AND object_data.obj_id = qpl_questions.obj_fi
2771 AND qpl_questions.tstamp > 0
2772 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
2777 if ($query_result->numRows()) {
2778 while ($row = $this->db->fetchAssoc($query_result)) {
2781 if (!$row[
'plugin']) {
2782 $row[
'ttype' ] = $this->
lng->txt($row[
"type_tag" ]);
2788 $plugin = $this->component_repository->getPluginByName($row[
'plugin_name']);
2793 $pl = $this->component_factory->getPlugin(
$plugin->getId());
2794 $row[
'ttype' ] = $pl->getQuestionTypeTranslation();
2808 if (($importdir =
ilSession::get(
'path_to_container_import_file')) ===
null) {
2814 $this->saveToDb(
true);
2816 $main_settings = $this->getMainSettings();
2826 $introduction_settings = $introduction_settings->withIntroductionEnabled(
false);
2827 foreach ($assessment->objectives as
$objectives) {
2829 $introduction_settings = $this->addIntroductionToSettingsFromImport(
2830 $introduction_settings,
2831 $this->qtiMaterialToArray($material),
2841 $finishing_settings = $this->addConcludingRemarksToSettingsFromImport(
2842 $finishing_settings,
2843 $this->qtiMaterialToArray(
2851 $score_settings = $this->getScoreSettings();
2858 foreach ($assessment->qtimetadata as $metadata) {
2859 switch ($metadata[
"label"]) {
2860 case "solution_details":
2861 $result_details_settings = $result_details_settings->withShowPassDetails((
bool) $metadata[
"entry"]);
2863 case "show_solution_list_comparison":
2864 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
2866 case "print_bs_with_res":
2867 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
2870 $this->saveAuthorToMetadata($metadata[
"entry"]);
2873 $test_behaviour_settings = $test_behaviour_settings->withNumberOfTries((
int) $metadata[
"entry"]);
2875 case 'block_after_passed':
2876 $test_behaviour_settings = $test_behaviour_settings->withBlockAfterPassedEnabled((
bool) $metadata[
'entry']);
2878 case "pass_waiting":
2879 $test_behaviour_settings = $test_behaviour_settings->withPassWaiting($metadata[
"entry"]);
2882 $test_behaviour_settings = $test_behaviour_settings->withKioskMode((
int) $metadata[
"entry"]);
2884 case 'show_introduction':
2885 $introduction_settings = $introduction_settings->withIntroductionEnabled((
bool) $metadata[
'entry']);
2887 case "showfinalstatement":
2888 case 'show_concluding_remarks':
2889 $finishing_settings = $finishing_settings->withConcludingRemarksEnabled((
bool) $metadata[
"entry"]);
2891 case 'exam_conditions':
2892 $introduction_settings = $introduction_settings->withExamConditionsCheckboxEnabled($metadata[
'entry'] ===
'1');
2894 case "highscore_enabled":
2895 $gamification_settings = $gamification_settings->withHighscoreEnabled((
bool) $metadata[
"entry"]);
2897 case "highscore_anon":
2898 $gamification_settings = $gamification_settings->withHighscoreAnon((
bool) $metadata[
"entry"]);
2900 case "highscore_achieved_ts":
2901 $gamification_settings = $gamification_settings->withHighscoreAchievedTS((
bool) $metadata[
"entry"]);
2903 case "highscore_score":
2904 $gamification_settings = $gamification_settings->withHighscoreScore((
bool) $metadata[
"entry"]);
2906 case "highscore_percentage":
2907 $gamification_settings = $gamification_settings->withHighscorePercentage((
bool) $metadata[
"entry"]);
2909 case "highscore_wtime":
2910 $gamification_settings = $gamification_settings->withHighscoreWTime((
bool) $metadata[
"entry"]);
2912 case "highscore_own_table":
2913 $gamification_settings = $gamification_settings->withHighscoreOwnTable((
bool) $metadata[
"entry"]);
2915 case "highscore_top_table":
2916 $gamification_settings = $gamification_settings->withHighscoreTopTable((
bool) $metadata[
"entry"]);
2918 case "highscore_top_num":
2919 $gamification_settings = $gamification_settings->withHighscoreTopNum((
int) $metadata[
"entry"]);
2921 case "use_previous_answers":
2922 $participant_functionality_settings = $participant_functionality_settings->withUsePreviousAnswerAllowed((
bool) $metadata[
"entry"]);
2924 case 'question_list_enabled':
2925 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
'entry']);
2927 case "title_output":
2928 $question_behaviour_settings = $question_behaviour_settings->withQuestionTitleOutputMode((
int) $metadata[
"entry"]);
2930 case "question_set_type":
2931 if ($metadata[
'entry'] === self::QUESTION_SET_TYPE_RANDOM) {
2932 $this->questions = [];
2934 $general_settings = $general_settings->withQuestionSetType($metadata[
"entry"]);
2937 $general_settings = $general_settings->withAnonymity((
bool) $metadata[
"entry"]);
2939 case "results_presentation":
2940 $result_details_settings = $result_details_settings->withResultsPresentation((
int) $metadata[
"entry"]);
2942 case "reset_processing_time":
2943 $test_behaviour_settings = $test_behaviour_settings->withResetProcessingTime($metadata[
"entry"] ===
'1');
2945 case "answer_feedback_points":
2946 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackPointsEnabled((
bool) $metadata[
"entry"]);
2948 case "answer_feedback":
2949 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackGenericEnabled((
bool) $metadata[
"entry"]);
2951 case 'instant_feedback_specific':
2952 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSpecificEnabled((
bool) $metadata[
'entry']);
2954 case "instant_verification":
2955 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSolutionEnabled((
bool) $metadata[
"entry"]);
2957 case "force_instant_feedback":
2958 $question_behaviour_settings = $question_behaviour_settings->withForceInstantFeedbackOnNextQuestion((
bool) $metadata[
"entry"]);
2960 case "follow_qst_answer_fixation":
2961 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnNextQuestionEnabled((
bool) $metadata[
"entry"]);
2963 case "instant_feedback_answer_fixation":
2964 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnInstantFeedbackEnabled((
bool) $metadata[
"entry"]);
2967 case "suspend_test_allowed":
2968 $participant_functionality_settings = $participant_functionality_settings->withSuspendTestAllowed((
bool) $metadata[
"entry"]);
2970 case "sequence_settings":
2971 $participant_functionality_settings = $participant_functionality_settings->withPostponedQuestionsMoveToEnd((
bool) $metadata[
"entry"]);
2974 $participant_functionality_settings = $participant_functionality_settings->withQuestionMarkingEnabled((
bool) $metadata[
"entry"]);
2976 case "fixed_participants":
2977 $access_settings = $access_settings->withFixedParticipants((
bool) $metadata[
"entry"]);
2979 case "score_reporting":
2980 if ($metadata[
'entry'] !==
null) {
2981 $result_summary_settings = $result_summary_settings->withScoreReporting(
2982 ScoreReportingTypes::tryFrom((
int) $metadata[
'entry']) ?? ScoreReportingTypes::SCORE_REPORTING_DISABLED
2986 case "shuffle_questions":
2987 $question_behaviour_settings = $question_behaviour_settings->withShuffleQuestions((
bool) $metadata[
"entry"]);
2989 case "count_system":
2990 $scoring_settings = $scoring_settings->withCountSystem((
int) $metadata[
"entry"]);
2992 case "mailnotification":
2993 $finishing_settings = $finishing_settings->withMailNotificationContentType((
int) $metadata[
"entry"]);
2996 $finishing_settings = $finishing_settings->withAlwaysSendMailNotification((
bool) $metadata[
"entry"]);
2998 case "exportsettings":
2999 $result_details_settings = $result_details_settings->withExportSettings((
int) $metadata[
"entry"]);
3001 case "score_cutting":
3002 $scoring_settings = $scoring_settings->withScoreCutting((
int) $metadata[
"entry"]);
3005 $access_settings = $access_settings->withPasswordEnabled(
3006 $metadata[
"entry"] !==
null && $metadata[
"entry"] !==
''
3007 )->withPassword($metadata[
"entry"]);
3009 case 'ip_range_from':
3010 if ($metadata[
'entry'] !==
'') {
3011 $access_settings = $access_settings->withIpRangeFrom($metadata[
'entry']);
3015 if ($metadata[
'entry'] !==
'') {
3016 $access_settings = $access_settings->withIpRangeTo($metadata[
'entry']);
3019 case "pass_scoring":
3020 $scoring_settings = $scoring_settings->withPassScoring((
int) $metadata[
"entry"]);
3022 case 'pass_deletion_allowed':
3023 $result_summary_settings = $result_summary_settings->withPassDeletionAllowed((
bool) $metadata[
"entry"]);
3025 case "usr_pass_overview_mode":
3026 $participant_functionality_settings = $participant_functionality_settings->withUsrPassOverviewMode((
int) $metadata[
"entry"]);
3028 case "question_list":
3029 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
"entry"]);
3032 case "reporting_date":
3033 $reporting_date = $this->buildDateTimeImmutableFromPeriod($metadata[
'entry']);
3034 if ($reporting_date !==
null) {
3035 $result_summary_settings = $result_summary_settings->withReportingDate($reporting_date);
3038 case 'enable_processing_time':
3039 $test_behaviour_settings = $test_behaviour_settings->withProcessingTimeEnabled((
bool) $metadata[
'entry']);
3041 case "processing_time":
3042 $test_behaviour_settings = $test_behaviour_settings->withProcessingTime($metadata[
'entry']);
3044 case "starting_time":
3045 $starting_time = $this->buildDateTimeImmutableFromPeriod($metadata[
'entry']);
3046 if ($starting_time !==
null) {
3047 $access_settings = $access_settings->withStartTime($starting_time)
3048 ->withStartTimeEnabled(
true);
3052 $ending_time = $this->buildDateTimeImmutableFromPeriod($metadata[
'entry']);
3053 if ($ending_time !==
null) {
3054 $access_settings = $access_settings->withEndTime($ending_time)
3055 ->withStartTimeEnabled(
true);
3058 case "enable_examview":
3059 $finishing_settings = $finishing_settings->withShowAnswerOverview((
bool) $metadata[
"entry"]);
3061 case 'redirection_mode':
3062 $finishing_settings = $finishing_settings->withRedirectionMode(
3063 RedirectionModes::tryFrom($metadata[
'entry'] ?? 0) ?? RedirectionModes::NONE
3066 case 'redirection_url':
3067 $finishing_settings = $finishing_settings->withRedirectionUrl($metadata[
'entry']);
3069 case 'examid_in_test_pass':
3070 $test_behaviour_settings = $test_behaviour_settings->withExamIdInTestAttemptEnabled((
bool) $metadata[
'entry']);
3072 case 'examid_in_test_res':
3073 $result_details_settings = $result_details_settings->withShowExamIdInTestResults((
bool) $metadata[
"entry"]);
3075 case 'skill_service':
3076 $additional_settings = $additional_settings->withSkillsServiceEnabled((
bool) $metadata[
'entry']);
3078 case 'show_grading_status':
3079 $result_summary_settings = $result_summary_settings->withShowGradingStatusEnabled((
bool) $metadata[
"entry"]);
3081 case 'show_grading_mark':
3082 $result_summary_settings = $result_summary_settings->withShowGradingMarkEnabled((
bool) $metadata[
"entry"]);
3085 $question_behaviour_settings = $question_behaviour_settings->withAutosaveEnabled((
bool) $metadata[
'entry']);
3087 case 'autosave_ival':
3088 $question_behaviour_settings = $question_behaviour_settings->withAutosaveInterval((
int) $metadata[
'entry']);
3090 case 'show_summary':
3091 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled(($metadata[
'entry'] & 1) > 0)
3092 ->withUsrPassOverviewMode((
int) $metadata[
'entry']);
3095 case 'hide_info_tab':
3096 $additional_settings = $additional_settings->withHideInfoTab($metadata[
'entry'] ===
'1');
3098 if (preg_match(
"/mark_step_\d+/", $metadata[
"label"])) {
3099 $xmlmark = $metadata[
"entry"];
3100 preg_match(
"/<short>(.*?)<\/short>/", $xmlmark, $matches);
3101 $mark_short = $matches[1];
3102 preg_match(
"/<official>(.*?)<\/official>/", $xmlmark, $matches);
3103 $mark_official = $matches[1];
3104 preg_match(
"/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
3105 $mark_percentage = (float) $matches[1];
3106 preg_match(
"/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
3107 $mark_passed = (bool) $matches[1];
3108 $mark_steps[] =
new Mark($mark_short, $mark_official, $mark_percentage, $mark_passed);
3111 $this->mark_schema = $this->getMarkSchema()->withMarkSteps($mark_steps);
3113 $this->getObjectProperties()->storePropertyTitleAndDescription(
3114 $this->getObjectProperties()->getPropertyTitleAndDescription()
3118 $this->addToNewsOnOnline(
false, $this->getObjectProperties()->getPropertyIsOnline()->getIsOnline());
3119 $main_settings = $main_settings
3121 ->withIntroductionSettings($introduction_settings)
3122 ->withAccessSettings($access_settings)
3123 ->withParticipantFunctionalitySettings($participant_functionality_settings)
3124 ->withTestBehaviourSettings($test_behaviour_settings)
3125 ->withQuestionBehaviourSettings($question_behaviour_settings)
3126 ->withFinishingSettings($finishing_settings)
3127 ->withAdditionalSettings($additional_settings);
3128 $this->getMainSettingsRepository()->store($main_settings);
3129 $this->main_settings = $main_settings;
3131 $score_settings = $score_settings
3133 ->withScoringSettings($scoring_settings)
3134 ->withResultDetailsSettings($result_details_settings)
3135 ->withResultSummarySettings($result_summary_settings);
3136 $this->getScoreSettingsRepository()->store($score_settings);
3137 $this->score_settings = $score_settings;
3138 $this->loadFromDb();
3147 $text = $material[
'text'];
3148 $mobs = $material[
'mobs'];
3149 if (str_starts_with($text,
'<PageObject>')) {
3150 $text = $this->replaceMobsInPageImports(
3152 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
3154 $text = $this->replaceFilesInPageImports(
3156 $mappings[
'components/ILIAS/File'][
'file'] ?? []
3159 $page_object->setParentId($this->
getId());
3160 $page_object->setXMLContent($text);
3161 $new_page_id = $page_object->createPageWithNextId();
3165 $text = $this->retrieveMobsFromLegacyImports($text, $mobs, $importdir);
3180 $file_to_import =
ilSession::
get(
'path_to_import_file');
3181 $text = $material[
'text'];
3182 $mobs = $material[
'mobs'];
3183 if (str_starts_with($text,
'<PageObject>')) {
3184 $text = $this->replaceMobsInPageImports(
3186 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
3188 $text = $this->replaceFilesInPageImports(
3190 $mappings[
'components/ILIAS/File'][
'file'] ?? []
3193 $page_object->setParentId($this->
getId());
3194 $page_object->setXMLContent($text);
3195 $new_page_id = $page_object->createPageWithNextId();
3199 $text = $this->retrieveMobsFromLegacyImports($text, $mobs, $importdir);
3216 preg_match_all(
'/il_(\d+)_mob_(\d+)/', $text, $matches);
3217 foreach ($matches[0] as $index => $match) {
3218 if (empty($mappings[$matches[2][$index]])) {
3221 $text = str_replace($match,
"il__mob_{$mappings[$matches[2][$index]]}", $text);
3229 preg_match_all(
'/il_(\d+)_file_(\d+)/', $text, $matches);
3230 foreach ($matches[0] as $index => $match) {
3231 if (empty($mappings[$matches[2][$index]])) {
3234 $text = str_replace($match,
"il__file_{$mappings[$matches[2][$index]]}", $text);
3241 foreach ($mobs as $mob) {
3242 $importfile = $importdir . DIRECTORY_SEPARATOR . $mob[
'uri'];
3243 if (file_exists($importfile)) {
3248 'src="' . $mob[
'mob'] .
'"',
3249 'src="' .
'il_' .
IL_INST_ID .
'_mob_' . $media_object->getId() .
'"',
3266 $main_settings = $this->getMainSettings();
3269 $a_xml_writer->xmlHeader();
3270 $a_xml_writer->xmlSetDtdDef(
"<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
3271 $a_xml_writer->xmlStartTag(
"questestinterop");
3274 "ident" =>
"il_" .
IL_INST_ID .
"_tst_" . $this->getTestId(),
3277 $a_xml_writer->xmlStartTag(
"assessment", $attrs);
3278 $a_xml_writer->xmlElement(
"qticomment",
null, $this->getDescription());
3281 $a_xml_writer->xmlElement(
3284 $this->getProcessingTimeForXML()
3288 $a_xml_writer->xmlStartTag(
"qtimetadata");
3289 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3290 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ILIAS_VERSION");
3291 $a_xml_writer->xmlElement(
"fieldentry",
null,
ILIAS_VERSION);
3292 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3294 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3295 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"anonymity");
3296 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $main_settings->
getGeneralSettings()->getAnonymity()));
3297 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3299 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3300 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"question_set_type");
3301 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getGeneralSettings()->getQuestionSetType());
3302 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3304 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3305 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"sequence_settings");
3307 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3309 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3310 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"author");
3311 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getAuthor());
3312 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3314 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3315 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"reset_processing_time");
3316 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getTestBehaviourSettings()->getResetProcessingTime());
3317 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3319 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3320 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"count_system");
3321 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getCountSystem());
3322 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3324 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3325 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"score_cutting");
3326 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getScoreCutting());
3327 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3329 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3330 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"password");
3331 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getPassword() ??
'');
3332 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3334 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3335 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ip_range_from");
3336 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getIpRangeFrom());
3337 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3339 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3340 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ip_range_to");
3341 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getIpRangeTo());
3342 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3344 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3345 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"pass_scoring");
3346 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getPassScoring());
3347 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3349 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3350 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'pass_deletion_allowed');
3351 $a_xml_writer->xmlElement(
'fieldentry',
null, (
int) $this->isPassDeletionAllowed());
3352 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3354 if ($this->getScoreSettings()->getResultSummarySettings()->getReportingDate() !==
null) {
3355 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3356 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"reporting_date");
3357 $a_xml_writer->xmlElement(
3360 $this->buildIso8601PeriodForExportCompatibility(
3361 $this->getScoreSettings()->getResultSummarySettings()->getReportingDate(),
3364 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3367 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3368 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"nr_of_tries");
3369 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getNumberOfTries()));
3370 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3372 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3373 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'block_after_passed');
3374 $a_xml_writer->xmlElement(
'fieldentry',
null, (
int) $main_settings->
getTestBehaviourSettings()->getBlockAfterPassedEnabled());
3375 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3377 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3378 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"pass_waiting");
3380 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3382 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3383 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"kiosk");
3384 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getKioskMode()));
3385 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3387 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3388 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"redirection_mode");
3389 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getFinishingSettings()->getRedirectionMode()->value);
3390 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3392 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3393 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"redirection_url");
3394 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getFinishingSettings()->getRedirectionUrl());
3395 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3397 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3398 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"use_previous_answers");
3400 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3402 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3403 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'question_list_enabled');
3405 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3407 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3408 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"title_output");
3409 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $main_settings->
getQuestionBehaviourSettings()->getQuestionTitleOutputMode()));
3410 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3412 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3413 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"results_presentation");
3414 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $this->getScoreSettings()->getResultDetailsSettings()->getResultsPresentation()));
3415 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3417 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3418 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"examid_in_test_pass");
3419 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getExamIdInTestAttemptEnabled()));
3420 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3422 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3423 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"examid_in_test_res");
3424 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $this->getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults()));
3425 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3427 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3428 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"usr_pass_overview_mode");
3430 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3432 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3433 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"score_reporting");
3434 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $this->getScoreSettings()->getResultSummarySettings()->getScoreReporting()->value));
3435 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3437 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3438 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_solution_list_comparison");
3439 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $this->score_settings->getResultDetailsSettings()->getShowSolutionListComparison());
3440 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3442 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3443 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_verification");
3444 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled()));
3445 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3447 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3448 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"answer_feedback");
3449 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled()));
3450 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3452 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3453 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_specific");
3454 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled()));
3455 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3457 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3458 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"answer_feedback_points");
3459 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled()));
3460 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3462 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3463 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"follow_qst_answer_fixation");
3464 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled());
3465 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3467 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3468 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_answer_fixation");
3469 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled());
3470 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3472 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3473 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"force_instant_feedback");
3474 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion());
3475 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3477 $highscore_metadata = [
3478 'highscore_enabled' => [
'value' => $this->getHighscoreEnabled()],
3479 'highscore_anon' => [
'value' => $this->getHighscoreAnon()],
3480 'highscore_achieved_ts' => [
'value' => $this->getHighscoreAchievedTS()],
3481 'highscore_score' => [
'value' => $this->getHighscoreScore()],
3482 'highscore_percentage' => [
'value' => $this->getHighscorePercentage()],
3483 'highscore_wtime' => [
'value' => $this->getHighscoreWTime()],
3484 'highscore_own_table' => [
'value' => $this->getHighscoreOwnTable()],
3485 'highscore_top_table' => [
'value' => $this->getHighscoreTopTable()],
3486 'highscore_top_num' => [
'value' => $this->getHighscoreTopNum()],
3488 foreach ($highscore_metadata as $label =>
$data) {
3489 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3490 $a_xml_writer->xmlElement(
"fieldlabel",
null, $label);
3491 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d",
$data[
'value']));
3492 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3495 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3496 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"suspend_test_allowed");
3498 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3500 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3501 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_marker");
3503 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3505 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3506 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"fixed_participants");
3507 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getAccessSettings()->getFixedParticipants()));
3508 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3510 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3511 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_introduction");
3512 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getIntroductionSettings()->getIntroductionEnabled()));
3513 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3515 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3516 $a_xml_writer->xmlElement(
"fieldlabel",
null,
'exam_conditions');
3517 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getIntroductionSettings()->getExamConditionsCheckboxEnabled()));
3518 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3520 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3521 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_concluding_remarks");
3522 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getFinishingSettings()->getConcludingRemarksEnabled()));
3523 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3525 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3526 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mailnotification");
3527 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getFinishingSettings()->getMailNotificationContentType());
3528 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3530 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3531 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mailnottype");
3532 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getFinishingSettings()->getAlwaysSendMailNotification());
3533 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3535 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3536 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"exportsettings");
3537 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getExportSettings());
3538 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3540 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3541 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"shuffle_questions");
3542 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getQuestionBehaviourSettings()->getShuffleQuestions()));
3543 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3545 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3546 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"processing_time");
3548 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3550 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3551 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"enable_examview");
3552 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getFinishingSettings()->getShowAnswerOverview());
3553 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3555 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3556 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"skill_service");
3557 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getAdditionalSettings()->getSkillsServiceEnabled());
3558 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3560 if ($this->getInstantFeedbackSolution() == 1) {
3562 "solutionswitch" =>
"Yes"
3567 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs,
null);
3569 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3570 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_grading_status");
3571 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $this->isShowGradingStatusEnabled());
3572 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3574 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3575 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_grading_mark");
3576 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $this->isShowGradingMarkEnabled());
3577 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3579 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3580 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'hide_info_tab');
3581 $a_xml_writer->xmlElement(
'fieldentry',
null, (
int) $this->getMainSettings()->getAdditionalSettings()->getHideInfoTab());
3582 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3584 if ($this->getStartingTime() > 0) {
3585 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3586 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"starting_time");
3587 $a_xml_writer->xmlElement(
3590 $this->buildIso8601PeriodForExportCompatibility(
3591 (
new DateTimeImmutable())->setTimestamp($this->getStartingTime()),
3594 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3597 if ($this->getEndingTime() > 0) {
3598 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3599 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ending_time");
3600 $a_xml_writer->xmlElement(
3603 $this->buildIso8601PeriodForExportCompatibility(
3604 (
new DateTimeImmutable())->setTimestamp($this->getEndingTime()),
3607 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3610 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3611 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"autosave");
3613 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3615 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3616 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"autosave_ival");
3618 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3620 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3621 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_specific");
3622 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled());
3623 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3625 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3626 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_answer_fixation");
3627 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled());
3628 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3630 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3631 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"enable_processing_time");
3632 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getTestBehaviourSettings()->getProcessingTimeEnabled());
3633 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3635 foreach ($this->getMarkSchema()->getMarkSteps() as $index => $mark) {
3636 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3637 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mark_step_$index");
3638 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
3639 "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
3640 $mark->getShortName(),
3641 $mark->getOfficialName(),
3642 $mark->getMinimumLevel(),
3645 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3647 $a_xml_writer->xmlEndTag(
"qtimetadata");
3650 $introduction = $page_id !==
null
3651 ? (
new ilTestPage($page_id))->getXMLContent()
3654 $a_xml_writer->xmlStartTag(
"objectives");
3655 $this->addQTIMaterial($a_xml_writer, $page_id, $introduction);
3656 $a_xml_writer->xmlEndTag(
"objectives");
3658 if ($this->getInstantFeedbackSolution() == 1) {
3660 "solutionswitch" =>
"Yes"
3665 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs,
null);
3667 if (strlen($this->getFinalStatement())) {
3669 $concluding_remarks = $page_id !==
null
3670 ? (
new ilTestPage($page_id))->getXMLContent()
3673 $a_xml_writer->xmlStartTag(
"presentation_material");
3674 $a_xml_writer->xmlStartTag(
"flow_mat");
3675 $this->addQTIMaterial($a_xml_writer, $page_id, $concluding_remarks);
3676 $a_xml_writer->xmlEndTag(
"flow_mat");
3677 $a_xml_writer->xmlEndTag(
"presentation_material");
3683 $a_xml_writer->xmlElement(
"section", $attrs,
null);
3684 $a_xml_writer->xmlEndTag(
"assessment");
3685 $a_xml_writer->xmlEndTag(
"questestinterop");
3687 $xml = $a_xml_writer->xmlDumpMem(
false);
3693 return $date_time->setTimezone(
new DateTimeZone(
'UTC'))->format(
'\PY\Yn\Mj\D\TG\Hi\Ms\S');
3698 if ($period ===
null) {
3701 if (preg_match(
"/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $period, $matches)) {
3702 return new DateTimeImmutable(
3704 "%02d-%02d-%02d %02d:%02d:%02d",
3712 new \DateTimeZone(
'UTC')
3724 public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog): void
3726 $this->mob_ids = [];
3729 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Page Objects");
3730 $this->bench->start(
"ContentObjectExport",
"exportPageObjects");
3731 $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
3732 $this->bench->stop(
"ContentObjectExport",
"exportPageObjects");
3733 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Page Objects");
3736 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Media Objects");
3737 $this->bench->start(
"ContentObjectExport",
"exportMediaObjects");
3738 $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
3739 $this->bench->stop(
"ContentObjectExport",
"exportMediaObjects");
3740 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Media Objects");
3743 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export File Items");
3744 $this->bench->start(
"ContentObjectExport",
"exportFileItems");
3745 $this->exportFileItems($a_target_dir, $expLog);
3746 $this->bench->stop(
"ContentObjectExport",
"exportFileItems");
3747 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export File Items");
3757 if ($a_tag ==
"Identifier" && $a_param ==
"Entry") {
3773 foreach ($this->questions as $question_id) {
3774 $this->bench->start(
"ContentObjectExport",
"exportPageObject");
3775 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Page Object " . $question_id);
3778 $a_xml_writer->xmlStartTag(
"PageObject", $attrs);
3782 $this->bench->start(
"ContentObjectExport",
"exportPageObject_XML");
3784 $page_object->buildDom();
3785 $page_object->insertInstIntoIDs((
string) $inst);
3786 $mob_ids = $page_object->collectMediaObjects(
false);
3788 $xml = $page_object->getXMLFromDom(
false,
false,
false,
"",
true);
3789 $xml = str_replace(
"&",
"&", $xml);
3790 $a_xml_writer->appendXML($xml);
3791 $page_object->freeDom();
3792 unset($page_object);
3794 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_XML");
3797 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectMedia");
3799 foreach ($mob_ids as $mob_id) {
3800 $this->mob_ids[$mob_id] = $mob_id;
3802 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectMedia");
3805 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
3807 foreach ($file_ids as $file_id) {
3808 $this->file_ids[$file_id] = $file_id;
3810 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
3812 $a_xml_writer->xmlEndTag(
"PageObject");
3815 $this->bench->stop(
"ContentObjectExport",
"exportPageObject");
3824 foreach ($this->mob_ids as $mob_id) {
3825 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Media Object " . $mob_id);
3827 $target_dir = $a_target_dir . DIRECTORY_SEPARATOR .
'objects'
3828 . DIRECTORY_SEPARATOR .
'il_' .
IL_INST_ID .
'_mob_' . $mob_id;
3831 $media_obj->exportXML($a_xml_writer, (
int) $a_inst);
3832 foreach ($media_obj->getMediaItems() as $item) {
3833 $stream = $item->getLocationStream();
3834 file_put_contents($target_dir . DIRECTORY_SEPARATOR . $item->getLocation(), $stream);
3848 foreach ($this->file_ids as $file_id) {
3849 $expLog->write(date(
"[y-m-d H:i:s] ") .
"File Item " . $file_id);
3850 $file_dir = $target_dir .
'/objects/il_' .
IL_INST_ID .
'_file_' . $file_id;
3852 $file_obj =
new ilObjFile((
int) $file_id,
false);
3853 $source_file = $file_obj->getFile($file_obj->getVersion());
3854 if (!is_file($source_file)) {
3855 $source_file = $file_obj->getFile();
3857 if (is_file($source_file)) {
3858 copy($source_file, $file_dir .
'/' . $file_obj->getFileName());
3877 $this->saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
3879 if ($this->participantDataExist()) {
3880 $this->recalculateScores(
true);
3889 $total = $this->evalTotalPersons();
3890 $results_summary_settings = $this->getScoreSettings()->getResultSummarySettings();
3892 || $results_summary_settings->getScoreReporting()->isReportingEnabled() ===
false) {
3896 if ($results_summary_settings->getScoreReporting() === ScoreReportingTypes::SCORE_REPORTING_DATE) {
3897 return $results_summary_settings->getReportingDate()
3898 >=
new DateTimeImmutable(
'now',
new DateTimeZone(
'UTC'));
3915 $path_to_lifecycle = $this->lo_metadata->paths()->custom()->withNextStep(
'lifeCycle')->get();
3916 $path_to_authors = $this->lo_metadata->paths()->authors();
3918 $reader = $this->lo_metadata->read($this->
getId(), 0, $this->getType(), $path_to_lifecycle);
3919 if (!is_null($reader->allData($path_to_lifecycle)->current())) {
3923 if ($author ===
'') {
3924 $author = $this->
user->getFullname();
3926 $this->lo_metadata->manipulate($this->
getId(), 0, $this->getType())
3927 ->prepareCreateOrUpdate($path_to_authors, $author)
3936 $this->saveAuthorToMetadata();
3948 $path_to_authors = $this->lo_metadata->paths()->authors();
3949 $author_data = $this->lo_metadata->read($this->
getId(), 0, $this->getType(), $path_to_authors)
3950 ->allData($path_to_authors);
3952 return $this->lo_metadata->dataHelper()->makePresentableAsList(
', ', ...$author_data);
3966 $lo_metadata =
$DIC->learningObjectMetadata();
3968 $path_to_authors = $lo_metadata->paths()->authors();
3969 $author_data = $lo_metadata->read($obj_id, 0,
"tst", $path_to_authors)
3970 ->allData($path_to_authors);
3972 return $lo_metadata->dataHelper()->makePresentableAsList(
',', ...$author_data);
3984 $ilUser =
$DIC[
'ilUser'];
3987 $tests = array_slice(
3995 if (count($tests)) {
3998 if ($use_object_id) {
4000 $result_array[$obj_id] = $titles[
$ref_id];
4006 return $result_array;
4019 $this->loadFromDb();
4021 $new_obj = parent::cloneObject($target_id, $copy_id, $omit_tree);
4022 $new_obj->setTmpCopyWizardCopyId($copy_id);
4023 $this->cloneMetaData($new_obj);
4025 $new_obj->saveToDb();
4026 $new_obj->addToNewsOnOnline(
false, $new_obj->getObjectProperties()->getPropertyIsOnline()->getIsOnline());
4027 $this->getMainSettingsRepository()->store(
4028 $this->getMainSettings()->withTestId($new_obj->getTestId())
4029 ->withIntroductionSettings(
4030 $this->getMainSettings()->getIntroductionSettings()->withIntroductionPageId(
4031 $this->cloneIntroduction()
4032 )->withTestId($new_obj->getTestId())
4033 )->withFinishingSettings(
4034 $this->getMainSettings()->getFinishingSettings()->withConcludingRemarksPageId(
4035 $this->cloneConcludingRemarks()
4036 )->withTestId($new_obj->getTestId())
4039 $this->getScoreSettingsRepository()->store(
4040 $this->getScoreSettings()->withTestId($new_obj->getTestId())
4042 $this->marks_repository->storeMarkSchema(
4043 $this->getMarkSchema()->withTestId($new_obj->getTestId())
4046 $new_obj->setTemplate($this->getTemplate());
4055 $templateRepository,
4059 $cloneAction->cloneCertificate($this, $new_obj);
4061 $this->question_set_config_factory->getQuestionSetConfig()->cloneQuestionSetRelatedData($new_obj);
4062 $new_obj->saveQuestionsToDb();
4065 $skillLevelThresholdList->setTestId($this->getTestId());
4066 $skillLevelThresholdList->loadFromDb();
4067 $skillLevelThresholdList->cloneListForTest($new_obj->getTestId());
4070 $obj_settings->cloneSettings($new_obj->getId());
4072 if ($new_obj->getTestLogger()->isLoggingEnabled()) {
4073 $new_obj->getTestLogger()->logTestAdministrationInteraction(
4074 $new_obj->getTestLogger()->getInteractionFactory()->buildTestAdministrationInteraction(
4075 $new_obj->getRefId(),
4076 $this->user->getId(),
4077 TestAdministrationInteractionTypes::NEW_TEST_CREATED,
4090 if ($this->isRandomTest()) {
4096 $this->component_repository,
4098 $this->questionrepository
4101 $questionSetConfig->loadFromDb();
4103 if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
4110 $sourcePoolDefinitionList->loadDefinitions();
4112 if (is_int($sourcePoolDefinitionList->getQuestionAmount())) {
4113 $num = $sourcePoolDefinitionList->getQuestionAmount();
4115 } elseif (is_int($questionSetConfig->getQuestionAmountPerTest())) {
4116 $num = $questionSetConfig->getQuestionAmountPerTest();
4119 $this->loadQuestions();
4120 $num = count($this->questions);
4128 if ($this->isRandomTest()) {
4129 return $this->getQuestionCount();
4131 return count($this->questions);
4146 $result =
$ilDB->queryF(
4147 "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
4151 if ($result->numRows()) {
4152 $row =
$ilDB->fetchAssoc($result);
4153 $object_id = $row[
"obj_fi"];
4170 $result =
$ilDB->queryF(
4171 "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",
4175 if ($result->numRows()) {
4176 $row =
$ilDB->fetchAssoc($result);
4177 $object_id = $row[
"obj_fi"];
4194 $result =
$ilDB->queryF(
4195 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
4199 if ($result->numRows()) {
4200 $row =
$ilDB->fetchAssoc($result);
4201 $test_id = $row[
"test_id"];
4216 if (($active_id) && ($question_id)) {
4217 if ($pass ===
null) {
4220 if ($pass ===
null) {
4223 $query = $this->db->queryF(
4224 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
4225 [
'integer',
'integer',
'integer'],
4226 [$active_id, $question_id, $pass]
4228 $result = $this->db->fetchAll($query);
4229 if (count($result) == 1) {
4230 return $result[0][
"value1"];
4247 $result = $this->db->queryF(
4248 "SELECT question_text FROM qpl_questions WHERE question_id = %s",
4252 if ($result->numRows() == 1) {
4253 $row = $this->db->fetchAssoc($result);
4254 $res = $row[
"question_text"];
4263 $participant_list->initializeFromDbRows($this->getTestParticipants());
4265 return $participant_list;
4278 if ($this->getAnonymity()) {
4280 $result = $this->db->queryF(
4281 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
4282 "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 " .
4283 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4284 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4286 [
'text',
'text',
'text',
'integer',
'integer'],
4287 [
'', $this->
lng->txt(
'anonymous'),
'', $this->getTestId(),
$user_id]
4290 $result = $this->db->queryF(
4291 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
4292 "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 " .
4293 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4294 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4296 [
'text',
'text',
'text',
'integer'],
4297 [
'', $this->
lng->txt(
'anonymous'),
'', $this->getTestId()]
4302 $result = $this->db->queryF(
4303 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
4304 "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 " .
4305 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4306 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4308 [
'integer',
'integer'],
4312 $result = $this->db->queryF(
4313 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
4314 "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 " .
4315 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4316 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4319 [$this->getTestId()]
4324 while ($row = $this->db->fetchAssoc($result)) {
4325 $result_array[$row[
'usr_id']] = $row;
4327 return $result_array;
4334 SELECT tst_active.active_id,
4336 tst_active.user_fi usr_id,
4340 tst_active.submitted test_finished,
4341 usr_data.matriculation,
4343 tst_active.lastindex,
4344 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
4347 ON tst_active.user_fi = usr_data.usr_id
4348 WHERE tst_active.test_fi = %s
4349 ORDER BY usr_data.lastname
4351 $result = $this->db->queryF(
4353 [
'text',
'text',
'text',
'integer'],
4354 [
'', $this->
lng->txt(
"anonymous"),
"", $this->getTestId()]
4358 SELECT tst_active.active_id,
4360 tst_active.user_fi usr_id,
4364 tst_active.submitted test_finished,
4365 usr_data.matriculation,
4367 tst_active.lastindex,
4368 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
4371 ON tst_active.user_fi = usr_data.usr_id
4372 WHERE tst_active.test_fi = %s
4373 ORDER BY usr_data.lastname
4375 $result = $this->db->queryF(
4378 [$this->getTestId()]
4382 while ($row = $this->db->fetchAssoc($result)) {
4383 $data[$row[
'active_id']] = $row;
4385 foreach (
$data as $index => $participant) {
4386 if (strlen(trim($participant[
"firstname"] . $participant[
"lastname"])) == 0) {
4387 $data[$index][
"lastname"] = $this->
lng->txt(
"deleted_user");
4395 if (!$this->getGlobalSettings()->isManualScoringEnabled()) {
4399 $filtered_participants = [];
4400 foreach ($this->getTestParticipants() as $active_id => $participant) {
4401 if ($participant[
'tries'] > 0) {
4404 if ($this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
4405 $filtered_participants[$active_id] = $participant;
4409 if (!$this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
4410 $filtered_participants[$active_id] = $participant;
4414 $filtered_participants[$active_id] = $participant;
4418 return $filtered_participants;
4429 if (!is_array($ids) || count($ids) == 0) {
4433 if ($this->getAnonymity()) {
4434 $result = $this->db->queryF(
4435 "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",
4436 [
'text',
'text',
'text'],
4437 [
"", $this->lng->txt(
"anonymous"),
""]
4440 $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");
4444 while ($row = $this->db->fetchAssoc($result)) {
4445 $result_array[$row[
"usr_id"]] = $row;
4447 return $result_array;
4452 if (!is_array($ids) || count($ids) == 0) {
4465 if (!is_array($ids) || count($ids) == 0) {
4469 foreach ($ids as $obj_id) {
4483 $this->db->manipulateF(
4484 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
4485 [
'integer',
'integer'],
4488 $this->db->manipulateF(
4489 "INSERT INTO tst_invited_user (test_fi, user_fi, ip_range_from, ip_range_to, tstamp) VALUES (%s, %s, %s, %s, %s)",
4490 [
'integer',
'integer',
'text',
'text',
'integer'],
4491 [$this->getTestId(),
$user_id, (strlen($client_ip)) ? $client_ip :
null, (strlen($client_ip)) ? $client_ip :
null,time()]
4504 if (is_numeric($question_fi)) {
4505 $result =
$ilDB->queryF(
4506 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
4507 [
'integer',
'integer'],
4508 [$active_id, $question_fi]
4511 $result =
$ilDB->queryF(
4512 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
4518 while ($row =
$ilDB->fetchAssoc($result)) {
4519 $result_array[$row[
"question_fi"]] = $row;
4521 return $result_array;
4530 $active_id = $this->getActiveIdOfUser(
$user_id);
4531 $this->db->manipulateF(
4532 "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
4533 [
'integer',
'integer'],
4534 [$active_id, $question_id]
4536 $this->db->manipulateF(
4537 "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
4538 [
'integer',
'integer',
'integer'],
4539 [$value, $question_id, $active_id]
4548 $result = $this->db->queryF(
4549 "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
4550 [
'integer',
'integer'],
4553 return $result->numRows() == 1;
4565 $result = $this->db->queryF(
4566 "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
4567 [
'integer',
'integer',
'integer'],
4570 return $result->numRows() == 1;
4578 return $this->getNrOfTries() != 0;
4589 return $tries >= $this->getNrOfTries();
4604 "user_id" => $this->
lng->txt(
"user_id"),
4605 "matriculation" => $this->
lng->txt(
"matriculation"),
4606 "lastname" => $this->
lng->txt(
"lastname"),
4607 "firstname" => $this->
lng->txt(
"firstname"),
4608 "login" => $this->
lng->txt(
"login"),
4609 "reached_points" => $this->
lng->txt(
"tst_reached_points"),
4610 "max_points" => $this->
lng->txt(
"tst_maximum_points"),
4611 "percent_value" => $this->
lng->txt(
"tst_percent_solved"),
4612 "mark" => $this->
lng->txt(
"tst_mark"),
4613 "passed" => $this->
lng->txt(
"tst_mark_passed"),
4616 if (count($participants)) {
4617 foreach ($participants as $active_id => $user_rec) {
4620 $reached_points = 0;
4624 if (!is_int($pass)) {
4627 foreach ($this->questions as $value) {
4629 if (is_object($question)) {
4630 $max_points += $question->getMaximumPoints();
4631 $reached_points += $question->getReachedPoints($active_id, $pass);
4634 if ($max_points > 0) {
4635 $percentvalue = $reached_points / $max_points;
4636 if ($percentvalue < 0) {
4637 $percentvalue = 0.0;
4642 $mark_obj = $this->getMarkSchema()->getMatchingMark($percentvalue * 100);
4644 if ($mark_obj !==
null) {
4645 $mark = $mark_obj->getOfficialName();
4647 if ($this->getAnonymity()) {
4648 $user_rec[
'firstname'] =
"";
4649 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
4652 "user_id" => $user_rec[
'usr_id'],
4653 "matriculation" => $user_rec[
'matriculation'],
4654 "lastname" => $user_rec[
'lastname'],
4655 "firstname" => $user_rec[
'firstname'],
4656 "login" => $user_rec[
'login'],
4657 "reached_points" => $reached_points,
4658 "max_points" => $max_points,
4659 "percent_value" => $percentvalue,
4661 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
4680 $result =
$ilDB->queryF(
4681 "SELECT tries FROM tst_active WHERE active_id = %s",
4685 if ($result->numRows()) {
4686 $row =
$ilDB->fetchAssoc($result);
4687 return $row[
"tries"];
4706 $result =
$ilDB->queryF(
4707 "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
4712 if ($result->numRows()) {
4713 $row =
$ilDB->fetchAssoc($result);
4714 return $row[
"maxpass"];
4730 $result =
$ilDB->queryF(
4731 "SELECT * FROM tst_pass_result WHERE active_fi = %s",
4736 if (!$result->numRows()) {
4742 while ($row =
$ilDB->fetchAssoc($result)) {
4743 if ($row[
"maxpoints"] > 0.0) {
4744 $factor = (float) ($row[
"points"] / $row[
"maxpoints"]);
4748 if ($factor === 0.0 && $bestfactor === 0.0
4749 || $factor > $bestfactor) {
4751 $bestfactor = $factor;
4755 if (is_array($bestrow)) {
4756 return $bestrow[
"pass"];
4772 $counted_pass =
null;
4778 return $counted_pass;
4792 if ($this->isRandomTest()) {
4793 $this->loadQuestions($active_id, $pass);
4796 foreach ($this->questions as $value) {
4797 if ($this->questionrepository->lookupResultRecordExist($active_id, $value, $pass)) {
4798 $workedthrough += 1;
4801 return $workedthrough;
4815 if (is_null($pass)) {
4820 SELECT tst_pass_result.tstamp pass_res_tstamp,
4821 tst_test_result.tstamp quest_res_tstamp
4823 FROM tst_pass_result
4825 LEFT JOIN tst_test_result
4826 ON tst_test_result.active_fi = tst_pass_result.active_fi
4827 AND tst_test_result.pass = tst_pass_result.pass
4829 WHERE tst_pass_result.active_fi = %s
4830 AND tst_pass_result.pass = %s
4832 ORDER BY tst_test_result.tstamp DESC
4835 $result =
$ilDB->queryF(
4837 [
'integer',
'integer'],
4841 while ($row =
$ilDB->fetchAssoc($result)) {
4842 if ($row[
'quest_res_tstamp']) {
4843 return $row[
'quest_res_tstamp'];
4846 return $row[
'pass_res_tstamp'];
4863 "executable" =>
true,
4864 "errormessage" =>
""
4867 if (!$this->getObjectProperties()->getPropertyIsOnline()->getIsOnline()) {
4868 $result[
"executable"] =
false;
4869 $result[
"errormessage"] = $this->
lng->txt(
'autosave_failed') .
': ' . $this->
lng->txt(
'offline');
4873 if (!$this->startingTimeReached()) {
4874 $result[
"executable"] =
false;
4878 if ($this->endingTimeReached()) {
4879 $result[
"executable"] =
false;
4884 $active_id = $this->getActiveIdOfUser(
$user_id);
4886 if ($this->getEnableProcessingTime()
4888 && ($starting_time = $this->getStartingTimeOfUser($active_id)) !==
false
4889 && $this->isMaxProcessingTimeReached($starting_time, $active_id)) {
4890 $result[
"executable"] =
false;
4891 $result[
"errormessage"] = $this->
lng->txt(
"detail_max_processing_time_reached");
4896 $testPassesSelector->setActiveId($active_id);
4897 $testPassesSelector->setLastFinishedPass($test_session->getLastFinishedPass());
4899 if ($this->hasNrOfTriesRestriction() && ($active_id > 0)) {
4900 $closedPasses = $testPassesSelector->getClosedPasses();
4902 if (count($closedPasses) >= $this->getNrOfTries()) {
4903 $result[
"executable"] =
false;
4904 $result[
"errormessage"] = $this->
lng->txt(
"maximum_nr_of_tries_reached");
4908 if ($this->isBlockPassesAfterPassedEnabled() && !$testPassesSelector->openPassExists()) {
4909 if ($this->test_result_repository->isPassed(
$user_id, $this->getId())) {
4910 $result[
'executable'] =
false;
4911 $result[
'errormessage'] = $this->
lng->txt(
"tst_addit_passes_blocked_after_passed_msg");
4917 $next_pass_allowed_timestamp = 0;
4918 if (!$this->isNextPassAllowed($testPassesSelector, $next_pass_allowed_timestamp)) {
4921 $result[
'executable'] =
false;
4922 $result[
'errormessage'] = sprintf($this->
lng->txt(
'wait_for_next_pass_hint_msg'), $date);
4930 $waiting_between_passes = $this->getMainSettings()->getTestBehaviourSettings()->getPassWaiting();
4934 $this->getMainSettings()->getTestBehaviourSettings()->getPassWaitingEnabled()
4935 && ($waiting_between_passes !==
'')
4937 && ($last_finished_pass_timestamp !==
null)
4939 $time_values = explode(
':', $waiting_between_passes);
4940 $next_pass_allowed_timestamp = strtotime(
'+ ' . $time_values[0] .
' Days + ' . $time_values[1] .
' Hours' . $time_values[2] .
' Minutes', $last_finished_pass_timestamp);
4941 return (time() > $next_pass_allowed_timestamp);
4951 $pass_selector->setActiveId($test_session->
getActiveId());
4954 return $pass_selector->hasReportablePasses();
4961 $pass_selector->setActiveId($test_session->
getActiveId());
4964 return $pass_selector->hasExistingPasses();
4976 if ($active_id < 1) {
4979 if ($pass ===
null) {
4980 $pass = ($this->getResetProcessingTime()) ? self::_getPass($active_id) : 0;
4982 $result = $this->db->queryF(
4983 "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
4984 [
'integer',
'integer'],
4987 if ($result->numRows()) {
4988 $row = $this->db->fetchAssoc($result);
4989 if (preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches)) {
5014 if (!$this->getEnableProcessingTime()) {
5018 $processing_time = $this->getProcessingTimeInSeconds($active_id);
5020 if ($now > ($starting_time + $processing_time)) {
5029 $tags_trafo = $this->
refinery->string()->stripTags();
5033 questtypes.type_tag,
5035 origquest.obj_fi orig_obj_fi
5037 FROM qpl_questions questions
5039 INNER JOIN qpl_qst_type questtypes
5040 ON questtypes.question_type_id = questions.question_type_fi
5042 INNER JOIN tst_test_question tstquest
5043 ON tstquest.question_fi = questions.question_id
5045 LEFT JOIN qpl_questions origquest
5046 ON origquest.question_id = questions.original_id
5048 WHERE tstquest.test_fi = %s
5050 ORDER BY tstquest.sequence
5053 $query_result = $this->db->queryF(
5056 [$this->getTestId()]
5061 while ($row = $this->db->fetchAssoc($query_result)) {
5062 $row[
'title'] = $tags_trafo->transform($row[
'title']);
5063 $row[
'description'] = $tags_trafo->transform($row[
'description'] !==
'' && $row[
'description'] !==
null ? $row[
'description'] :
' ');
5064 $row[
'author'] = $tags_trafo->transform($row[
'author']);
5066 $questions[] = $row;
5074 foreach ($this->getTestQuestions() as $questionData) {
5075 if ($questionData[
'question_id'] != $question_id) {
5087 $row = $this->db->fetchAssoc($this->db->queryF(
5088 "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
5089 [
'integer',
'integer'],
5090 [$question_id, $this->getId()]
5093 return (
bool) $row[
'cnt'];
5100 foreach ($this->getTestQuestions() as $question_data) {
5101 $points += $question_data[
'points'];
5114 questtypes.type_tag,
5115 origquest.obj_fi orig_obj_fi
5117 FROM qpl_questions questions
5119 INNER JOIN qpl_qst_type questtypes
5120 ON questtypes.question_type_id = questions.question_type_fi
5122 INNER JOIN tst_rnd_cpy tstquest
5123 ON tstquest.qst_fi = questions.question_id
5125 LEFT JOIN qpl_questions origquest
5126 ON origquest.question_id = questions.original_id
5128 WHERE tstquest.tst_fi = %s
5131 $query_result = $this->db->queryF(
5134 [$this->getTestId()]
5137 return $this->db->fetchAll($query_result);
5142 return $this->getMainSettings()->getQuestionBehaviourSettings()->getShuffleQuestions();
5158 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewMode();
5163 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getQuestionListEnabled();
5168 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewEnabled();
5173 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtBeginning();
5178 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtEnd();
5183 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getShowDescriptionInQuestionList();
5191 return $this->getScoreSettings()->getResultDetailsSettings()->getShowPassDetails();
5199 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionPrintview();
5206 return $this->getShowSolutionPrintview();
5214 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionFeedback();
5222 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionAnswersOnly();
5230 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionSignature();
5238 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionSuggested();
5247 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionListComparison();
5252 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionListOwnAnswers();
5262 $result =
$ilDB->queryF(
5263 "SELECT user_fi FROM tst_active WHERE active_id = %s",
5267 if ($result->numRows()) {
5268 $row =
$ilDB->fetchAssoc($result);
5269 return $row[
"user_fi"];
5277 $result = $this->db->queryF(
5278 "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
5282 if ($result->numRows()) {
5283 $row = $this->db->fetchAssoc($result);
5284 return $row[
"finished"];
5289 public static function lookupLastTestPassAccess(
int $active_id,
int $pass_index): ?
int
5296 SELECT MAX(tst_times.tstamp) as last_pass_access
5298 WHERE active_fi = %s
5304 [
'integer',
'integer'],
5305 [$active_id, $pass_index]
5308 while ($row =
$ilDB->fetchAssoc(
$res)) {
5309 return $row[
'last_pass_access'];
5324 if (preg_match(
"/<[^>]*?>/", $a_text)) {
5341 for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
5342 $material = $a_material->getMaterial($i);
5343 if ($material[
'type'] ===
'mattext') {
5344 $result .= $material[
'material']->getContent();
5346 if ($material[
'type'] ===
'matimage') {
5347 $matimage = $material[
'material'];
5348 if (preg_match(
'/(il_([0-9]+)_mob_([0-9]+))/', $matimage->getLabel(), $matches)) {
5350 'mob' => $matimage->getLabel(),
5351 'uri' => $matimage->getUri()
5357 $decoded_result = base64_decode($result);
5358 if (str_starts_with($decoded_result,
'<PageObject>')) {
5359 $result = $decoded_result;
5373 'texttype' =>
'text/plain'
5377 if ($page_id !==
null) {
5378 $attrs[
'texttype'] =
'text/xml';
5381 $page_object->buildDom();
5382 $page_object->insertInstIntoIDs((
string)
IL_INST_ID);
5383 $material = base64_encode($page_object->getXMLFromDom());
5385 foreach ($file_ids as $file_id) {
5386 $this->file_ids[] = (
int) $file_id;
5389 } elseif ($this->isHTML($material)) {
5390 $attrs[
'texttype'] =
'text/xhtml';
5392 $mob_string =
'mm_';
5395 $xml_writer->
xmlElement(
'mattext', $attrs, $material);
5396 foreach ($mobs as $mob) {
5397 $mob_id_string = (string) $mob;
5398 $moblabel =
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string;
5399 if (strpos($material, $mob_string . $mob_id_string) !==
false) {
5403 'label' => $moblabel,
5404 'uri' =>
'objects/' .
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string .
'/' . $mob_obj->getTitle()
5407 $xml_writer->
xmlElement(
'matimage', $imgattrs,
null);
5421 if ($txt_output ==
null) {
5426 $prepare_for_latex_output,
5427 $omitNl2BrWhenTextArea
5433 return $this->getMainSettings()->getGeneralSettings()->getAnonymity();
5442 $result =
$ilDB->queryF(
5443 "SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
5447 while ($row =
$ilDB->fetchAssoc($result)) {
5448 return (
int) $row[
'anonymity'];
5455 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getSuspendTestAllowed();
5460 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getQuestionMarkingEnabled();
5465 return $this->getMainSettings()->getAccessSettings()->getFixedParticipants();
5471 SELECT tst_tests.question_set_type
5473 INNER JOIN tst_tests
5474 ON tst_active.test_fi = tst_tests.test_id
5475 WHERE tst_active.active_id = %s
5478 $res = $this->db->queryF($query, [
'integer'], [$active_id]);
5480 while ($row = $this->db->fetchAssoc(
$res)) {
5481 return $row[
'question_set_type'];
5499 if ($this->getAnonymity() && !$overwrite_anonymity) {
5500 return $this->
lng->txt(
"anonymous") . $suffix;
5503 if (strlen($uname[
"firstname"] . $uname[
"lastname"]) == 0) {
5504 $uname[
"firstname"] = $this->
lng->txt(
"deleted_user");
5506 if ($sorted_order) {
5507 return trim($uname[
"lastname"] .
", " . $uname[
"firstname"]) . $suffix;
5509 return trim($uname[
"firstname"] .
" " . $uname[
"lastname"]) . $suffix;
5521 $result = $this->db->queryF(
5522 "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
5524 [$this->
user->getId()]
5527 while ($row = $this->db->fetchAssoc($result)) {
5528 $defaults[$row[
"test_defaults_id"]] = $row;
5535 $result = $this->db->queryF(
5536 "SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
5540 if ($result->numRows() == 1) {
5541 $row = $this->db->fetchAssoc($result);
5550 $this->db->manipulateF(
5551 "DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
5565 $main_settings = $this->getMainSettings();
5566 $score_settings = $this->getScoreSettings();
5613 'mailnotification' => $main_settings->
getFinishingSettings()->getMailNotificationContentType(),
5646 fn(
Mark $v): array => [
5652 $this->getMarkSchema()->getMarkSteps()
5655 $next_id = $this->db->nextId(
'tst_test_defaults');
5657 'tst_test_defaults',
5659 'test_defaults_id' => [
'integer', $next_id],
5660 'name' => [
'text', $a_name],
5661 'user_fi' => [
'integer', $this->
user->getId()],
5662 'defaults' => [
'clob', serialize($testsettings)],
5663 'marks' => [
'clob', json_encode($marks)],
5664 'tstamp' => [
'integer', time()]
5671 $testsettings = unserialize($test_defaults[
'defaults'], [
'allowed_classes' => [DateTimeImmutable::class]]);
5672 $activation_starting_time = is_numeric($testsettings[
'activation_starting_time'] ??
false)
5673 ? (
int) $testsettings[
'activation_starting_time']
5675 $activation_ending_time = is_numeric($testsettings[
'activation_ending_time'] ??
false)
5676 ? (
int) $testsettings[
'activation_ending_time']
5678 $unserialized_marks = json_decode($test_defaults[
'marks'],
true);
5681 if (is_array($unserialized_marks)
5682 && is_array($unserialized_marks[0])) {
5683 $this->mark_schema = $this->getMarkSchema()->withMarkSteps(
5687 $v[
'official_name'],
5688 $v[
'minimum_level'],
5695 $info =
'old_mark_default_not_applied';
5698 $main_settings = $this->getMainSettings();
5709 $main_settings = $main_settings
5712 ->withQuestionSetType(
5713 $testsettings[
'questionSetType'] ?? $general_settings->getQuestionSetType()
5715 $testsettings[
'Anonymity'] ?? $general_settings->getAnonymity()
5717 )->withIntroductionSettings(
5718 $introduction_settings
5719 ->withIntroductionEnabled(
5720 $testsettings[
'IntroEnabled'] ?? $introduction_settings->getIntroductionEnabled()
5721 )->withExamConditionsCheckboxEnabled(
5722 $testsettings[
'ExamConditionsCheckboxEnabled'] ?? $introduction_settings->getExamConditionsCheckboxEnabled()
5724 )->withAccessSettings(
5726 ->withStartTimeEnabled(
5727 $testsettings[
'StartingTimeEnabled'] ?? $access_settings->getStartTimeEnabled()
5729 $this->convertTimeToDateTimeImmutableIfNecessary(
5730 $testsettings[
'StartingTime'] ?? $access_settings->getStartTime()
5732 )->withEndTimeEnabled(
5733 $testsettings[
'EndingTimeEnabled'] ?? $access_settings->getEndTimeEnabled()
5735 $this->convertTimeToDateTimeImmutableIfNecessary(
5736 $testsettings[
'EndingTime'] ?? $access_settings->getEndTime()
5738 )->withPasswordEnabled(
5739 $testsettings[
'password_enabled'] ?? $access_settings->getPasswordEnabled()
5741 $testsettings[
'password'] ?? $access_settings->getPassword()
5742 )->withFixedParticipants(
5743 $testsettings[
'fixed_participants'] ?? $access_settings->getFixedParticipants()
5745 )->withTestBehaviourSettings(
5746 $test_behavior_settings
5747 ->withNumberOfTries(
5748 $testsettings[
'NrOfTries'] ?? $test_behavior_settings->getNumberOfTries()
5749 )->withBlockAfterPassedEnabled(
5750 $testsettings[
'BlockAfterPassed'] ?? $test_behavior_settings->getBlockAfterPassedEnabled()
5752 $testsettings[
'pass_waiting'] ?? $test_behavior_settings->getPassWaiting()
5754 $testsettings[
'Kiosk'] ?? $test_behavior_settings->getKioskMode()
5755 )->withProcessingTimeEnabled(
5756 $testsettings[
'EnableProcessingTime'] ?? $test_behavior_settings->getProcessingTimeEnabled()
5757 )->withProcessingTime(
5758 $testsettings[
'ProcessingTime'] ?? $test_behavior_settings->getProcessingTime()
5759 )->withResetProcessingTime(
5760 $testsettings[
'ResetProcessingTime'] ?? $test_behavior_settings->getResetProcessingTime()
5761 )->withExamIdInTestAttemptEnabled(
5762 $testsettings[
'examid_in_test_pass'] ?? $test_behavior_settings->getExamIdInTestAttemptEnabled()
5764 )->withQuestionBehaviourSettings(
5765 $question_behavior_settings
5766 ->withQuestionTitleOutputMode(
5767 $testsettings[
'TitleOutput'] ?? $question_behavior_settings->getQuestionTitleOutputMode()
5768 )->withAutosaveEnabled(
5769 $testsettings[
'autosave'] ?? $question_behavior_settings->getAutosaveEnabled()
5770 )->withAutosaveInterval(
5771 $testsettings[
'autosave_ival'] ?? $question_behavior_settings->getAutosaveInterval()
5772 )->withShuffleQuestions(
5773 $testsettings[
'Shuffle'] ?? $question_behavior_settings->getShuffleQuestions()
5774 )->withInstantFeedbackPointsEnabled(
5775 $testsettings[
'AnswerFeedbackPoints'] ?? $question_behavior_settings->getInstantFeedbackPointsEnabled()
5776 )->withInstantFeedbackGenericEnabled(
5777 $testsettings[
'AnswerFeedback'] ?? $question_behavior_settings->getInstantFeedbackGenericEnabled()
5778 )->withInstantFeedbackSpecificEnabled(
5779 $testsettings[
'SpecificAnswerFeedback'] ?? $question_behavior_settings->getInstantFeedbackSpecificEnabled()
5780 )->withInstantFeedbackSolutionEnabled(
5781 $testsettings[
'InstantFeedbackSolution'] ?? $question_behavior_settings->getInstantFeedbackSolutionEnabled()
5782 )->withForceInstantFeedbackOnNextQuestion(
5783 $testsettings[
'force_inst_fb'] ?? $question_behavior_settings->getForceInstantFeedbackOnNextQuestion()
5784 )->withLockAnswerOnInstantFeedbackEnabled(
5785 $testsettings[
'inst_fb_answer_fixation'] ?? $question_behavior_settings->getLockAnswerOnInstantFeedbackEnabled()
5786 )->withLockAnswerOnNextQuestionEnabled(
5787 $testsettings[
'follow_qst_answer_fixation'] ?? $question_behavior_settings->getLockAnswerOnNextQuestionEnabled()
5789 )->withParticipantFunctionalitySettings(
5790 $participant_functionality_settings
5791 ->withUsePreviousAnswerAllowed(
5792 $testsettings[
'use_previous_answers'] ?? $participant_functionality_settings->getUsePreviousAnswerAllowed()
5793 )->withSuspendTestAllowed(
5794 $testsettings[
'ShowCancel'] ?? $participant_functionality_settings->getSuspendTestAllowed()
5795 )->withPostponedQuestionsMoveToEnd(
5796 $testsettings[
'SequenceSettings'] ?? $participant_functionality_settings->getPostponedQuestionsMoveToEnd()
5797 )->withUsrPassOverviewMode(
5798 $testsettings[
'ListOfQuestionsSettings'] ?? $participant_functionality_settings->getUsrPassOverviewMode()
5799 )->withQuestionMarkingEnabled(
5800 $testsettings[
'ShowMarker'] ?? $participant_functionality_settings->getQuestionMarkingEnabled()
5802 )->withFinishingSettings(
5804 ->withShowAnswerOverview(
5805 $testsettings[
'enable_examview'] ?? $finishing_settings->getShowAnswerOverview()
5806 )->withConcludingRemarksEnabled(
5807 $testsettings[
'ShowFinalStatement'] ?? $finishing_settings->getConcludingRemarksEnabled()
5808 )->withRedirectionMode(
5809 RedirectionModes::tryFrom($testsettings[
'redirection_mode'] ?? 0) ?? $finishing_settings->getRedirectionMode()
5810 )->withRedirectionUrl(
5811 $testsettings[
'redirection_url'] ?? $finishing_settings->getRedirectionUrl()
5812 )->withMailNotificationContentType(
5813 $testsettings[
'mailnotification'] ?? $finishing_settings->getMailNotificationContentType()
5814 )->withAlwaysSendMailNotification(
5815 $testsettings[
'mailnottype'] ?? $finishing_settings->getAlwaysSendMailNotification()
5817 )->withAdditionalSettings(
5818 $additional_settings
5819 ->withSkillsServiceEnabled(
5820 $testsettings[
'skill_service'] ?? $additional_settings->getSkillsServiceEnabled()
5822 $testsettings[
'HideInfoTab'] ?? $additional_settings->getHideInfoTab()
5826 $this->getMainSettingsRepository()->store($main_settings);
5828 $score_reporting = ScoreReportingTypes::SCORE_REPORTING_DISABLED;
5829 if ($testsettings[
'ScoreReporting'] !==
null) {
5830 $score_reporting = ScoreReportingTypes::tryFrom($testsettings[
'ScoreReporting'])
5831 ?? ScoreReportingTypes::SCORE_REPORTING_DISABLED;
5834 $reporting_date = $testsettings[
'ReportingDate'];
5835 if (is_string($reporting_date)) {
5836 $reporting_date =
new DateTimeImmutable($testsettings[
'ReportingDate'],
new DateTimeZone(
'UTC'));
5839 $score_settings = $this->getScoreSettings();
5846 $score_settings = $score_settings
5850 $testsettings[
'PassScoring'] ?? $scoring_settings->getPassScoring()
5851 )->withScoreCutting(
5852 $testsettings[
'ScoreCutting'] ?? $scoring_settings->getScoreCutting()
5854 $testsettings[
'CountSystem'] ?? $scoring_settings->getCountSystem()
5856 )->withResultSummarySettings(
5857 $result_summary_settings
5858 ->withPassDeletionAllowed(
5859 $testsettings[
'pass_deletion_allowed'] ?? $result_summary_settings->getPassDeletionAllowed()
5860 )->withShowGradingStatusEnabled(
5861 $testsettings[
'show_grading_status'] ?? $result_summary_settings->getShowGradingStatusEnabled()
5862 )->withShowGradingMarkEnabled(
5863 $testsettings[
'show_grading_mark'] ?? $result_summary_settings->getShowGradingMarkEnabled()
5864 )->withScoreReporting(
5866 )->withReportingDate(
5869 )->withResultDetailsSettings(
5870 $result_details_settings
5871 ->withResultsPresentation(
5872 $testsettings[
'ResultsPresentation'] ?? $result_details_settings->getResultsPresentation()
5873 )->withShowSolutionListComparison(
5874 $testsettings[
'show_solution_list_comparison'] ?? $result_details_settings->getShowSolutionListComparison()
5875 )->withShowExamIdInTestResults(
5876 $testsettings[
'examid_in_test_res'] ?? $result_details_settings->getShowExamIdInTestResults()
5878 )->withGamificationSettings(
5879 $gamification_settings
5880 ->withHighscoreEnabled(
5881 $testsettings[
'highscore_enabled'] ?? $gamification_settings->getHighscoreEnabled()
5882 )->withHighscoreAnon(
5883 $testsettings[
'highscore_anon'] ?? $gamification_settings->getHighscoreAnon()
5884 )->withHighscoreAchievedTS(
5885 $testsettings[
'highscore_achieved_ts'] ?? $gamification_settings->getHighscoreAchievedTS()
5886 )->withHighscoreScore(
5887 $testsettings[
'highscore_score'] ?? $gamification_settings->getHighscoreScore()
5888 )->withHighscorePercentage(
5889 $testsettings[
'highscore_percentage'] ?? $gamification_settings->getHighscorePercentage()
5890 )->withHighscoreWTime(
5891 $testsettings[
'highscore_wtime'] ?? $gamification_settings->getHighscoreWTime()
5892 )->withHighscoreOwnTable(
5893 $testsettings[
'highscore_own_table'] ?? $gamification_settings->getHighscoreOwnTable()
5894 )->withHighscoreTopTable(
5895 $testsettings[
'highscore_top_table'] ?? $gamification_settings->getHighscoreTopTable()
5896 )->withHighscoreTopNum(
5897 $testsettings[
'highscore_top_num'] ?? $gamification_settings->getHighscoreTopNum()
5901 $this->getScoreSettingsRepository()->store($score_settings);
5908 DateTimeImmutable|
int|
null $date_time
5909 ): ?DateTimeImmutable {
5910 if ($date_time === null || $date_time instanceof DateTimeImmutable) {
5914 return DateTimeImmutable::createFromFormat(
'U', (
string) $date_time);
5926 if (extension_loaded(
"tidy")) {
5929 "output-xml" =>
true,
5930 "numeric-entities" =>
true
5933 $tidy->parseString($print_output, $config,
'utf8');
5934 $tidy->cleanRepair();
5935 $print_output = tidy_get_output($tidy);
5936 $print_output = preg_replace(
"/^.*?(<html)/",
"\\1", $print_output);
5938 $print_output = str_replace(
" ",
" ", $print_output);
5939 $print_output = str_replace(
"⊗",
"X", $print_output);
5941 $xsl = file_get_contents(
"./components/ILIAS/Test/xml/question2fo.xsl");
5946 'font-family="Helvetica, unifont"',
5947 'font-family="' . $this->
settings->get(
'rpc_pdf_font',
'Helvetica, unifont') .
'"',
5951 $args = [
'/_xml' => $print_output,
'/_xsl' => $xsl ];
5952 $xh = xslt_create();
5954 $output = xslt_process($xh,
"arg:/_xml",
"arg:/_xsl",
null, $args,
$params);
5968 $content = preg_replace(
"/href=\".*?\"/",
"", $content);
5969 $printbody =
new ilTemplate(
"tpl.il_as_tst_print_body.html",
true,
true,
"components/ILIAS/Test");
5971 $printbody->setVariable(
"ADM_CONTENT", $content);
5972 $printbody->setCurrentBlock(
"css_file");
5974 $printbody->parseCurrentBlock();
5975 $printoutput = $printbody->get();
5976 $html = str_replace(
"href=\"./",
"href=\"" . ILIAS_HTTP_PATH .
"/", $printoutput);
5977 $html = preg_replace(
"/<div id=\"dontprint\">.*?<\\/div>/ims",
"", $html);
5978 if (extension_loaded(
"tidy")) {
5981 "output-xml" =>
true,
5982 "numeric-entities" =>
true
5985 $tidy->parseString($html, $config,
'utf8');
5986 $tidy->cleanRepair();
5987 $html = tidy_get_output($tidy);
5988 $html = preg_replace(
"/^.*?(<html)/",
"\\1", $html);
5990 $html = str_replace(
" ",
" ", $html);
5991 $html = str_replace(
"⊗",
"X", $html);
5993 $html = preg_replace(
"/src=\".\\//ims",
"src=\"" . ILIAS_HTTP_PATH .
"/", $html);
5994 $this->deliverPDFfromFO($this->processPrintoutput2FO($html), $title);
6005 $fp = fopen($fo_file,
"w");
6014 $pdf_base64->scalar,
6019 }
catch (Exception
$e) {
6020 $this->
logger->info(__METHOD__ .
': ' .
$e->getMessage());
6036 if ($pass ===
null) {
6040 $row = self::getSingleManualFeedback((
int) $active_id, (
int) $question_id, (
int) $pass);
6043 $feedback = $row[
'feedback'] ??
'';
6054 $result =
$ilDB->queryF(
6055 "SELECT * FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
6056 [
'integer',
'integer',
'integer'],
6057 [$active_id, $question_id, $pass]
6060 if (
$ilDB->numRows($result) === 1) {
6061 $row =
$ilDB->fetchAssoc($result);
6063 } elseif (
$ilDB->numRows($result) > 1) {
6064 $DIC->logger()->root()->warning(
6065 "WARNING: Multiple feedback entries on tst_manual_fb for " .
6066 "active_fi = $active_id , question_fi = $question_id and pass = $pass"
6086 $result =
$ilDB->queryF(
6087 "SELECT * FROM tst_manual_fb WHERE question_fi = %s",
6092 while ($row =
$ilDB->fetchAssoc($result)) {
6093 $active = $row[
'active_fi'];
6094 $pass = $row[
'pass'];
6095 $question = $row[
'question_fi'];
6099 $feedback[$active][$pass][$question] = $row;
6110 bool $finalized =
false
6112 $feedback_old = self::getSingleManualFeedback($active_id, $question_id, $pass);
6113 $this->db->manipulateF(
6114 'DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s',
6115 [
'integer',
'integer',
'integer'],
6116 [$active_id, $question_id, $pass]
6119 $this->insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old);
6131 $next_id = $this->db->nextId(
'tst_manual_fb');
6132 $user = $this->
user->getId();
6133 $finalized_time = time();
6136 'manual_feedback_id' => [
'integer', $next_id],
6137 'active_fi' => [
'integer', $active_id],
6138 'question_fi' => [
'integer', $question_id],
6139 'pass' => [
'integer', $pass],
6141 'tstamp' => [
'integer', time()]
6144 if ($feedback_old !== [] && (
int) $feedback_old[
'finalized_evaluation'] === 1) {
6145 $user = $feedback_old[
'finalized_by_usr_id'];
6146 $finalized_time = $feedback_old[
'finalized_tstamp'];
6149 if ($finalized ===
false) {
6150 $update_default[
'finalized_evaluation'] = [
'integer', 0];
6151 $update_default[
'finalized_by_usr_id'] = [
'integer', 0];
6152 $update_default[
'finalized_tstamp'] = [
'integer', 0];
6153 } elseif ($finalized ===
true) {
6154 $update_default[
'finalized_evaluation'] = [
'integer', 1];
6155 $update_default[
'finalized_by_usr_id'] = [
'integer', $user];
6156 $update_default[
'finalized_tstamp'] = [
'integer', $finalized_time];
6159 $this->db->insert(
'tst_manual_fb', $update_default);
6161 if ($this->
logger->isLoggingEnabled()) {
6162 $this->
logger->logScoringInteraction(
6163 $this->
logger->getInteractionFactory()->buildScoringInteraction(
6166 $this->user->getId(),
6167 self::_getUserIdFromActiveId($active_id),
6168 TestScoringInteractionTypes::QUESTION_GRADED,
6170 AdditionalInformationGenerator::KEY_EVAL_FINALIZED => $this->logger
6171 ->getAdditionalInformationGenerator()->getTrueFalseTagForBool($finalized),
6193 $this->test_sequence =
new ilTestSequence($active_id, $pass, $this->isRandomTest(), $this->questionrepository);
6203 $this->test_id = $a_id;
6216 if (count($participants)) {
6217 foreach ($participants as $active_id => $user_rec) {
6219 $reached_points = 0;
6222 foreach ($this->questions as $value) {
6224 if (is_object($question)) {
6225 $max_points += $question->getMaximumPoints();
6226 $reached_points += $question->getReachedPoints($active_id, $pass);
6227 if ($max_points > 0) {
6228 $percentvalue = $reached_points / $max_points;
6229 if ($percentvalue < 0) {
6230 $percentvalue = 0.0;
6235 if ($this->getAnonymity()) {
6236 $user_rec[
'firstname'] =
"";
6237 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
6240 "user_id" => $user_rec[
'usr_id'],
6241 "matriculation" => $user_rec[
'matriculation'],
6242 "lastname" => $user_rec[
'lastname'],
6243 "firstname" => $user_rec[
'firstname'],
6244 "login" => $user_rec[
'login'],
6245 "question_id" => $question->getId(),
6246 "question_title" => $question->getTitle(),
6247 "reached_points" => $reached_points,
6248 "max_points" => $max_points,
6249 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
6266 $result =
$ilDB->queryF(
6267 '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',
6271 $rec =
$ilDB->fetchAssoc($result);
6272 return $rec[
'obj_id'] ??
null;
6283 if (!$this->component_repository->getComponentByTypeAndName(
6286 )->getPluginSlotById(
'qst')->hasPluginName($a_pname)) {
6290 return $this->component_repository
6291 ->getComponentByTypeAndName(
6295 ->getPluginSlotById(
6309 SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass
6310 FROM tst_test_result
6311 INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s
6312 INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi
6313 LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi
6314 WHERE tst_test_result.question_fi = %s
6315 ORDER BY usr_data.lastname ASC, usr_data.firstname ASC
6318 $result = $this->db->queryF(
6320 [
'integer',
'integer'],
6321 [$test_id, $question_id]
6325 while ($row = $this->db->fetchAssoc($result)) {
6326 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row[
"active_fi"])) {
6330 if (!array_key_exists($row[
"active_fi"], $foundusers)) {
6331 $foundusers[$row[
"active_fi"]] = [];
6333 array_push($foundusers[$row[
"active_fi"]], [
"pass" => $row[
"pass"],
"qid" => $row[
"question_fi"]]);
6340 $data = $this->getCompleteEvaluationData();
6341 $found_participants =
$data->getParticipants();
6342 $results = [
'overview' => [],
'questions' => []];
6343 if ($found_participants !== []) {
6344 $results[
'overview'][
'tst_stat_result_mark_median'] =
$data->getStatistics()->getEvaluationDataOfMedianUser()?->getMark()?->getShortName() ??
'';
6345 $results[
'overview'][
'tst_stat_result_rank_median'] =
$data->getStatistics()->rankMedian();
6346 $results[
'overview'][
'tst_stat_result_total_participants'] =
$data->getStatistics()->count();
6347 $results[
'overview'][
'tst_stat_result_median'] =
$data->getStatistics()->median();
6348 $results[
'overview'][
'tst_eval_total_persons'] = count($found_participants);
6349 $total_finished =
$data->getTotalFinishedParticipants();
6350 $results[
'overview'][
'tst_eval_total_finished'] = $total_finished;
6351 $results[
'overview'][
'tst_eval_total_finished_average_time'] =
6352 $this->secondsToHoursMinutesSecondsString(
6353 $this->evalTotalStartedAverageTime(
$data->getParticipantIds())
6356 $total_passed_reached = 0;
6357 $total_passed_max = 0;
6358 $total_passed_time = 0;
6359 foreach ($found_participants as $userdata) {
6360 if ($userdata->getMark()?->getPassed()) {
6362 $total_passed_reached += $userdata->getReached();
6363 $total_passed_max += $userdata->getMaxpoints();
6364 $total_passed_time += $userdata->getTimeOnTask();
6367 $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
6368 $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
6369 $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
6370 $results[
'overview'][
'tst_eval_total_passed'] = $total_passed;
6371 $results[
'overview'][
'tst_eval_total_passed_average_points'] = sprintf(
'%2.2f', $average_passed_reached)
6372 .
' ' . strtolower(
'of') .
' ' . sprintf(
'%2.2f', $average_passed_max);
6373 $results[
'overview'][
'tst_eval_total_passed_average_time'] =
6374 $this->secondsToHoursMinutesSecondsString($average_passed_time);
6377 foreach (
$data->getQuestionTitles() as $question_id => $question_title) {
6381 foreach ($found_participants as $userdata) {
6382 for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
6383 if (is_object($userdata->getPass($i))) {
6384 $question = $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
6385 if (is_array($question)) {
6387 $reached += $question[
'reached'];
6388 $max += $question[
'points'];
6393 $percent = $max ? $reached / $max * 100.0 : 0;
6394 $results[
'questions'][$question_id] = [
6396 sprintf(
'%.2f', $answered ? $reached / $answered : 0) .
' ' . strtolower($this->
lng->txt(
'of')) .
' ' . sprintf(
'%.2f', $answered ? $max / $answered : 0),
6397 sprintf(
'%.2f', $percent) .
'%',
6399 sprintf(
'%.2f', $answered ? $reached / $answered : 0),
6400 sprintf(
'%.2f', $answered ? $max / $answered : 0),
6409 $diff_hours = floor($seconds / 3600);
6410 $seconds -= $diff_hours * 3600;
6411 $diff_minutes = floor($seconds / 60);
6412 $seconds -= $diff_minutes * 60;
6413 return sprintf(
'%02d:%02d:%02d', $diff_hours, $diff_minutes, $seconds);
6421 return $this->export_factory->getExporter($this,
'xml')
6427 return $this->getMainSettings()->getFinishingSettings()->getMailNotificationContentType();
6433 $owner_id = $this->getOwner();
6435 $mail->sendSimpleNotification($owner_id, $this->
getTitle(), $usr_data);
6441 $owner_id = $this->getOwner();
6444 $path = $this->export_factory->getExporter(
6446 ExportImportTypes::SCORED_ATTEMPT
6447 )->withFilterByActiveId($active_id)
6450 $delivered_file_name =
'result_' . $active_id .
'.xlsx';
6452 $fd->copyAttachmentFile(
$path, $delivered_file_name);
6453 $file_names[] = $delivered_file_name;
6455 $mail->sendAdvancedNotification($owner_id, $this->
getTitle(), $usr_data, $file_names);
6457 if (count($file_names)) {
6458 $fd->unlinkFiles($file_names);
6466 return $this->getMainSettings()->getFinishingSettings()->getAlwaysSendMailNotification();
6471 return $this->getScoreSettings()->getResultDetailsSettings()->getExportSettings();
6476 $this->template_id = $template_id;
6481 return $this->template_id;
6486 $question_set_config = $this->question_set_config_factory->getQuestionSetConfig();
6487 $reindexed_sequence_position_map = $question_set_config->reindexQuestionOrdering();
6489 $this->loadQuestions();
6491 return $reindexed_sequence_position_map;
6500 foreach (array_keys($order) as
$id) {
6504 UPDATE tst_test_question
6506 WHERE question_fi = %s
6509 $this->db->manipulateF(
6511 [
'integer',
'integer'],
6516 if ($this->
logger->isLoggingEnabled()) {
6517 $this->
logger->logTestAdministrationInteraction(
6518 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
6520 $this->user->getId(),
6521 TestAdministrationInteractionTypes::QUESTION_MOVED,
6523 AdditionalInformationGenerator::KEY_QUESTION_ORDER => $order
6529 $this->loadQuestions();
6534 $questions = $this->getQuestionTitlesAndIndexes();
6536 $IN_questions = $this->db->in(
'q1.question_id', array_keys($questions),
false,
'integer');
6539 SELECT count(q1.question_id) cnt
6541 FROM qpl_questions q1
6543 INNER JOIN qpl_questions q2
6544 ON q2.question_id = q1.original_id
6547 AND q1.obj_fi = q2.obj_fi
6549 $rset = $this->db->query($query);
6550 $row = $this->db->fetchAssoc($rset);
6552 return $row[
'cnt'] > 0;
6566 $result =
$ilDB->queryF(
6567 "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
6568 " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
6569 " WHERE user_fi=%s" .
6570 " GROUP BY test_fi",
6571 [
'integer',
'integer'],
6575 while ($row =
$ilDB->fetchAssoc($result)) {
6576 $obj_id = self::_getObjectIDFromTestID($row[
"test_fi"]);
6577 $all[$obj_id] = (bool) $row[
"pass"];
6584 return $this->questions;
6589 return $this->online;
6594 $page_id = $this->getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
6595 if ($page_id !==
null) {
6600 $page_object->setParentId($this->
getId());
6601 $new_page_id = $page_object->createPageWithNextId();
6602 $settings = $this->getMainSettings()->getIntroductionSettings()
6603 ->withIntroductionPageId($new_page_id);
6604 $this->getMainSettingsRepository()->store(
6605 $this->getMainSettings()->withIntroductionSettings($settings)
6607 return $new_page_id;
6612 $page_id = $this->getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
6613 if ($page_id !==
null) {
6618 $page_object->setParentId($this->
getId());
6619 $new_page_id = $page_object->createPageWithNextId();
6620 $settings = $this->getMainSettings()->getFinishingSettings()
6622 $this->getMainSettingsRepository()->store(
6623 $this->getMainSettings()->withFinishingSettings($settings)
6625 return $new_page_id;
6630 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreEnabled();
6644 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreAnon();
6657 return $this->getAnonymity() == 1 || $this->getHighscoreAnon();
6665 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreAchievedTS();
6673 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreScore();
6681 return $this->getScoreSettings()->getGamificationSettings()->getHighscorePercentage();
6689 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreWTime();
6697 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreOwnTable();
6705 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreTopTable();
6714 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreTopNum();
6719 return $this->getScoreSettings()->getGamificationSettings()->getHighScoreMode();
6724 return $this->getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled();
6729 return $this->getMainSettings()->getQuestionBehaviourSettings()->getAutosaveEnabled();
6734 return $this->getScoreSettings()->getResultSummarySettings()->getPassDeletionAllowed();
6739 return $this->getMainSettings()->getFinishingSettings()->getShowAnswerOverview();
6751 $result = $this->db->queryF(
6752 "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",
6754 [$this->getTestId()]
6756 while ($row = $this->db->fetchAssoc($result)) {
6757 $times[$row[
'active_fi']] = $row[
'started'];
6765 $result = $this->db->queryF(
6766 "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",
6768 [$this->getTestId()]
6770 while ($row = $this->db->fetchAssoc($result)) {
6771 $times[$row[
'active_fi']] = $row[
'additionaltime'];
6778 if ($active_id === 0) {
6781 return $this->participant_repository
6782 ->getParticipantByActiveId($this->getTestId(), $active_id)
6783 ?->getExtraTime() ?? 0;
6789 SELECT MAX(tst_pass_result.pass) + 1 max_res
6790 FROM tst_pass_result
6791 INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi
6792 WHERE test_fi = ' . $this->db->quote($this->getTestId(),
'integer') .
'
6794 $res = $this->db->query($query);
6796 return (
int)
$data[
'max_res'];
6804 $exam_id_query =
'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
6805 $exam_id_result =
$ilDB->queryF($exam_id_query, [
'integer',
'integer' ], [ $active_id, $pass ]);
6806 if (
$ilDB->numRows($exam_id_result) == 1) {
6807 $exam_id_row =
$ilDB->fetchAssoc($exam_id_result);
6809 if ($exam_id_row[
'exam_id'] !=
null) {
6810 return $exam_id_row[
'exam_id'];
6817 public static function buildExamId($active_id, $pass, $test_obj_id =
null): string
6824 if ($test_obj_id ===
null) {
6825 $obj_id = self::_getObjectIDFromActiveID($active_id);
6827 $obj_id = $test_obj_id;
6830 $examId =
'I' . $inst_id .
'_T' . $obj_id .
'_A' . $active_id .
'_P' . $pass;
6837 return $this->getMainSettings()->getTestBehaviourSettings()->getExamIdInTestAttemptEnabled();
6842 return $this->getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults();
6848 $this->main_settings = $this->getMainSettings()->withGeneralSettings(
6850 ->withQuestionSetType($question_set_type)
6856 return $this->getMainSettings()->getGeneralSettings()->getQuestionSetType();
6866 return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED;
6876 return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_RANDOM;
6881 switch ($questionSetType) {
6883 return $lng->txt(
'tst_question_set_type_fixed');
6886 return $lng->txt(
'tst_question_set_type_random');
6889 throw new ilTestException(
'invalid question set type value given: ' . $questionSetType);
6894 if ($this->participantDataExist ===
null) {
6895 $this->participantDataExist = (bool) $this->evalTotalPersons();
6898 return $this->participantDataExist;
6904 $scoring->setPreserveManualScores($preserve_manscoring);
6905 $scoring->recalculateSolutions();
6916 INNER JOIN tst_tests
6917 ON test_id = test_fi
6921 $res =
$ilDB->queryF($query, [
'integer'], [$userId]);
6925 while ($row =
$ilDB->fetchAssoc(
$res)) {
6926 $objIds[] = (
int) $row[
'obj_fi'];
6934 return $this->getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled();
6950 if (!$this->getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled()) {
6954 if (!self::isSkillManagementGloballyActivated()) {
6961 private static $isSkillManagementGloballyActivated =
null;
6965 if (self::$isSkillManagementGloballyActivated ===
null) {
6968 self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
6971 return self::$isSkillManagementGloballyActivated;
6976 return $this->getScoreSettings()->getResultSummarySettings()->getShowGradingStatusEnabled();
6981 return $this->getScoreSettings()->getResultSummarySettings()->getShowGradingMarkEnabled();
6986 return $this->getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled();
6991 return $this->getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled();
6996 return $this->getMainSettings()->getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion();
7004 $ilUser =
$DIC[
'ilUser'];
7008 $active_id = $test_obj->getActiveIdOfUser(
$user_id);
7013 $test_session_factory->reset();
7015 $test_sequence_factory =
new ilTestSequenceFactory($test_obj,
$ilDB, TestDIC::dic()[
'question.general_properties.repository']);
7017 $test_session = $test_session_factory->getSession($active_id);
7018 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $test_session->getPass());
7019 $test_sequence->loadFromDb();
7021 return $test_sequence->hasSequence();
7027 SELECT COUNT(test_question_id) cnt
7028 FROM tst_test_question
7033 $questRes = $this->db->queryF($query, [
'integer'], [$this->getTestId()]);
7035 $row = $this->db->fetchAssoc($questRes);
7036 $questCount = $row[
'cnt'];
7038 if ($this->getShuffleQuestions()) {
7042 INNER JOIN tst_sequence tseq
7043 ON tseq.active_fi = tac.active_id
7044 WHERE tac.test_fi = %s
7047 $partRes = $this->db->queryF(
7050 [$this->getTestId()]
7053 while ($row = $this->db->fetchAssoc($partRes)) {
7054 $sequence = @unserialize($row[
'sequence']);
7060 $sequence = array_filter($sequence,
function ($value) use ($questCount) {
7061 return $value <= $questCount;
7064 $num_seq = count($sequence);
7065 if ($questCount > $num_seq) {
7066 $diff = $questCount - $num_seq;
7067 for ($i = 1; $i <= $diff; $i++) {
7068 $sequence[$num_seq + $i - 1] = $num_seq + $i;
7072 $new_sequence = serialize($sequence);
7074 $this->db->update(
'tst_sequence', [
7075 'sequence' => [
'clob', $new_sequence]
7077 'active_fi' => [
'integer', $row[
'active_fi']],
7078 'pass' => [
'integer', $row[
'pass']]
7082 $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : []);
7087 INNER JOIN tst_sequence tseq
7088 ON tseq.active_fi = tac.active_id
7089 WHERE tac.test_fi = %s
7092 $part_rest = $this->db->queryF(
7095 [$this->getTestId()]
7098 while ($row = $this->db->fetchAssoc($part_rest)) {
7099 $this->db->update(
'tst_sequence', [
7100 'sequence' => [
'clob', $new_sequence]
7102 'active_fi' => [
'integer', $row[
'active_fi']],
7103 'pass' => [
'integer', $row[
'pass']]
7119 return $this->questionrepository;
7124 return $this->global_settings_repo->getGlobalSettings();
7129 if (!$this->main_settings) {
7130 $this->main_settings = $this->getMainSettingsRepository()
7131 ->getFor($this->getTestId());
7133 return $this->main_settings;
7138 if (!$this->main_settings_repo) {
7141 return $this->main_settings_repo;
7146 if (!$this->score_settings) {
7147 $this->score_settings = $this->getScoreSettingsRepository()
7148 ->getFor($this->getTestId());
7150 return $this->score_settings;
7155 if (!$this->score_settings_repo) {
7158 return $this->score_settings_repo;
7162 bool $old_online_status,
7163 bool $new_online_status
7165 if (!$old_online_status && $new_online_status) {
7167 $newsItem->setContext($this->
getId(),
'tst');
7169 $newsItem->setTitle(
'new_test_online');
7170 $newsItem->setContentIsLangVar(
true);
7171 $newsItem->setContent(
'');
7172 $newsItem->setUserId($this->
user->getId());
7174 $newsItem->create();
7178 if ($old_online_status && !$new_online_status) {
7184 if (!$new_online_status && $newsId > 0) {
7186 $newsItem->setTitle(
'new_test_online');
7187 $newsItem->setContentIsLangVar(
true);
7188 $newsItem->setContent(
'');
7189 $newsItem->update();
7200 $query =
'SELECT question_set_type FROM tst_tests WHERE obj_fi = %s';
7202 $res =
$DIC[
'ilDB']->queryF($query, [
'integer'], [$obj_id]);
7204 $question_set_type =
null;
7206 while ($row =
$DIC[
'ilDB']->fetchAssoc(
$res)) {
7207 $question_set_type = $row[
'question_set_type'];
7210 return $question_set_type === self::QUESTION_SET_TYPE_RANDOM;
7215 return $this->participant_repository->getFirstAndLastVisitForActiveId($active_id);
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
updatePassAndTestResults(array $active_ids)
removeAllQuestionResults($question_id)
A class defining mark schemas for assessment test objects.
A class defining marks for assessment test objects.
withGeneralSettings(SettingsGeneral $settings)
getQuestionBehaviourSettings()
getTestBehaviourSettings()
getParticipantFunctionalitySettings()
getIntroductionSettings()
withConcludingRemarksPageId(?int $concluding_remarks_page_id)
getAlwaysSendMailNotification()
getMailNotificationContentType()
withIntroductionPageId(?int $introduction_page_id)
withScoringSettings(SettingsScoring $settings)
getResultDetailsSettings()
withGamificationSettings(SettingsGamification $settings)
getGamificationSettings()
getResultSummarySettings()
raiseError(string $a_msg, int $a_err_obj)
wrapper for downward compability
static _getSolutionMaxPass(int $question_id, int $active_id)
Returns the maximum pass a users question solution.
static _getSuggestedSolutionOutput(int $question_id)
static instantiateQuestion(int $question_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static completeMissingPluginName(array $question_type_data)
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
@classDescription Date and time handling
static getASCIIFilename(string $a_filename)
static makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
static ilTempnam(?string $a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
static getDataDir()
get data directory (outside webspace)
static createDirectory(string $a_dir, int $a_mod=0755)
create directory
static removeTrailingPathSeparators(string $path)
static getInstanceByType(string $type)
static _refreshStatus(int $a_obj_id, ?array $a_users=null)
A news item can be created by different sources.
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 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.
static _getAvailableQuestionpools(bool $use_object_id=false, bool $equal_points=false, bool $could_be_offline=false, bool $showPath=false, bool $with_questioncount=false, string $permission='read', int $usr_id=0)
Returns the available question pools for the active user.
isNextPassAllowed(ilTestPassesSelector $testPassesSelector, int &$next_pass_allowed_timestamp)
setQuestionOrder(array $order)
static _getResultPass($active_id)
Retrieves the pass number that should be counted for a given user.
addConcludingRemarksToSettingsFromImport(SettingsFinishing $settings, array $material, string $importdir, array $mappings)
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
getUserData($ids)
Returns a data of all users specified by id list.
buildIso8601PeriodForExportCompatibility(DateTimeImmutable $date_time)
getTestId()
Gets the database id of the additional test data.
endingTimeReached()
Returns true if the ending time of a test is reached An ending time is not available for self assessm...
setTestId($a_id)
Sets the test ID.
getTotalPointsPassedArray()
Returns an array with the total points of all users who passed the test This array could be used for ...
getShowKioskModeParticipant()
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
getAnsweredQuestionCount($active_id, $pass=null)
Retrieves the number of answered questions for a given user in a given test.
hasAnyTestResult(ilTestSession $test_session)
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
isShowExamIdInTestPassEnabled()
RequestDataCollector $testrequest
removeQuestionsWithResults(array $question_ids)
canShowSolutionPrintview($user_id=null)
getEnableProcessingTime()
getListOfQuestionsStart()
& getExistingQuestions($pass=null)
Get the id's of the questions which are already part of the test.
saveToDb(bool $properties_only=false)
getActiveParticipantList()
static _getTestIDFromObjectID($object_id)
Returns the ILIAS test id for a given object id.
pcArrayShuffle($array)
Shuffles the values of a given array.
getInstantFeedbackSolution()
getStartingTimeOfUser($active_id, $pass=null)
Returns the unix timestamp of the time a user started a test.
checkQuestionParent(int $question_id)
& getInvitedUsers(int $user_id=0, $order="login, lastname, firstname")
Returns a list of all invited users in a test.
getDetailedTestResults($participants)
returns all test results for all participants
isNrOfTriesReached($tries)
returns if number of tries are reached
static _lookupRandomTest(int $obj_id)
reindexFixedQuestionOrdering()
static getTestObjIdsWithActiveForUserId($userId)
getAllQuestions($pass=null)
Returns all questions of a test in test order.
getPotentialRandomTestQuestions()
getScoreSettingsRepository()
isPreviousSolutionReuseEnabled($active_id)
inviteUser($user_id, $client_ip="")
Invites a user to a test.
static _getCountSystem($active_id)
removeTestResultsFromSoapLpAdministration(array $user_ids)
replaceFilesInPageImports(string $text, array $mappings)
getQuestiontext($question_id)
Returns the question text for a given question.
loadQuestions(int $active_id=0, ?int $pass=null)
Load the test question id's from the database.
const QUESTION_SET_TYPE_RANDOM
getQuestionTitlesAndIndexes()
Returns the titles of the test questions in question sequence.
static _getScoreCutting(int $active_id)
Determines if the score of a question should be cut at 0 points or the score of the whole test.
processPrintoutput2FO($print_output)
Convert a print output to XSL-FO.
sendSimpleNotification($active_id)
getXMLZip()
Get zipped xml file for test.
getShowSolutionListComparison()
static lookupExamId($active_id, $pass)
createExportDirectory()
creates data directory for export files (data_dir/tst_data/tst_<id>/export, depending on data directo...
ExportImportFactory $export_factory
getAnonOnlyParticipantIds()
return int[]
static _getActiveIdOfUser($user_id="", $test_id="")
removeQuestionFromSequences(int $question_id, array $active_ids, ilTestReindexedSequencePositionMap $reindexed_sequence_position_map)
exportXMLPageObjects(&$a_xml_writer, $inst, &$expLog)
export page objects to xml (see ilias_co.dtd)
storeMarkSchema(MarkSchema $mark_schema)
& createTestSequence($active_id, $pass, $shuffle)
createQuestionGUI($question_type, $question_id=-1)
Creates a question GUI instance of a given question type.
sendAdvancedNotification(int $active_id)
questionMoveDown($question_id)
Moves a question down in order.
isMaxProcessingTimeReached(int $starting_time, int $active_id)
Returns whether the maximum processing time for a test is reached or not.
$metadata
A reference to an IMS compatible matadata set.
addToNewsOnOnline(bool $old_online_status, bool $new_online_status)
getExtraTime(int $active_id)
getWorkingTimeOfParticipantForPass(int $active_id, int $pass)
@depracated 11, will be removed in 12, use TestResultManager::fetchWorkingTime instead
ilTestParticipantAccessFilterFactory $participant_access_filter
hasQuestionsWithoutQuestionpool()
exportFileItems($target_dir, &$expLog)
export files of file itmes
getQuestionsOfTest(int $active_id)
getImagePath()
Returns the image path for web accessable images of a test The image path is under the CLIENT_WEB_DIR...
getShowSolutionSignature()
Returns if the signature field should be shown in the test results.
getHighscoreAnon()
Gets if the highscores should be anonymized per setting.
exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export media objects to xml (see ilias_co.dtd)
getPassScoring()
Gets the pass scoring type.
ScoreSettingsRepository $score_settings_repo
isShowGradingStatusEnabled()
isHighscoreAnon()
Gets if the highscores should be displayed anonymized.
getShowSolutionAnswersOnly()
Returns if the full solution (including ILIAS content) should be presented to the solution or not.
MarksRepository $marks_repository
startingTimeReached()
Returns true if the starting time of a test is reached A starting time is not available for self asse...
getProcessingTimeInSeconds(int $active_id=0)
getProcessingTimeForXML()
getShowPassDetails()
Returns if the pass details should be shown when a test is not finished.
getQuestionSetTypeTranslation(ilLanguage $lng, $questionSetType)
Filesystem $filesystem_web
applyDefaults(array $test_defaults)
getQuestionsOfPass(int $active_id, int $pass)
static _lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object.
getShowSolutionFeedback()
Returns if the feedback should be presented to the solution or not.
$test_sequence
contains the test sequence data
getTimeExtensionsOfParticipants()
const QUESTION_SET_TYPE_FIXED
duplicateQuestionForTest($question_id)
Takes a question and creates a copy of the question for use in the test.
_getLastAccess(int $active_id)
isActiveTestSubmitted($user_id=null)
returns if the active for user_id has been submitted
getTestResult(int $active_id, ?int $attempt=null, bool $ordered_sequence=false, bool $consider_hidden_questions=true, bool $consider_optional_questions=true)
Calculates the results of a test for a given user and returns an array with all test results.
bool $activation_visibility
evalStatistical($active_id)
Returns the statistical evaluation of the test for a specified user.
cloneObject(int $target_id, int $copy_id=0, bool $omit_tree=false)
Clone object.
isExecutable($test_session, $user_id, $allow_pass_increase=false)
Checks if the test is executable by the given user.
addIntroductionToSettingsFromImport(SettingsIntroduction $settings, array $material, string $importdir, array $mappings)
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
getAuthor()
Gets the authors name of the ilObjTest object.
getAnswerFeedbackPoints()
getFixedQuestionSetTotalPoints()
isTestQuestion(int $question_id)
getScoreCutting()
Determines if the score of a question should be cut at 0 points or the score of the whole test.
getShowSolutionSuggested()
getHighscorePercentage()
Gets if the percentage column should be shown.
getQuestionCountWithoutReloading()
addDefaults($a_name)
Adds the defaults of this test to the test defaults.
prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output in tests.
getTestParticipantsForManualScoring($filter=null)
getHtmlQuestionContentPurifier()
getAvailableQuestions($arr_filter, $completeonly=0)
Calculates the available questions for a test.
static _getObjectIDFromTestID($test_id)
Returns the ILIAS test object id for a given test id.
fromXML(ilQTIAssessment $assessment, array $mappings)
Receives parameters from a QTI parser and creates a valid ILIAS test object.
isSkillServiceToBeConsidered()
Returns whether this test must consider skills, usually by providing appropriate extensions in the us...
modifyExportIdentifier($a_tag, $a_param, $a_value)
Returns the installation id for a given identifier.
lookupQuestionSetTypeByActiveId(int $active_id)
buildDateTimeImmutableFromPeriod(?string $period)
updateWorkingTime($times_id)
Update the working time of a test when a question is answered.
canShowTestResults(ilTestSession $test_session)
removeQuestion(int $question_id)
static isSkillManagementGloballyActivated()
evalTotalStartedAverageTime(?array $active_ids_to_filter=null)
addQTIMaterial(ilXmlWriter &$xml_writer, ?int $page_id, string $material='')
buildStatisticsAccessFilteredParticipantList()
$evaluation_data
Contains the evaluation data settings the tutor defines for the user.
getGenericAnswerFeedback()
static _getUserIdFromActiveId(int $active_id)
doCreateMetaData()
@inheritDoc
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...
isRandomTest()
Returns the fact wether this test is a random questions test or not.
getQuestionType($question_id)
Returns the question type of a question with a given id.
getShowSolutionPrintview()
Returns if the solution printview should be presented to the user or not.
setAccessFilteredParticipantList(ilTestParticipantList $access_filtered_participant_list)
MainSettings $main_settings
removeTestResultsByUserIds(array $user_ids)
getAvailableDefaults()
Returns the available test defaults for the active user.
setQuestionSetSolved($value, $question_id, $user_id)
sets question solved state to value for given user_id
isFixedTest()
Returns the fact wether this test is a fixed question set test or not.
isComplete(ilTestQuestionSetConfig $test_question_set_config)
replaceMobsInPageImports(string $text, array $mappings)
& _getCompleteWorkingTimeOfParticipants($test_id)
Returns the complete working time in seconds for all test participants.
getTestDefaults($test_defaults_id)
deleteDefaults($test_default_id)
convertTimeToDateTimeImmutableIfNecessary(DateTimeImmutable|int|null $date_time)
isTestFinished($active_id)
returns if the active for user_id has been submitted
static _getBestPass($active_id)
Retrieves the best pass of a given user for a given test.
static getSingleManualFeedback(int $active_id, int $question_id, int $pass)
getQuestionDataset($question_id)
Returns the dataset for a given question id.
insertQuestion(int $question_id, bool $link_only=false)
getAggregatedResultsData()
int $activation_starting_time
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
getHighscoreTopNum(int $a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
Repository $test_result_repository
isHTML($a_text)
Checks if a given string contains HTML or not.
& getWorkedQuestions($active_id, $pass=null)
Gets the id's of all questions a user already worked through.
getListOfQuestionsSettings()
Returns the settings for the list of questions options in the test properties This could contain one ...
startWorkingTime($active_id, $pass)
Write the initial entry for the tests working time to the database.
isFollowupQuestionAnswerFixationEnabled()
getCompleteWorkingTime($user_id)
Returns the complete working time in seconds a user worked on the test.
getQuestionTitle($title, $nr=null, $points=null)
Returns the title of a test question and checks if the title output is allowed.
static buildExamId($active_id, $pass, $test_obj_id=null)
getMailNotificationType()
setTemplate(int $template_id)
getAllTestResults($participants)
returns all test results for all participants
GlobalSettingsRepository $global_settings_repo
static _getPassScoring(int $active_id)
Gets the pass scoring type.
deliverPDFfromHTML($content, $title=null)
Delivers a PDF file from XHTML.
buildName(?int $user_id, ?string $firstname, ?string $lastname)
Builds a user name for the output depending on test type and existence of the user.
getImagePathWeb()
Returns the web image path for web accessable images of a test The image path is under the web access...
isShowExamIdInTestResultsEnabled()
static _createImportDirectory()
creates data directory for import files (data_dir/tst_data/tst_<id>/import, depending on data directo...
create()
note: title, description and type should be set when this function is called
retrieveMobsFromLegacyImports(string $text, array $mobs, string $importdir)
static _getAvailableTests($use_object_id=false)
Returns the available tests for the active user.
ilTestQuestionSetConfigFactory $question_set_config_factory
getCompleteWorkingTimeOfParticipant($active_id)
Returns the complete working time in seconds for a test participant.
getCompleteEvaluationData($filterby='', $filtertext='')
evalTotalPersons()
Returns the number of persons who started the test.
getUnfilteredEvaluationData()
removeTestActives(array $active_ids)
removeTestResults(ilTestParticipantData $participant_data)
isInstantFeedbackAnswerFixationEnabled()
evalTotalParticipantsArray(string $name_sort_order='asc')
saveManualFeedback(int $active_id, int $question_id, int $pass, ?string $feedback, bool $finalized=false)
copyQuestions(array $question_ids)
getSpecificAnswerFeedback()
saveCompleteStatus(ilTestQuestionSetConfig $test_question_set_config)
bool $print_best_solution_with_result
saveAuthorToMetadata($author="")
Saves an authors name into the lifecycle metadata if no lifecycle metadata exists This will only be c...
isPluginActive($a_pname)
Checks wheather or not a question plugin with a given name is active.
evalTotalPersonsArray(string $name_sort_order='asc')
deliverPDFfromFO($fo, $title=null)
Delivers a PDF file from a XSL-FO string.
static getManualFeedback(int $active_id, int $question_id, ?int $pass)
Retrieves the feedback comment for a question in a test if it is finalized.
GeneralQuestionPropertiesRepository $questionrepository
toXML()
Returns a QTI xml representation of the test.
static lookupPassResultsUpdateTimestamp($active_id, $pass)
ilComponentFactory $component_factory
setTmpCopyWizardCopyId(int $tmpCopyWizardCopyId)
$participantDataExist
holds the fact wether participant data exists or not DO NOT USE TIS PROPERTY DRIRECTLY ALWAYS USE ilO...
getHighscoreScore()
Gets if the score column should be shown.
static isParticipantsLastPassActive(int $test_ref_id, int $user_id)
isBlockPassesAfterPassedEnabled()
getConcludingRemarksPageId()
ilComponentRepository $component_repository
static _lookupFinishedUserTests($a_user_id)
Gather all finished tests for user.
getAvailableQuestionpools(bool $use_object_id=false, ?bool $equal_points=false, bool $could_be_offline=false, bool $show_path=false, bool $with_questioncount=false, string $permission='read')
Returns the available question pools for the active user.
getImportMapping()
get array of (two) new created questions for import id
insertManualFeedback(int $active_id, int $question_id, int $pass, ?string $feedback, bool $finalized, array $feedback_old)
ScoreSettings $score_settings
secondsToHoursMinutesSecondsString(int $seconds)
getVisitingTimeOfParticipant(int $active_id)
getCompleteManualFeedback(int $question_id)
Retrieves the manual feedback for a question in a test.
getListOfQuestionsDescription()
ilTestParticipantList $access_filtered_participant_list
getActiveIdOfUser($user_id="", $anonymous_id="")
Gets the active id of a given user.
removeTestResultsByActiveIds(array $active_ids)
recalculateScores($preserve_manscoring=false)
TestManScoringDoneHelper $test_man_scoring_done_helper
qtiMaterialToArray($a_material)
Reads an QTI material tag and creates a text string.
moveQuestions(array $move_questions, int $target_index, int $insert_mode)
getGeneralQuestionPropertiesRepository()
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions
static _lookupAnonymity($a_obj_id)
ParticipantRepository $participant_repository
getUsrPassOverviewEnabled()
getJavaScriptOutput()
Returns if Javascript should be chosen for drag & drop actions for the active user.
setQuestionSetType(string $question_set_type)
getTextAnswer($active_id, $question_id, $pass=null)
Returns the text answer of a given user for a given question.
userLookupFullName($user_id, $overwrite_anonymity=false, $sorted_order=false, $suffix="")
Returns the full name of a test user according to the anonymity status.
getParticipants()
Returns all persons who started the test.
getNrOfResultsForPass($active_id, $pass)
Calculates the number of user results for a specific test pass.
isShowGradingMarkEnabled()
int $activation_ending_time
getStartingTimeOfParticipants()
Note, this function should only be used if absolutely necessary, since it perform joins on tables tha...
getShowSolutionListOwnAnswers()
getAccessFilteredParticipantList()
removeQuestions(array $question_ids)
getQuestionCountAndPointsForPassOfParticipant(int $active_id, int $pass)
isTestFinishedToViewResults($active_id, $currentpass)
Returns true if an active user completed a test pass and did not start a new pass.
getMainSettingsRepository()
removeQuestionWithResults(int $question_id, TestScoring $scoring)
hasNrOfTriesRestriction()
returns if the numbers of tries have to be checked
clonePage(int $source_page_id)
TestLogViewer $log_viewer
getParticipantsForTestAndQuestion($test_id, $question_id)
Creates an associated array with all active id's for a given test and original question id.
getTitleFilenameCompliant()
returns the object title prepared to be used as a filename
questionMoveUp($question_id)
Moves a question up in order.
MainSettingsRepository $main_settings_repo
isForceInstantFeedbackEnabled()
& getCompleteWorkingTimeOfParticipants()
Returns the complete working time in seconds for all test participants.
static _lookupTestObjIdForQuestionId(int $q_id)
Get test Object ID for question ID.
exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export pages of test to xml (see ilias_co.dtd)
isScoreReportingEnabled()
static _lookupName(int $a_user_id)
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
static getInstance(int $obj_id)
Class ilObject Basic functions for all objects.
static _prepareCloneSelection(array $ref_ids, string $new_type, bool $show_path=true)
Prepare copy wizard object selection.
Properties $object_properties
static _lookupObjId(int $ref_id)
static _lookupTitle(int $obj_id)
static _lookupDescription(int $obj_id)
static collectFileItems(ilPageObject $a_page, DOMDocument $a_domdoc)
Get all file items that are used within the page.
getPresentationMaterial()
static _replaceMediaObjectImageSrc(string $a_text, int $a_direction=0, string $nic='')
Replaces image source from mob image urls with the mob id or replaces mob id with the correct image s...
static factory(string $a_package, int $a_timeout=0)
Creates an ilRpcClient instance to our ilServer.
static get(string $a_var)
static clear(string $a_var)
Skill management settings.
special template class to simplify handling of ITX/PEAR
Base Exception for all Exceptions relating to Modules/Test.
Class ilTestMailNotification.
@ilCtrl_Calls ilTestPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI @ilCtrl_Calls ilTestP...
@ilCtrl_Calls ilTestEditPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI @ilCtrl_Calls ilT...
getUserIdByActiveId($activeId)
getLastFinishedPassTimestamp()
isQuestionSetConfigured()
static isManScoringDone(int $active_id)
static getStyleSheetLocation(string $mode="output", string $a_css_name="")
get full style sheet file name (path inclusive) of current user
static insertInstIntoID(string $a_value)
inserts installation id into ILIAS id
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,...
static deliverData(string $a_data, string $a_filename, string $mime="application/octet-stream")
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content)
xmlEndTag(string $tag)
Writes an endtag.
xmlStartTag(string $tag, ?array $attrs=null, bool $empty=false, bool $encode=true, bool $escape=true)
Writes a starttag.
return['delivery_method'=> 'php',]
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
The filesystem interface provides the public interface for the Filesystem service API consumer.
Readable part of repository interface to ilComponentDataDB.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
Interface for html sanitizing functionality.
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
__construct(Container $dic, ilPlugin $plugin)
@inheritDoc
trait TestQuestionsImportTrait
buildImportDirectoryFromImportFile(string $file_to_import)
TestAdministrationInteractionTypes
TestScoringInteractionTypes
Class ilObjForumAdministration.
if(!file_exists('../ilias.ini.php'))