19declare(strict_types=1);
160 public function __construct(
int $id = 0,
bool $a_call_by_reference =
true)
166 $this->
ctrl = $DIC[
'ilCtrl'];
168 $this->
settings = $DIC[
'ilSetting'];
169 $this->bench =
$DIC[
'ilBench'];
170 $this->component_repository =
$DIC[
'component.repository'];
171 $this->component_factory =
$DIC[
'component.factory'];
172 $this->filesystem_web =
$DIC->filesystem()->web();
173 $this->lo_metadata =
$DIC->learningObjectMetadata();
174 $this->media_object_repository =
$DIC->mediaObjects()->internal()->repo()->mediaObject();
175 $this->irss =
$DIC->resourceStorage();
178 $this->participant_access_filter = $local_dic[
'participant.access_filter.factory'];
179 $this->test_man_scoring_done_helper = $local_dic[
'scoring.manual.done_helper'];
180 $this->
logger = $local_dic[
'logging.logger'];
181 $this->log_viewer = $local_dic[
'logging.viewer'];
182 $this->global_settings_repo = $local_dic[
'settings.global.repository'];
183 $this->marks_repository = $local_dic[
'marks.repository'];
184 $this->settings_factory = $local_dic[
'settings.factory'];
185 $this->questionrepository = $local_dic[
'question.general_properties.repository'];
186 $this->testrequest = $local_dic[
'request_data_collector'];
187 $this->participant_repository = $local_dic[
'participant.repository'];
188 $this->export_factory = $local_dic[
'exportimport.factory'];
189 $this->test_result_repository = $local_dic[
'results.data.repository'];
190 $this->main_settings_repository = $local_dic[
'settings.main.repository'];
191 $this->score_settings_repository = $local_dic[
'settings.scoring.repository'];
195 $this->
lng->loadLanguageModule(
"assessment");
196 $this->score_settings =
null;
203 $this->component_repository,
205 $this->questionrepository
211 return TestDIC::dic();
226 return $this->question_set_config_factory->getQuestionSetConfig();
249 $id = parent::create();
256 if (!parent::update()) {
268 $this->main_settings =
null;
269 $this->score_settings =
null;
270 $this->mark_schema =
null;
274 public function delete():
bool
277 if (!parent::delete()) {
288 $qsaImportFails->deleteRegisteredImportFails();
290 $sltImportFails->deleteRegisteredImportFails();
292 if ($this->
logger->isLoggingEnabled()) {
293 $this->
logger->logTestAdministrationInteraction(
294 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
296 $this->user->getId(),
299 AdditionalInformationGenerator::KEY_TEST_TITLE => $test_title = $this->title
311 $participantData->load($this->
getTestId());
314 $this->db->manipulateF(
315 "DELETE FROM tst_mark WHERE test_fi = %s",
320 $this->db->manipulateF(
321 "DELETE FROM tst_tests WHERE test_id = %s",
326 $this->db->manipulateF(
327 "DELETE FROM tst_test_settings WHERE id = %s",
333 $directory = $tst_data_dir .
"/tst_" . $this->
getId();
334 if (is_dir($directory)) {
342 foreach ($mobs as $mob) {
360 if (!is_writable($tst_data_dir)) {
361 $this->
ilias->raiseError(
"Test Data Directory (" . $tst_data_dir
362 .
") not writeable.", $this->
ilias->error_obj->MESSAGE);
366 $tst_dir = $tst_data_dir .
"/tst_" . $this->
getId();
368 if (!@is_dir($tst_dir)) {
369 $this->
ilias->raiseError(
"Creation of Test Directory failed.", $this->
ilias->error_obj->MESSAGE);
372 $export_dir = $tst_dir .
"/export";
374 if (!@is_dir($export_dir)) {
375 $this->
ilias->raiseError(
"Creation of Export Directory failed.", $this->
ilias->error_obj->MESSAGE);
385 public function getExportFiles(
string $dir =
''): array
388 if (!@is_dir($dir) || !is_writable($dir)) {
393 foreach (
new DirectoryIterator($dir) as $file) {
397 if ($file->isDir()) {
401 $files[] = $file->getBasename();
421 if (!is_writable($tst_data_dir)) {
423 .
") not writeable.",
$ilias->error_obj->FATAL);
427 $tst_dir = $tst_data_dir .
"/tst_import";
429 if (!@is_dir($tst_dir)) {
456 if ($this->
isComplete($test_question_set_config)) {
460 $this->db->manipulateF(
461 'UPDATE tst_tests SET complete = %s WHERE test_id = %s',
463 [$complete, $this->test_id]
468 public function saveToDb(
bool $properties_only =
false): void
470 if ($this->test_id === -1) {
472 $next_id = $this->db->nextId(
'tst_tests');
477 'test_id' => [
'integer', $next_id],
478 'obj_fi' => [
'integer', $this->
getId()],
479 'created' => [
'integer', time()],
480 'tstamp' => [
'integer', time()],
485 $this->test_id = $next_id;
488 $this->settings_factory->createDefaultMainSettings(),
496 $aresult = $this->db->queryF(
497 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
498 [
'integer',
'integer',
'integer'],
501 while ($row = $this->db->fetchAssoc($aresult)) {
502 $this->db->manipulateF(
503 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
504 [
'integer',
'timestamp',
'integer'],
505 [1, date(
'Y-m-d H:i:s'), $row[
"active_id"]]
510 $aresult = $this->db->queryF(
511 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
512 [
'integer',
'integer',
'integer'],
515 while ($row = $this->db->fetchAssoc($aresult)) {
516 $this->db->manipulateF(
517 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
518 [
'integer',
'timestamp',
'integer'],
519 [0,
null, $row[
"active_id"]]
524 $aresult = $this->db->queryF(
525 "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
526 [
'integer',
'integer'],
529 while ($row = $this->db->fetchAssoc($aresult)) {
530 $this->db->manipulateF(
531 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
532 [
'integer',
'timestamp',
'integer'],
533 [0,
null, $row[
"active_id"]]
540 if ($properties_only) {
548 $this->marks_repository->storeMarkSchema($this->
getMarkSchema());
553 $this->db->manipulateF(
554 'DELETE FROM tst_test_question WHERE test_fi = %s',
558 foreach ($this->questions as $key => $value) {
559 $next_id = $this->db->nextId(
'tst_test_question');
560 $this->db->insert(
'tst_test_question', [
561 'test_question_id' => [
'integer', $next_id],
562 'test_fi' => [
'integer', $this->
getTestId()],
563 'question_fi' => [
'integer', $value],
564 'sequence' => [
'integer', $key],
565 'tstamp' => [
'integer', time()]
578 foreach ($question_ids as
$id) {
579 $question = assQuestion::instantiateQuestionGUI(
$id);
581 $title = $question->getObject()->getTitle();
583 while (in_array(
$title .
' (' . $i .
')', $question_titles)) {
587 $title .=
' (' . $i .
')';
589 $question_titles[] =
$title;
591 $new_id = $question->getObject()->duplicate(
false,
$title);
593 $clone = assQuestion::instantiateQuestionGUI($new_id);
594 $question = $clone->getObject();
595 $question->setObjId($this->
getId());
596 $clone->setObject($question);
597 $clone->getObject()->saveToDb();
611 $result = $this->db->queryF(
612 "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
613 [
'integer',
'integer'],
616 return $result->numRows();
621 $result = $this->db->queryF(
622 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
626 if ($result->numRows() === 1) {
627 $data = $this->db->fetchObject($result);
639 $this->questions = [];
641 if ($active_id === 0) {
644 if (is_null($pass)) {
647 $result = $this->db->queryF(
648 'SELECT tst_test_rnd_qst.* '
649 .
'FROM tst_test_rnd_qst, qpl_questions '
650 .
'WHERE tst_test_rnd_qst.active_fi = %s '
651 .
'AND qpl_questions.question_id = tst_test_rnd_qst.question_fi '
652 .
'AND tst_test_rnd_qst.pass = %s '
653 .
'ORDER BY sequence',
654 [
'integer',
'integer'],
658 $result = $this->db->queryF(
659 'SELECT tst_test_question.* '
660 .
'FROM tst_test_question, qpl_questions '
661 .
'WHERE tst_test_question.test_fi = %s '
662 .
'AND qpl_questions.question_id = tst_test_question.question_fi '
663 .
'ORDER BY sequence',
669 if ($this->test_id !== -1) {
671 while (
$data = $this->db->fetchAssoc($result)) {
672 $this->questions[$index++] =
$data[
"question_fi"];
679 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
680 return $page_id !==
null
687 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
688 if ($page_id ===
null) {
696 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
697 return $page_id !==
null
704 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
705 if ($page_id ===
null) {
714 $page_object->setParentId($this->
getId());
715 $new_page_id = $page_object->createPageWithNextId();
716 (
new ilTestPage($source_page_id))->copy($new_page_id);
730 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getPostponedQuestionsMoveToEnd();
735 return $this->
getScoreSettings()->getResultSummarySettings()->getScoreReporting()->isReportingEnabled();
740 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled();
745 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled();
750 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled();
763 return TestDIC::dic()[
'settings.scoring.repository']->getFor(
810 if ($this->mark_schema ===
null) {
811 $this->mark_schema = $this->marks_repository->getMarkSchemaFor($this->
getTestId());
820 $this->mark_schema =
null;
825 return $this->
getMainSettings()->getTestBehaviourSettings()->getNumberOfTries();
830 return $this->
getMainSettings()->getTestBehaviourSettings()->getBlockAfterPassedEnabled();
835 return $this->
getMainSettings()->getTestBehaviourSettings()->getKioskModeEnabled();
840 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowTitleInKioskMode();
844 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowParticipantNameInKioskMode();
849 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed();
854 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getQuestionTitleOutputMode();
864 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
869 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
870 if ($processing_time ===
null
871 || $processing_time ===
''
872 || !preg_match(
'/(\d{2}):(\d{2}):(\d{2})/is', $processing_time, $matches)
887 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime() ??
'';
888 if (preg_match(
"/(\d{2}):(\d{2}):(\d{2})/", (
string) $processing_time, $matches)) {
890 return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
898 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTimeEnabled();
903 return $this->
getMainSettings()->getTestBehaviourSettings()->getResetProcessingTime();
908 return $this->
getMainSettings()->getAccessSettings()->getStartTimeEnabled();
913 $start_time = $this->
getMainSettings()->getAccessSettings()->getStartTime();
914 return $start_time !==
null ? $start_time->getTimestamp() : 0;
919 return $this->
getMainSettings()->getAccessSettings()->getEndTimeEnabled();
924 $end_time = $this->
getMainSettings()->getAccessSettings()->getEndTime();
925 return $end_time !==
null ? $end_time->getTimestamp() : 0;
930 return $this->
getMainSettings()->getAccessSettings()->getPasswordEnabled();
944 $this->test_result_repository
958 $participant_data->load($this->test_id);
960 $question->removeAllExistingSolutions();
967 $participant_data->getActiveIds(),
968 $this->reindexFixedQuestionOrdering()
974 $question->delete($question_id);
983 if ($this->
logger->isLoggingEnabled()) {
984 $this->
logger->logTestAdministrationInteraction(
985 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
987 $this->user->getId(),
988 TestAdministrationInteractionTypes::QUESTION_REMOVED_IN_CORRECTIONS,
990 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question->getTitleForHTMLOutput(),
991 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $question->getQuestion(),
992 AdditionalInformationGenerator::KEY_QUESTION_ID => $question->getId(),
993 AdditionalInformationGenerator::KEY_QUESTION_TYPE => $question->getQuestionType()
1011 $this->questionrepository
1014 foreach ($active_ids as $active_id) {
1016 $passSelector->setActiveId($active_id);
1018 foreach ($passSelector->getExistingPasses() as $pass) {
1019 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $pass);
1022 $test_sequence->removeQuestion($question_id, $reindexed_sequence_position_map);
1033 foreach ($question_ids as $question_id) {
1034 $this->removeQuestion((
int) $question_id);
1037 $this->reindexFixedQuestionOrdering();
1043 $question = self::_instanciateQuestion($question_id);
1044 $question_title = $question->getTitleForHTMLOutput();
1045 $question->delete($question_id);
1046 if ($this->
logger->isLoggingEnabled()) {
1047 $this->
logger->logTestAdministrationInteraction(
1048 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1050 $this->user->getId(),
1051 TestAdministrationInteractionTypes::QUESTION_REMOVED,
1053 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question_title
1058 }
catch (InvalidArgumentException
$e) {
1059 $this->
logger->error($e->getMessage());
1060 $this->
logger->error($e->getTraceAsString());
1074 $this->removeTestResultsByUserIds($user_ids);
1077 $participantData->setUserIdsFilter($user_ids);
1078 $participantData->load($this->getTestId());
1080 $this->removeTestActives($participantData->getActiveIds());
1083 if ($this->
logger->isLoggingEnabled()) {
1084 $this->
logger->logTestAdministrationInteraction(
1085 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1087 $this->user->getId(),
1088 TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
1090 AdditionalInformationGenerator::KEY_USERS => $participantData->getUserIds()
1102 $user_ids = array_map(
1106 $this->participant_repository->removeExtraTimeByUserId($this->getTestId(), $user_ids);
1109 if ($participant_data->
getUserIds() !== []) {
1112 if ($test_lp instanceof
ilTestLP) {
1113 $test_lp->setTestObject($this);
1114 $test_lp->resetLPDataForUserIds($participant_data->
getUserIds(),
false);
1117 $this->participant_repository->removeExtraTimeByUserId($this->getTestId(), $participant_data->
getUserIds());
1121 $this->removeTestActives($participant_data->
getActiveIds());
1123 $user_ids = array_map(
1127 $this->participant_repository->removeExtraTimeByUserId($this->getTestId(), $user_ids);
1130 if ($this->
logger->isLoggingEnabled()) {
1131 $this->
logger->logTestAdministrationInteraction(
1132 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1134 $this->user->getId(),
1135 TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
1137 AdditionalInformationGenerator::KEY_USERS => $participant_data->
getUserIds(),
1148 $participantData->setUserIdsFilter($user_ids);
1149 $participantData->load($this->getTestId());
1151 $in_user_ids = $this->db->in(
'usr_id', $participantData->getUserIds(),
false,
'integer');
1152 $this->db->manipulateF(
1153 "DELETE FROM usr_pref WHERE {$in_user_ids} AND keyword = %s",
1155 [
'tst_password_' . $this->getTestId()]
1158 if ($participantData->getActiveIds() !== []) {
1159 $this->removeTestResultsByActiveIds($participantData->getActiveIds());
1165 $in_active_ids = $this->db->in(
'active_fi', $active_ids,
false,
'integer');
1167 $this->db->manipulate(
"DELETE FROM tst_solutions WHERE {$in_active_ids}");
1168 $this->db->manipulate(
"DELETE FROM tst_qst_solved WHERE {$in_active_ids}");
1169 $this->db->manipulate(
"DELETE FROM tst_test_result WHERE {$in_active_ids}");
1170 $this->db->manipulate(
"DELETE FROM tst_pass_result WHERE {$in_active_ids}");
1171 $this->db->manipulate(
"DELETE FROM tst_result_cache WHERE {$in_active_ids}");
1172 $this->db->manipulate(
"DELETE FROM tst_sequence WHERE {$in_active_ids}");
1173 $this->db->manipulate(
"DELETE FROM tst_times WHERE {$in_active_ids}");
1174 $this->db->manipulate(
1176 .
' WHERE ' . $this->db->in(
'active_id', $active_ids,
false,
'integer')
1179 if ($this->isRandomTest()) {
1180 $this->db->manipulate(
"DELETE FROM tst_test_rnd_qst WHERE {$in_active_ids}");
1183 $this->test_result_repository->removeTestResults($active_ids, $this->
getId());
1185 foreach ($active_ids as $active_id) {
1187 if (is_dir(
CLIENT_WEB_DIR .
"/assessment/tst_" . $this->getTestId() .
"/$active_id")) {
1198 $IN_activeIds = $this->db->in(
'active_id', $active_ids,
false,
'integer');
1199 $this->db->manipulate(
"DELETE FROM tst_active WHERE $IN_activeIds");
1212 $result = $this->db->queryF(
1213 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1214 [
'integer',
'integer'],
1215 [$this->getTestId(), $question_id]
1217 $data = $this->db->fetchObject($result);
1218 if (
$data->sequence > 1) {
1220 $result = $this->db->queryF(
1221 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1222 [
'integer',
'integer'],
1223 [$this->getTestId(),
$data->sequence - 1]
1225 $data_previous = $this->db->fetchObject($result);
1227 $this->db->manipulateF(
1228 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1229 [
'integer',
'integer'],
1230 [
$data->sequence, $data_previous->test_question_id]
1233 $this->db->manipulateF(
1234 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1235 [
'integer',
'integer'],
1236 [
$data->sequence - 1,
$data->test_question_id]
1239 $this->loadQuestions();
1251 $current_question_result = $this->db->queryF(
1252 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1253 [
'integer',
'integer'],
1254 [$this->getTestId(), $question_id]
1256 $current_question_data = $this->db->fetchObject($current_question_result);
1257 $next_question_result = $this->db->queryF(
1258 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1259 [
'integer',
'integer'],
1260 [$this->getTestId(), $current_question_data->sequence + 1]
1262 if ($this->db->numRows($next_question_result) === 1) {
1264 $next_question_data = $this->db->fetchObject($next_question_result);
1266 $this->db->manipulateF(
1267 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1268 [
'integer',
'integer'],
1269 [$current_question_data->sequence, $next_question_data->test_question_id]
1272 $this->db->manipulateF(
1273 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1274 [
'integer',
'integer'],
1275 [$current_question_data->sequence + 1, $current_question_data->test_question_id]
1278 $this->loadQuestions();
1290 $duplicate_id = $question->duplicate(
true,
'',
'', -1, $this->
getId());
1291 return $duplicate_id;
1297 $duplicate_id = $question_id;
1299 $duplicate_id = $this->duplicateQuestionForTest($question_id);
1303 $result = $this->db->queryF(
1304 "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
1306 [$this->getTestId()]
1310 if ($result->numRows() == 1) {
1311 $data = $this->db->fetchObject($result);
1312 $sequence =
$data->seq + 1;
1315 $next_id = $this->db->nextId(
'tst_test_question');
1316 $this->db->manipulateF(
1317 "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
1318 [
'integer',
'integer',
'integer',
'integer',
'integer'],
1319 [$next_id, $this->getTestId(), $duplicate_id, $sequence, time()]
1322 $this->db->manipulateF(
1323 "DELETE FROM tst_active WHERE test_fi = %s",
1325 [$this->getTestId()]
1327 $this->loadQuestions();
1328 $this->saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
1330 if ($this->
logger->isLoggingEnabled()) {
1331 $this->
logger->logTestAdministrationInteraction(
1332 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1334 $this->user->getId(),
1335 TestAdministrationInteractionTypes::QUESTION_ADDED,
1337 AdditionalInformationGenerator::KEY_QUESTION_ID => $question_id
1339 ->toLog($this->logger->getAdditionalInformationGenerator())
1344 return $duplicate_id;
1350 if ($this->getQuestionSetType() === self::QUESTION_SET_TYPE_FIXED) {
1351 $result = $this->db->queryF(
1352 'SELECT qpl_questions.title FROM tst_test_question, qpl_questions '
1353 .
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id '
1354 .
'ORDER BY tst_test_question.sequence',
1356 [$this->getTestId()]
1358 while ($row = $this->db->fetchAssoc($result)) {
1359 array_push($titles, $row[
'title']);
1375 if ($this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED) {
1376 $result = $this->db->queryF(
1377 'SELECT qpl_questions.title, qpl_questions.question_id '
1378 .
'FROM tst_test_question, qpl_questions '
1379 .
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id '
1380 .
'ORDER BY tst_test_question.sequence',
1382 [$this->getTestId()]
1384 while ($row = $this->db->fetchAssoc($result)) {
1385 $titles[$row[
'question_id']] = $row[
"title"];
1403 switch ($this->getTitleOutput()) {
1410 return $this->
lng->txt(
"ass_question") .
' ' . $nr;
1412 return $this->
lng->txt(
"ass_question");
1416 $txt = $this->
lng->txt(
"ass_question") .
' ' . $nr;
1418 $txt = $this->
lng->txt(
"ass_question");
1420 if ($points !=
'') {
1421 $lngv = $this->
lng->txt(
'points');
1423 $lngv = $this->
lng->txt(
'point');
1425 $txt .=
' - ' . $points .
' ' . $lngv;
1431 return $this->
lng->txt(
"ass_question");
1445 $result = $this->db->queryF(
1446 "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",
1450 $row = $this->db->fetchObject($result);
1462 $existing_questions = [];
1463 $active_id = $this->getActiveIdOfUser($this->
user->getId());
1464 if ($this->isRandomTest()) {
1465 if (is_null($pass)) {
1468 $result = $this->db->queryF(
1469 "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",
1470 [
'integer',
'integer'],
1474 $result = $this->db->queryF(
1475 "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",
1477 [$this->getTestId()]
1480 while (
$data = $this->db->fetchObject($result)) {
1481 if (
$data->original_id ===
null) {
1485 array_push($existing_questions,
$data->original_id);
1487 return $existing_questions;
1499 if ($question_id < 1) {
1502 $result = $this->db->queryF(
1503 "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",
1507 if ($result->numRows() == 1) {
1508 $data = $this->db->fetchObject($result);
1509 return $data->type_tag;
1523 $next_id = $this->db->nextId(
'tst_times');
1524 $affectedRows = $this->db->manipulateF(
1525 "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
1526 [
'integer',
'integer',
'timestamp',
'timestamp',
'integer',
'integer'],
1527 [$next_id, $active_id, date(
"Y-m-d H:i:s"), date(
"Y-m-d H:i:s"), $pass, time()]
1540 $affectedRows = $this->db->manipulateF(
1541 "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
1542 [
'timestamp',
'integer',
'integer'],
1543 [date(
'Y-m-d H:i:s'), time(), $times_id]
1555 if (is_null($pass)) {
1556 $result = $this->db->queryF(
1557 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1558 [
'integer',
'integer'],
1562 $result = $this->db->queryF(
1563 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1564 [
'integer',
'integer'],
1569 while ($row = $this->db->fetchAssoc($result)) {
1570 array_push($result_array, $row[
"question_fi"]);
1572 return $result_array;
1586 return ((($currentpass > 0) && ($num == 0)) || $this->isTestFinished($active_id)) ?
true :
false;
1597 if ($this->isRandomTest()) {
1598 $active_id = $this->getActiveIdOfUser($this->
user->getId());
1599 if ($active_id ===
null) {
1602 $this->loadQuestions($active_id, $pass);
1603 if (count($this->questions) === 0) {
1606 if (is_null($pass)) {
1607 $pass = self::_getPass($active_id);
1609 $result = $this->db->queryF(
1610 "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'),
1611 [
'integer',
'integer'],
1615 if (count($this->questions) === 0) {
1618 $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'));
1621 while ($row = $this->db->fetchAssoc($result)) {
1622 $result_array[$row[
"question_id"]] = $row;
1624 return $result_array;
1642 if (is_array($tst_access_code) &&
1644 isset($tst_access_code[$this->getTestId()]) &&
1645 $tst_access_code[$this->getTestId()] !==
'') {
1646 $result = $this->db->queryF(
1647 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1648 [
'integer',
'integer',
'text'],
1649 [
$user_id, $this->test_id, $tst_access_code[$this->getTestId()]]
1651 } elseif ((
string) $anonymous_id !==
'') {
1652 $result = $this->db->queryF(
1653 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1654 [
'integer',
'integer',
'text'],
1655 [
$user_id, $this->test_id, $anonymous_id]
1661 $result = $this->db->queryF(
1662 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s',
1663 [
'integer',
'integer'],
1668 if ($result->numRows()) {
1669 $row = $this->db->fetchAssoc($result);
1670 return (
int) $row[
'active_id'];
1680 $ilUser =
$DIC[
'ilUser'];
1688 $result =
$ilDB->queryF(
1689 "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
1690 [
'integer',
'integer'],
1693 if ($result->numRows()) {
1694 $row =
$ilDB->fetchAssoc($result);
1695 return $row[
"active_id"];
1709 $keys = array_keys($array);
1712 foreach ($keys as $key) {
1713 $result[$key] = $array[$key];
1726 ?
int $attempt =
null,
1727 bool $ordered_sequence =
false,
1728 bool $consider_hidden_questions =
true,
1729 bool $consider_optional_questions =
true
1731 $test_result = $this->test_result_repository->getTestResult($active_id);
1733 if ($test_result ===
null) {
1734 $test_result = $this->test_result_repository->updateTestResultCache($active_id);
1737 if ($attempt ===
null) {
1738 $attempt = $test_result->getAttempt();
1742 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $attempt);
1744 $test_sequence->setConsiderHiddenQuestionsEnabled($consider_hidden_questions);
1745 $test_sequence->setConsiderOptionalQuestionsEnabled($consider_optional_questions);
1747 $test_sequence->loadFromDb();
1748 $test_sequence->loadQuestions();
1750 if ($ordered_sequence) {
1751 $sequence = $test_sequence->getOrderedSequenceQuestions();
1753 $sequence = $test_sequence->getUserSequenceQuestions();
1760 tst_test_result.question_fi,
1761 tst_test_result.points reached,
1762 tst_test_result.answered answered,
1763 tst_manual_fb.finalized_evaluation finalized_evaluation
1765 FROM tst_test_result
1767 LEFT JOIN tst_solutions
1768 ON tst_solutions.active_fi = tst_test_result.active_fi
1769 AND tst_solutions.question_fi = tst_test_result.question_fi
1771 LEFT JOIN tst_manual_fb
1772 ON tst_test_result.active_fi = tst_manual_fb.active_fi
1773 AND tst_test_result.question_fi = tst_manual_fb.question_fi
1775 WHERE tst_test_result.active_fi = %s
1776 AND tst_test_result.pass = %s
1779 $solutionresult = $this->db->queryF(
1781 [
'integer',
'integer'],
1782 [$active_id, $attempt]
1785 while ($row = $this->db->fetchAssoc($solutionresult)) {
1786 $arr_results[ $row[
'question_fi'] ] = $row;
1789 $result = $this->db->query(
1790 'SELECT qpl_questions.*, qpl_qst_type.type_tag, qpl_sol_sug.question_fi has_sug_sol' . PHP_EOL
1791 .
'FROM qpl_qst_type, qpl_questions' . PHP_EOL
1792 .
'LEFT JOIN qpl_sol_sug' . PHP_EOL
1793 .
'ON qpl_sol_sug.question_fi = qpl_questions.question_id' . PHP_EOL
1794 .
'WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi' . PHP_EOL
1795 .
'AND ' . $this->db->in(
'qpl_questions.question_id', $sequence,
false,
'integer')
1800 while ($row = $this->db->fetchAssoc($result)) {
1801 if (!isset($arr_results[ $row[
'question_id'] ])) {
1802 $percentvalue = 0.0;
1805 $row[
'points'] ? $arr_results[$row[
'question_id']][
'reached'] / $row[
'points'] : 0
1808 if ($percentvalue < 0) {
1809 $percentvalue = 0.0;
1815 'max' => round($row[
'points'], 2),
1816 'reached' => round($arr_results[$row[
'question_id']][
'reached'] ?? 0, 2),
1817 'percent' => sprintf(
'%2.2f ', ($percentvalue) * 100) .
'%',
1819 'type' => $row[
'type_tag'],
1820 'qid' => $row[
'question_id'],
1821 'original_id' => $row[
'original_id'],
1822 'workedthrough' => isset($arr_results[$row[
'question_id']]) ? 1 : 0,
1823 'answered' => $arr_results[$row[
'question_id']][
'answered'] ?? 0,
1824 'finalized_evaluation' => $arr_results[$row[
'question_id']][
'finalized_evaluation'] ?? 0,
1827 $unordered[ $row[
'question_id'] ] =
$data;
1835 foreach ($sequence as $qid) {
1838 $pass_max += round($unordered[$qid][
'max'], 2);
1839 $pass_reached += round($unordered[$qid][
'reached'], 2);
1840 $found[] = $unordered[$qid];
1843 if ($this->getScoreCutting() == 1) {
1844 if ($pass_reached < 0) {
1849 $found[
'pass'][
'total_max_points'] = $pass_max;
1850 $found[
'pass'][
'total_reached_points'] = $pass_reached;
1851 $found[
'pass'][
'percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
1852 $found[
'pass'][
'num_workedthrough'] = count($arr_results);
1853 $found[
'pass'][
'num_questions_total'] = count($unordered);
1855 $found[
'test'][
'total_max_points'] = $test_result->getMaxPoints();
1856 $found[
'test'][
'total_reached_points'] = $test_result->getReachedPoints();
1857 $found[
'test'][
'result_pass'] = $attempt;
1858 $found[
'test'][
'result_tstamp'] = $test_result->getTimestamp();
1859 $found[
'test'][
'passed'] = $test_result->isPassed();
1872 $result = $this->db->queryF(
1873 'SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s',
1875 [$this->getTestId()]
1877 $row = $this->db->fetchAssoc($result);
1878 return $row[
'total'];
1889 $result = $this->db->queryF(
1890 "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",
1891 [
'integer',
'integer'],
1895 while ($row = $this->db->fetchAssoc($result)) {
1896 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
1905 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
1914 $time += ($epoch_2 - $epoch_1);
1927 return $this->_getCompleteWorkingTimeOfParticipants($this->getTestId());
1939 $result = $this->db->queryF(
1940 "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",
1946 while ($row = $this->db->fetchAssoc($result)) {
1947 if (!array_key_exists($row[
"active_fi"], $times)) {
1948 $times[$row[
"active_fi"]] = 0;
1950 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
1959 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
1968 $times[$row[
"active_fi"]] += ($epoch_2 - $epoch_1);
1981 $result = $this->db->queryF(
1982 "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",
1983 [
'integer',
'integer'],
1984 [$this->getTestId(), $active_id]
1987 while ($row = $this->db->fetchAssoc($result)) {
1988 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
1997 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2006 $time += ($epoch_2 - $epoch_1);
2016 return $this->test_result_repository->fetchWorkingTime($active_id, $pass);
2025 $test_result = &$this->getTestResult($active_id, $pass);
2026 $result = $this->db->queryF(
2027 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
2034 while ($row = $this->db->fetchObject($result)) {
2035 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2044 if (!$first_visit) {
2045 $first_visit = $epoch_1;
2047 if ($epoch_1 < $first_visit) {
2048 $first_visit = $epoch_1;
2050 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2060 $last_visit = $epoch_2;
2062 if ($epoch_2 > $last_visit) {
2063 $last_visit = $epoch_2;
2065 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2068 foreach ($times as $key => $value) {
2069 $max_time += $value;
2071 if ((!$test_result[
"test"][
"total_reached_points"]) or (!$test_result[
"test"][
"total_max_points"])) {
2074 $percentage = ($test_result[
"test"][
"total_reached_points"] / $test_result[
"test"][
"total_max_points"]) * 100.0;
2075 if ($percentage < 0) {
2079 $mark_obj = $this->getMarkSchema()->getMatchingMark($percentage);
2080 $first_date = getdate($first_visit);
2081 $last_date = getdate($last_visit);
2082 $qworkedthrough = 0;
2083 foreach ($test_result as $key => $value) {
2084 if (preg_match(
"/\d+/", $key)) {
2085 $qworkedthrough += $value[
"workedthrough"];
2088 if (!$qworkedthrough) {
2091 $atimeofwork = $max_time / $qworkedthrough;
2097 if ($mark_obj !==
null) {
2098 $result_mark = $mark_obj->getShortName();
2100 if ($mark_obj->getPassed()) {
2106 $percent_worked_through = 0;
2107 if (count($this->questions)) {
2108 $percent_worked_through = $qworkedthrough / count($this->questions);
2111 "qworkedthrough" => $qworkedthrough,
2112 "qmax" => count($this->questions),
2113 "pworkedthrough" => $percent_worked_through,
2114 "timeofwork" => $max_time,
2115 "atimeofwork" => $atimeofwork,
2116 "firstvisit" => $first_date,
2117 "lastvisit" => $last_date,
2118 "resultspoints" => $test_result[
"test"][
"total_reached_points"],
2119 "maxpoints" => $test_result[
"test"][
"total_max_points"],
2120 "resultsmarks" => $result_mark,
2121 "passed" => $passed,
2122 "distancemedian" =>
"0"
2124 foreach ($test_result as $key => $value) {
2125 if (preg_match(
"/\d+/", $key)) {
2126 $result_array[$key] = $value;
2129 return $result_array;
2141 $totalpoints_array = [];
2142 $all_users = $this->evalTotalParticipantsArray();
2143 foreach ($all_users as $active_id => $user_name) {
2144 $test_result = &$this->getTestResult($active_id);
2145 $reached = $test_result[
"test"][
"total_reached_points"];
2146 $total = $test_result[
"test"][
"total_max_points"];
2147 $percentage = $total != 0 ? $reached / $total : 0;
2148 $mark = $this->getMarkSchema()->getMatchingMark($percentage * 100.0);
2150 if ($mark !==
null && $mark->getPassed()) {
2151 array_push($totalpoints_array, $test_result[
"test"][
"total_reached_points"]);
2154 return $totalpoints_array;
2164 $result = $this->db->queryF(
2165 "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",
2167 [$this->getTestId()]
2169 $persons_array = [];
2170 while ($row = $this->db->fetchAssoc($result)) {
2171 $name = $this->
lng->txt(
"anonymous");
2172 $fullname = $this->
lng->txt(
"anonymous");
2174 if (!$this->getAnonymity()) {
2175 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2176 $name = $this->
lng->txt(
"deleted_user");
2177 $fullname = $this->
lng->txt(
"deleted_user");
2178 $login = $this->
lng->txt(
"unknown");
2180 $login = $row[
"login"];
2182 $name = $this->
lng->txt(
"anonymous");
2183 $fullname = $this->
lng->txt(
"anonymous");
2185 $name = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2186 $fullname = trim($row[
"title"] .
" " . $row[
"firstname"] .
" " . $row[
"lastname"]);
2190 $persons_array[$row[
"active_id"]] = [
2192 "fullname" => $fullname,
2196 return $persons_array;
2201 $result = $this->db->queryF(
2202 "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),
2204 [$this->getTestId()]
2206 $persons_array = [];
2207 while ($row = $this->db->fetchAssoc($result)) {
2208 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row[
"active_id"])) {
2212 if ($this->getAnonymity()) {
2213 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"anonymous");
2215 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2216 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"deleted_user");
2219 $persons_array[$row[
"active_id"]] = $row[
"lastname"];
2221 $persons_array[$row[
"active_id"]] = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2226 return $persons_array;
2231 $result = $this->db->queryF(
2232 'SELECT tst_active.user_fi, tst_active.active_id, usr_data.login, '
2233 .
'usr_data.firstname, usr_data.lastname, usr_data.title FROM tst_active '
2234 .
'LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id '
2235 .
'WHERE tst_active.test_fi = %s '
2236 .
'ORDER BY usr_data.lastname ' . strtoupper($name_sort_order),
2238 [$this->getTestId()]
2240 $persons_array = [];
2241 while ($row = $this->db->fetchAssoc($result)) {
2242 if ($this->getAnonymity()) {
2243 $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
"anonymous")];
2245 if (strlen($row[
'firstname'] . $row[
'lastname'] . $row[
"title"]) == 0) {
2246 $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
'deleted_user')];
2249 $persons_array[$row[
'active_id']] = [
'name' => $row[
'lastname']];
2251 $persons_array[$row[
'active_id']] = [
2252 'name' => trim($row[
'lastname'] .
', ' . $row[
'firstname']
2253 .
' ' . $row[
'title']),
2254 'login' => $row[
'login']
2260 return $persons_array;
2265 if ($this->isRandomTest()) {
2266 $this->db->setLimit($this->getQuestionCount(), 0);
2267 $result = $this->db->queryF(
2268 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, '
2269 .
'tst_test_rnd_qst.pass, qpl_questions.points '
2270 .
'FROM tst_test_rnd_qst, qpl_questions '
2271 .
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id '
2272 .
'AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence',
2277 $result = $this->db->queryF(
2278 'SELECT tst_test_question.sequence, tst_test_question.question_fi, '
2279 .
'qpl_questions.points '
2280 .
'FROM tst_test_question, tst_active, qpl_questions '
2281 .
'WHERE tst_test_question.question_fi = qpl_questions.question_id '
2282 .
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
2288 if ($result->numRows()) {
2289 while ($row = $this->db->fetchAssoc($result)) {
2290 array_push($qtest, $row);
2298 if ($this->isRandomTest()) {
2299 $this->db->setLimit($this->getQuestionCount(), 0);
2300 $result = $this->db->queryF(
2301 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, '
2302 .
'qpl_questions.points '
2303 .
'FROM tst_test_rnd_qst, qpl_questions '
2304 .
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id '
2305 .
'AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s '
2306 .
'ORDER BY tst_test_rnd_qst.sequence',
2307 [
'integer',
'integer'],
2311 $result = $this->db->queryF(
2312 'SELECT tst_test_question.sequence, tst_test_question.question_fi, '
2313 .
'qpl_questions.points '
2314 .
'FROM tst_test_question, tst_active, qpl_questions '
2315 .
'WHERE tst_test_question.question_fi = qpl_questions.question_id '
2316 .
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
2322 if ($result->numRows()) {
2323 while ($row = $this->db->fetchAssoc($result)) {
2324 array_push($qpass, $row);
2332 return $this->access_filtered_participant_list;
2337 $this->access_filtered_participant_list = $access_filtered_participant_list;
2343 $list->initializeFromDbRows($this->getTestParticipants());
2345 return $list->getAccessFilteredList(
2346 $this->participant_access_filter->getAccessStatisticsUserFilter($this->getRefId())
2356 $list->initializeFromDbRows($this->getTestParticipants());
2357 if ($this->getAnonymity()) {
2358 return $list->getAllUserIds();
2360 return $list->getAccessFilteredList(
2361 $this->participant_access_filter->getAnonOnlyParticipantsUserFilter($this->getRefId())
2368 ->getEvaluationData();
2373 $question_set_type = $this->lookupQuestionSetTypeByActiveId($active_id);
2375 switch ($question_set_type) {
2377 $res = $this->db->queryF(
2379 SELECT tst_test_rnd_qst.pass,
2380 COUNT(tst_test_rnd_qst.question_fi) qcount,
2381 SUM(qpl_questions.points) qsum
2383 FROM tst_test_rnd_qst,
2386 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id
2387 AND tst_test_rnd_qst.active_fi = %s
2390 GROUP BY tst_test_rnd_qst.active_fi,
2391 tst_test_rnd_qst.pass
2393 [
'integer',
'integer'],
2399 $res = $this->db->queryF(
2401 SELECT COUNT(tst_test_question.question_fi) qcount,
2402 SUM(qpl_questions.points) qsum
2404 FROM tst_test_question,
2408 WHERE tst_test_question.question_fi = qpl_questions.question_id
2409 AND tst_test_question.test_fi = tst_active.test_fi
2410 AND tst_active.active_id = %s
2412 GROUP BY tst_test_question.test_fi
2420 throw new ilTestException(
"not supported question set type: $question_set_type");
2423 $row = $this->db->fetchAssoc(
$res);
2425 if (is_array($row)) {
2426 return [
"count" => $row[
"qcount"],
"points" => $row[
"qsum"]];
2429 return [
"count" => 0,
"points" => 0];
2434 $data = $this->getUnfilteredEvaluationData();
2435 $data->setFilter($filterby, $filtertext);
2456 || $firstname . $lastname ===
'') {
2457 return $this->
lng->txt(
'deleted_user');
2460 if ($this->getAnonymity()) {
2461 return $this->
lng->txt(
'anonymous');
2468 return trim($lastname .
', ' . $firstname);
2473 $query =
"SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi";
2475 if ($active_ids_to_filter !==
null && $active_ids_to_filter !== []) {
2476 $query .=
" AND " . $this->db->in(
'active_id', $active_ids_to_filter,
false,
'integer');
2479 $result = $this->db->queryF($query, [
'integer'], [$this->getTestId()]);
2481 while ($row = $this->db->fetchObject($result)) {
2482 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2491 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2500 if (isset($times[$row->active_fi])) {
2501 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2503 $times[$row->active_fi] = ($epoch_2 - $epoch_1);
2508 foreach ($times as $value) {
2509 $max_time += $value;
2515 return (
int) round($max_time /
$counter);
2525 bool $use_object_id =
false,
2526 ?
bool $equal_points =
false,
2527 bool $could_be_offline =
false,
2528 bool $show_path =
false,
2529 bool $with_questioncount =
false,
2530 string $permission =
'read'
2534 $equal_points ?? false,
2537 $with_questioncount,
2579 if ((!$question_type) and ($question_id > 0)) {
2580 $question_type = $this->getQuestionType($question_id);
2583 if (!strlen($question_type)) {
2587 if ($question_id > 0) {
2588 $question_gui = assQuestion::instantiateQuestionGUI($question_id);
2590 $question_type_gui = $question_type .
'GUI';
2591 $question_gui =
new $question_type_gui();
2594 return $question_gui;
2605 if (strcmp((
string) $question_id,
"") !== 0) {
2616 public function moveQuestions(array $move_questions,
int $target_index,
int $insert_mode): void
2618 $this->questions = array_values($this->questions);
2619 $array_pos = array_search($target_index, $this->questions);
2620 if ($insert_mode == 0) {
2621 $part1 = array_slice($this->questions, 0, $array_pos);
2622 $part2 = array_slice($this->questions, $array_pos);
2623 } elseif ($insert_mode == 1) {
2624 $part1 = array_slice($this->questions, 0, $array_pos + 1);
2625 $part2 = array_slice($this->questions, $array_pos + 1);
2627 foreach ($move_questions as $question_id) {
2628 if (!(array_search($question_id, $part1) ===
false)) {
2629 unset($part1[array_search($question_id, $part1)]);
2631 if (!(array_search($question_id, $part2) ===
false)) {
2632 unset($part2[array_search($question_id, $part2)]);
2635 $part1 = array_values($part1);
2636 $part2 = array_values($part2);
2637 $new_array = array_values(array_merge($part1, $move_questions, $part2));
2638 $this->questions = [];
2640 foreach ($new_array as $question_id) {
2641 $this->questions[
$counter] = $question_id;
2644 $this->saveQuestionsToDb();
2646 if ($this->
logger->isLoggingEnabled()) {
2647 $this->
logger->logTestAdministrationInteraction(
2648 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
2650 $this->user->getId(),
2651 TestAdministrationInteractionTypes::QUESTION_MOVED,
2653 AdditionalInformationGenerator::KEY_QUESTION_ORDER => $this->questions
2670 if ($this->isStartingTimeEnabled() && $this->getStartingTime() != 0) {
2672 if ($now < $this->getStartingTime()) {
2688 if ($this->isEndingTimeEnabled() && $this->getEndingTime() != 0) {
2690 if ($now > $this->getEndingTime()) {
2706 if (count($available_pools)) {
2707 $available =
" AND " . $this->db->in(
'qpl_questions.obj_fi', $available_pools,
false,
'integer');
2711 if ($completeonly) {
2712 $available .=
" AND qpl_questions.complete = " . $this->db->quote(
"1",
'text');
2716 if (is_array($arr_filter)) {
2717 if (array_key_exists(
'title', $arr_filter) && strlen($arr_filter[
'title'])) {
2718 $where .=
" AND " . $this->db->like(
'qpl_questions.title',
'text',
"%%" . $arr_filter[
'title'] .
"%%");
2720 if (array_key_exists(
'description', $arr_filter) && strlen($arr_filter[
'description'])) {
2721 $where .=
" AND " . $this->db->like(
'qpl_questions.description',
'text',
"%%" . $arr_filter[
'description'] .
"%%");
2723 if (array_key_exists(
'author', $arr_filter) && strlen($arr_filter[
'author'])) {
2724 $where .=
" AND " . $this->db->like(
'qpl_questions.author',
'text',
"%%" . $arr_filter[
'author'] .
"%%");
2726 if (array_key_exists(
'type', $arr_filter) && strlen($arr_filter[
'type'])) {
2727 $where .=
" AND qpl_qst_type.type_tag = " . $this->db->quote($arr_filter[
'type'],
'text');
2729 if (array_key_exists(
'qpl', $arr_filter) && strlen($arr_filter[
'qpl'])) {
2730 $where .=
" AND " . $this->db->like(
'object_data.title',
'text',
"%%" . $arr_filter[
'qpl'] .
"%%");
2734 $original_ids = &$this->getExistingQuestions();
2735 $original_clause =
" qpl_questions.original_id IS NULL";
2736 if (count($original_ids)) {
2737 $original_clause =
" qpl_questions.original_id IS NULL AND " . $this->db->in(
'qpl_questions.question_id', $original_ids,
true,
'integer');
2740 $query_result = $this->db->query(
"
2741 SELECT qpl_questions.*, qpl_questions.tstamp,
2742 qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name,
2743 object_data.title parent_title
2744 FROM qpl_questions, qpl_qst_type, object_data
2745 WHERE $original_clause $available
2746 AND object_data.obj_id = qpl_questions.obj_fi
2747 AND qpl_questions.tstamp > 0
2748 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id
2753 if ($query_result->numRows()) {
2754 while ($row = $this->db->fetchAssoc($query_result)) {
2757 if (!$row[
'plugin']) {
2758 $row[
'ttype' ] = $this->
lng->txt($row[
"type_tag" ]);
2764 $plugin = $this->component_repository->getPluginByName($row[
'plugin_name']);
2769 $pl = $this->component_factory->getPlugin(
$plugin->getId());
2770 $row[
'ttype' ] = $pl->getQuestionTypeTranslation();
2784 $this->saveToDb(
true);
2786 $main_settings = $this->getMainSettings();
2796 $introduction_settings = $introduction_settings->withIntroductionEnabled(
false);
2797 foreach ($assessment->objectives as
$objectives) {
2799 $introduction_settings = $this->addIntroductionToSettingsFromImport(
2800 $introduction_settings,
2801 $this->qtiMaterialToArray($material),
2810 $finishing_settings = $this->addConcludingRemarksToSettingsFromImport(
2811 $finishing_settings,
2812 $this->qtiMaterialToArray(
2819 $score_settings = $this->getScoreSettings();
2826 foreach ($assessment->qtimetadata as $metadata) {
2827 switch ($metadata[
"label"]) {
2828 case "solution_details":
2829 $result_details_settings = $result_details_settings->withShowPassDetails((
bool) $metadata[
"entry"]);
2831 case "show_solution_list_comparison":
2832 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
2834 case "print_bs_with_res":
2835 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
2838 $this->saveAuthorToMetadata($metadata[
"entry"]);
2841 $test_behaviour_settings = $test_behaviour_settings->withNumberOfTries((
int) $metadata[
"entry"]);
2843 case 'block_after_passed':
2844 $test_behaviour_settings = $test_behaviour_settings->withBlockAfterPassedEnabled((
bool) $metadata[
'entry']);
2846 case "pass_waiting":
2847 $test_behaviour_settings = $test_behaviour_settings->withPassWaiting($metadata[
"entry"]);
2850 $test_behaviour_settings = $test_behaviour_settings->withKioskMode((
int) $metadata[
"entry"]);
2852 case 'show_introduction':
2853 $introduction_settings = $introduction_settings->withIntroductionEnabled((
bool) $metadata[
'entry']);
2855 case "showfinalstatement":
2856 case 'show_concluding_remarks':
2857 $finishing_settings = $finishing_settings->withConcludingRemarksEnabled((
bool) $metadata[
"entry"]);
2859 case 'exam_conditions':
2860 $introduction_settings = $introduction_settings->withExamConditionsCheckboxEnabled($metadata[
'entry'] ===
'1');
2862 case "highscore_enabled":
2863 $gamification_settings = $gamification_settings->withHighscoreEnabled((
bool) $metadata[
"entry"]);
2865 case "highscore_anon":
2866 $gamification_settings = $gamification_settings->withHighscoreAnon((
bool) $metadata[
"entry"]);
2868 case "highscore_achieved_ts":
2869 $gamification_settings = $gamification_settings->withHighscoreAchievedTS((
bool) $metadata[
"entry"]);
2871 case "highscore_score":
2872 $gamification_settings = $gamification_settings->withHighscoreScore((
bool) $metadata[
"entry"]);
2874 case "highscore_percentage":
2875 $gamification_settings = $gamification_settings->withHighscorePercentage((
bool) $metadata[
"entry"]);
2877 case "highscore_wtime":
2878 $gamification_settings = $gamification_settings->withHighscoreWTime((
bool) $metadata[
"entry"]);
2880 case "highscore_own_table":
2881 $gamification_settings = $gamification_settings->withHighscoreOwnTable((
bool) $metadata[
"entry"]);
2883 case "highscore_top_table":
2884 $gamification_settings = $gamification_settings->withHighscoreTopTable((
bool) $metadata[
"entry"]);
2886 case "highscore_top_num":
2887 $gamification_settings = $gamification_settings->withHighscoreTopNum((
int) $metadata[
"entry"]);
2889 case "use_previous_answers":
2890 $participant_functionality_settings = $participant_functionality_settings->withUsePreviousAnswerAllowed((
bool) $metadata[
"entry"]);
2892 case 'question_list_enabled':
2893 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
'entry']);
2895 case "title_output":
2896 $question_behaviour_settings = $question_behaviour_settings->withQuestionTitleOutputMode((
int) $metadata[
"entry"]);
2898 case "question_set_type":
2899 if ($metadata[
'entry'] === self::QUESTION_SET_TYPE_RANDOM) {
2900 $this->questions = [];
2902 $general_settings = $general_settings->withQuestionSetType($metadata[
"entry"]);
2905 $general_settings = $general_settings->withAnonymity((
bool) $metadata[
"entry"]);
2907 case "results_presentation":
2908 $result_details_settings = $result_details_settings->withResultsPresentation((
int) $metadata[
"entry"]);
2910 case "reset_processing_time":
2911 $test_behaviour_settings = $test_behaviour_settings->withResetProcessingTime($metadata[
"entry"] ===
'1');
2913 case "answer_feedback_points":
2914 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackPointsEnabled((
bool) $metadata[
"entry"]);
2916 case "answer_feedback":
2917 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackGenericEnabled((
bool) $metadata[
"entry"]);
2919 case 'instant_feedback_specific':
2920 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSpecificEnabled((
bool) $metadata[
'entry']);
2922 case "instant_verification":
2923 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSolutionEnabled((
bool) $metadata[
"entry"]);
2925 case "force_instant_feedback":
2926 $question_behaviour_settings = $question_behaviour_settings->withForceInstantFeedbackOnNextQuestion((
bool) $metadata[
"entry"]);
2928 case "follow_qst_answer_fixation":
2929 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnNextQuestionEnabled((
bool) $metadata[
"entry"]);
2931 case "instant_feedback_answer_fixation":
2932 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnInstantFeedbackEnabled((
bool) $metadata[
"entry"]);
2935 case "suspend_test_allowed":
2936 $participant_functionality_settings = $participant_functionality_settings->withSuspendTestAllowed((
bool) $metadata[
"entry"]);
2938 case "sequence_settings":
2939 $participant_functionality_settings = $participant_functionality_settings->withPostponedQuestionsMoveToEnd((
bool) $metadata[
"entry"]);
2942 $participant_functionality_settings = $participant_functionality_settings->withQuestionMarkingEnabled((
bool) $metadata[
"entry"]);
2944 case "fixed_participants":
2945 $access_settings = $access_settings->withFixedParticipants((
bool) $metadata[
"entry"]);
2947 case "score_reporting":
2948 if ($metadata[
'entry'] !==
null) {
2949 $result_summary_settings = $result_summary_settings->withScoreReporting(
2950 ScoreReportingTypes::tryFrom((
int) $metadata[
'entry']) ?? ScoreReportingTypes::SCORE_REPORTING_DISABLED
2954 case "shuffle_questions":
2955 $question_behaviour_settings = $question_behaviour_settings->withShuffleQuestions((
bool) $metadata[
"entry"]);
2957 case "count_system":
2958 $scoring_settings = $scoring_settings->withCountSystem((
int) $metadata[
"entry"]);
2960 case "exportsettings":
2961 $result_details_settings = $result_details_settings->withExportSettings((
int) $metadata[
"entry"]);
2963 case "score_cutting":
2964 $scoring_settings = $scoring_settings->withScoreCutting((
int) $metadata[
"entry"]);
2967 $access_settings = $access_settings->withPasswordEnabled(
2968 $metadata[
"entry"] !==
null && $metadata[
"entry"] !==
''
2969 )->withPassword($metadata[
"entry"]);
2971 case 'ip_range_from':
2972 if ($metadata[
'entry'] !==
'') {
2973 $access_settings = $access_settings->withIpRangeFrom($metadata[
'entry']);
2977 if ($metadata[
'entry'] !==
'') {
2978 $access_settings = $access_settings->withIpRangeTo($metadata[
'entry']);
2981 case "pass_scoring":
2982 $scoring_settings = $scoring_settings->withPassScoring((
int) $metadata[
"entry"]);
2984 case 'pass_deletion_allowed':
2985 $result_summary_settings = $result_summary_settings->withPassDeletionAllowed((
bool) $metadata[
"entry"]);
2987 case "usr_pass_overview_mode":
2988 $participant_functionality_settings = $participant_functionality_settings->withUsrPassOverviewMode((
int) $metadata[
"entry"]);
2990 case "question_list":
2991 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
"entry"]);
2994 case "reporting_date":
2995 $reporting_date = $this->buildDateTimeImmutableFromPeriod($metadata[
'entry']);
2996 if ($reporting_date !==
null) {
2997 $result_summary_settings = $result_summary_settings->withReportingDate($reporting_date);
3000 case 'enable_processing_time':
3001 $test_behaviour_settings = $test_behaviour_settings->withProcessingTimeEnabled((
bool) $metadata[
'entry']);
3003 case "processing_time":
3004 $test_behaviour_settings = $test_behaviour_settings->withProcessingTime($metadata[
'entry']);
3006 case "starting_time":
3007 $starting_time = $this->buildDateTimeImmutableFromPeriod($metadata[
'entry']);
3008 if ($starting_time !==
null) {
3009 $access_settings = $access_settings->withStartTime($starting_time)
3010 ->withStartTimeEnabled(
true);
3014 $ending_time = $this->buildDateTimeImmutableFromPeriod($metadata[
'entry']);
3015 if ($ending_time !==
null) {
3016 $access_settings = $access_settings->withEndTime($ending_time)
3017 ->withStartTimeEnabled(
true);
3020 case "enable_examview":
3021 $finishing_settings = $finishing_settings->withShowAnswerOverview((
bool) $metadata[
"entry"]);
3023 case 'redirection_mode':
3024 $finishing_settings = $finishing_settings->withRedirectionMode(
3025 RedirectionModes::tryFrom((
int) ($metadata[
'entry'] ?? 0)) ?? RedirectionModes::NONE
3028 case 'redirection_url':
3029 $finishing_settings = $finishing_settings->withRedirectionUrl($metadata[
'entry']);
3031 case 'examid_in_test_pass':
3032 $test_behaviour_settings = $test_behaviour_settings->withExamIdInTestAttemptEnabled((
bool) $metadata[
'entry']);
3034 case 'examid_in_test_res':
3035 $result_details_settings = $result_details_settings->withShowExamIdInTestResults((
bool) $metadata[
"entry"]);
3037 case 'skill_service':
3038 $additional_settings = $additional_settings->withSkillsServiceEnabled((
bool) $metadata[
'entry']);
3040 case 'show_grading_status':
3041 $result_summary_settings = $result_summary_settings->withShowGradingStatusEnabled((
bool) $metadata[
"entry"]);
3043 case 'show_grading_mark':
3044 $result_summary_settings = $result_summary_settings->withShowGradingMarkEnabled((
bool) $metadata[
"entry"]);
3047 $question_behaviour_settings = $question_behaviour_settings->withAutosaveEnabled((
bool) $metadata[
'entry']);
3049 case 'autosave_ival':
3050 $question_behaviour_settings = $question_behaviour_settings->withAutosaveInterval((
int) $metadata[
'entry']);
3052 case 'show_summary':
3053 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled(($metadata[
'entry'] & 1) > 0)
3054 ->withUsrPassOverviewMode((
int) $metadata[
'entry']);
3057 case 'hide_info_tab':
3058 $additional_settings = $additional_settings->withHideInfoTab($metadata[
'entry'] ===
'1');
3060 if (preg_match(
"/mark_step_\d+/", $metadata[
"label"])) {
3061 $xmlmark = $metadata[
"entry"];
3062 preg_match(
"/<short>(.*?)<\/short>/", $xmlmark, $matches);
3063 $mark_short = $matches[1];
3064 preg_match(
"/<official>(.*?)<\/official>/", $xmlmark, $matches);
3065 $mark_official = $matches[1];
3066 preg_match(
"/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
3067 $mark_percentage = (float) $matches[1];
3068 preg_match(
"/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
3069 $mark_passed = (bool) $matches[1];
3070 $mark_steps[] =
new Mark($mark_short, $mark_official, $mark_percentage, $mark_passed);
3073 $this->mark_schema = $this->getMarkSchema()->withMarkSteps($mark_steps);
3075 $this->getObjectProperties()->storePropertyTitleAndDescription(
3076 $this->getObjectProperties()->getPropertyTitleAndDescription()
3080 $this->addToNewsOnOnline(
false, $this->getObjectProperties()->getPropertyIsOnline()->getIsOnline());
3081 $main_settings = $main_settings
3083 ->withIntroductionSettings($introduction_settings)
3084 ->withAccessSettings($access_settings)
3085 ->withParticipantFunctionalitySettings($participant_functionality_settings)
3086 ->withTestBehaviourSettings($test_behaviour_settings)
3087 ->withQuestionBehaviourSettings($question_behaviour_settings)
3088 ->withFinishingSettings($finishing_settings)
3089 ->withAdditionalSettings($additional_settings);
3090 $this->getMainSettingsRepository()->store($main_settings);
3091 $this->main_settings = $main_settings;
3093 $score_settings = $score_settings
3095 ->withScoringSettings($scoring_settings)
3096 ->withResultDetailsSettings($result_details_settings)
3097 ->withResultSummarySettings($result_summary_settings);
3098 $this->getScoreSettingsRepository()->store($score_settings);
3099 $this->score_settings = $score_settings;
3100 $this->loadFromDb();
3108 if (!str_starts_with($material[
'text'],
'<PageObject>')) {
3112 $text = $this->replaceFilesInPageImports(
3113 $this->replaceMobsInPageImports(
3115 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
3117 $mappings[
'components/ILIAS/File'][
'file'] ?? []
3121 $page_object->setParentId($this->
getId());
3122 $page_object->setXMLContent(
$text);
3123 $new_page_id = $page_object->createPageWithNextId();
3124 return $settings->withIntroductionPageId($new_page_id);
3132 if (!str_starts_with($material[
'text'],
'<PageObject>')) {
3136 $text = $this->replaceFilesInPageImports(
3137 $this->replaceMobsInPageImports(
3139 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
3141 $mappings[
'components/ILIAS/File'][
'file'] ?? []
3145 $page_object->setParentId($this->
getId());
3146 $page_object->setXMLContent(
$text);
3147 $new_page_id = $page_object->createPageWithNextId();
3148 return $settings->withConcludingRemarksPageId($new_page_id);
3153 preg_match_all(
'/il_(\d+)_mob_(\d+)/',
$text, $matches);
3154 foreach ($matches[0] as $index => $match) {
3155 if (empty($mappings[$matches[2][$index]])) {
3158 $text = str_replace($match,
"il__mob_{$mappings[$matches[2][$index]]}",
$text);
3166 preg_match_all(
'/il_(\d+)_file_(\d+)/',
$text, $matches);
3167 foreach ($matches[0] as $index => $match) {
3168 if (empty($mappings[$matches[2][$index]])) {
3171 $text = str_replace($match,
"il__file_{$mappings[$matches[2][$index]]}",
$text);
3183 $main_settings = $this->getMainSettings();
3186 $a_xml_writer->xmlHeader();
3187 $a_xml_writer->xmlSetDtdDef(
"<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
3188 $a_xml_writer->xmlStartTag(
"questestinterop");
3191 "ident" =>
"il_" .
IL_INST_ID .
"_tst_" . $this->getTestId(),
3194 $a_xml_writer->xmlStartTag(
"assessment", $attrs);
3195 $a_xml_writer->xmlElement(
"qticomment",
null, $this->getDescription());
3198 $a_xml_writer->xmlElement(
3201 $this->getProcessingTimeForXML()
3205 $a_xml_writer->xmlStartTag(
"qtimetadata");
3206 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3207 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ILIAS_VERSION");
3208 $a_xml_writer->xmlElement(
"fieldentry",
null,
ILIAS_VERSION);
3209 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3211 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3212 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"anonymity");
3213 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getGeneralSettings()->getAnonymity() ? 1 : 0);
3214 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3216 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3217 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"question_set_type");
3218 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getGeneralSettings()->getQuestionSetType());
3219 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3221 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3222 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"sequence_settings");
3224 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3226 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3227 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"author");
3228 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getAuthor());
3229 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3231 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3232 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"reset_processing_time");
3233 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getTestBehaviourSettings()->getResetProcessingTime() ? 1 : 0);
3234 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3236 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3237 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"count_system");
3238 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getCountSystem());
3239 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3241 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3242 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"score_cutting");
3243 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getScoreCutting());
3244 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3246 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3247 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"password");
3248 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getPassword() ??
'');
3249 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3251 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3252 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ip_range_from");
3253 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getIpRangeFrom());
3254 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3256 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3257 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ip_range_to");
3258 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getIpRangeTo());
3259 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3261 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3262 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"pass_scoring");
3263 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getPassScoring());
3264 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3266 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3267 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'pass_deletion_allowed');
3268 $a_xml_writer->xmlElement(
'fieldentry',
null, $this->isPassDeletionAllowed() ? 1 : 0);
3269 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3271 if ($this->getScoreSettings()->getResultSummarySettings()->getReportingDate() !==
null) {
3272 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3273 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"reporting_date");
3274 $a_xml_writer->xmlElement(
3277 $this->buildIso8601PeriodForExportCompatibility(
3278 $this->getScoreSettings()->getResultSummarySettings()->getReportingDate(),
3281 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3284 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3285 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"nr_of_tries");
3287 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3289 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3290 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'block_after_passed');
3291 $a_xml_writer->xmlElement(
'fieldentry',
null, $main_settings->
getTestBehaviourSettings()->getBlockAfterPassedEnabled() ? 1 : 0);
3292 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3294 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3295 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"pass_waiting");
3297 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3299 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3300 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"kiosk");
3302 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3304 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3305 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"redirection_mode");
3306 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getFinishingSettings()->getRedirectionMode()->value);
3307 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3309 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3310 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"redirection_url");
3311 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getFinishingSettings()->getRedirectionUrl());
3312 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3314 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3315 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"use_previous_answers");
3317 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3319 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3320 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'question_list_enabled');
3322 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3324 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3325 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"title_output");
3327 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3329 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3330 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"results_presentation");
3331 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getScoreSettings()->getResultDetailsSettings()->getResultsPresentation());
3332 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3334 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3335 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"examid_in_test_pass");
3336 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getTestBehaviourSettings()->getExamIdInTestAttemptEnabled() ? 1 : 0);
3337 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3339 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3340 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"examid_in_test_res");
3341 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults() ? 1 : 0);
3342 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3344 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3345 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"usr_pass_overview_mode");
3347 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3349 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3350 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"score_reporting");
3351 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getScoreSettings()->getResultSummarySettings()->getScoreReporting()->value);
3352 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3354 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3355 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_solution_list_comparison");
3356 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->score_settings->getResultDetailsSettings()->getShowSolutionListComparison() ? 1 : 0);
3357 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3359 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3360 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_verification");
3361 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled() ? 1 : 0);
3362 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3364 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3365 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"answer_feedback");
3366 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled() ? 1 : 0);
3367 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3369 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3370 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_specific");
3371 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled() ? 1 : 0);
3372 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3374 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3375 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"answer_feedback_points");
3376 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled() ? 1 : 0);
3377 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3379 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3380 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"follow_qst_answer_fixation");
3381 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled() ? 1 : 0);
3382 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3384 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3385 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_answer_fixation");
3386 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled() ? 1 : 0);
3387 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3389 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3390 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"force_instant_feedback");
3391 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion() ? 1 : 0);
3392 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3394 $highscore_metadata = [
3395 'highscore_enabled' => $this->getHighscoreEnabled(),
3396 'highscore_anon' => $this->getHighscoreAnon(),
3397 'highscore_achieved_ts' => $this->getHighscoreAchievedTS(),
3398 'highscore_score' => $this->getHighscoreScore(),
3399 'highscore_percentage' => $this->getHighscorePercentage(),
3400 'highscore_wtime' => $this->getHighscoreWTime(),
3401 'highscore_own_table' => $this->getHighscoreOwnTable(),
3402 'highscore_top_table' => $this->getHighscoreTopTable(),
3404 foreach ($highscore_metadata as $label => $value) {
3405 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3406 $a_xml_writer->xmlElement(
"fieldlabel",
null, $label);
3407 $a_xml_writer->xmlElement(
"fieldentry",
null, $value ? 1 : 0);
3408 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3410 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3411 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"highscore_top_num");
3412 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getHighscoreTopNum());
3413 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3415 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3416 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"suspend_test_allowed");
3418 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3420 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3421 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_marker");
3423 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3425 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3426 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"fixed_participants");
3427 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getFixedParticipants() ? 1 : 0);
3428 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3430 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3431 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_introduction");
3432 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getIntroductionSettings()->getIntroductionEnabled() ? 1 : 0);
3433 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3435 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3436 $a_xml_writer->xmlElement(
"fieldlabel",
null,
'exam_conditions');
3437 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getIntroductionSettings()->getExamConditionsCheckboxEnabled() ? 1 : 0);
3438 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3440 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3441 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_concluding_remarks");
3442 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getFinishingSettings()->getConcludingRemarksEnabled() ? 1 : 0);
3443 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3445 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3446 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"exportsettings");
3447 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->getExportSettings());
3448 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3450 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3451 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"shuffle_questions");
3453 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3455 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3456 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"processing_time");
3458 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3460 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3461 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"enable_examview");
3462 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getFinishingSettings()->getShowAnswerOverview() ? 1 : 0);
3463 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3465 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3466 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"skill_service");
3467 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAdditionalSettings()->getSkillsServiceEnabled() ? 1 : 0);
3468 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3470 if ($this->getInstantFeedbackSolution() == 1) {
3472 "solutionswitch" =>
"Yes"
3477 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs,
null);
3479 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3480 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_grading_status");
3481 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->isShowGradingStatusEnabled() ? 1 : 0);
3482 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3484 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3485 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_grading_mark");
3486 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->isShowGradingMarkEnabled() ? 1 : 0);
3487 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3489 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3490 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'hide_info_tab');
3491 $a_xml_writer->xmlElement(
'fieldentry',
null, $this->getMainSettings()->getAdditionalSettings()->getHideInfoTab() ? 1 : 0);
3492 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3494 if ($this->getStartingTime() > 0) {
3495 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3496 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"starting_time");
3497 $a_xml_writer->xmlElement(
3500 $this->buildIso8601PeriodForExportCompatibility(
3501 (
new DateTimeImmutable())->setTimestamp($this->getStartingTime()),
3504 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3507 if ($this->getEndingTime() > 0) {
3508 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3509 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ending_time");
3510 $a_xml_writer->xmlElement(
3513 $this->buildIso8601PeriodForExportCompatibility(
3514 (
new DateTimeImmutable())->setTimestamp($this->getEndingTime()),
3517 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3520 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3521 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"autosave");
3523 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3525 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3526 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"autosave_ival");
3528 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3530 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3531 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_specific");
3532 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled() ? 1 : 0);
3533 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3535 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3536 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_answer_fixation");
3537 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled() ? 1 : 0);
3538 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3540 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3541 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"enable_processing_time");
3542 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getTestBehaviourSettings()->getProcessingTimeEnabled() ? 1 : 0);
3543 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3545 foreach ($this->getMarkSchema()->getMarkSteps() as $index => $mark) {
3546 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3547 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mark_step_$index");
3548 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
3549 "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
3550 $mark->getShortName(),
3551 $mark->getOfficialName(),
3552 $mark->getMinimumLevel(),
3555 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3557 $a_xml_writer->xmlEndTag(
"qtimetadata");
3560 $introduction = $page_id !==
null
3561 ? (
new ilTestPage($page_id))->getXMLContent()
3564 $a_xml_writer->xmlStartTag(
"objectives");
3565 $this->addQTIMaterial($a_xml_writer, $page_id, $introduction);
3566 $a_xml_writer->xmlEndTag(
"objectives");
3568 if ($this->getInstantFeedbackSolution() == 1) {
3570 "solutionswitch" =>
"Yes"
3575 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs,
null);
3577 if (strlen($this->getFinalStatement())) {
3579 $concluding_remarks = $page_id !==
null
3580 ? (
new ilTestPage($page_id))->getXMLContent()
3583 $a_xml_writer->xmlStartTag(
"presentation_material");
3584 $a_xml_writer->xmlStartTag(
"flow_mat");
3585 $this->addQTIMaterial($a_xml_writer, $page_id, $concluding_remarks);
3586 $a_xml_writer->xmlEndTag(
"flow_mat");
3587 $a_xml_writer->xmlEndTag(
"presentation_material");
3593 $a_xml_writer->xmlElement(
"section", $attrs,
null);
3594 $a_xml_writer->xmlEndTag(
"assessment");
3595 $a_xml_writer->xmlEndTag(
"questestinterop");
3597 $xml = $a_xml_writer->xmlDumpMem(
false);
3603 return $date_time->setTimezone(
new DateTimeZone(
'UTC'))->format(
'\PY\Yn\Mj\D\TG\Hi\Ms\S');
3608 if ($period ===
null) {
3611 if (preg_match(
"/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $period, $matches)) {
3612 return new DateTimeImmutable(
3614 "%02d-%02d-%02d %02d:%02d:%02d",
3622 new \DateTimeZone(
'UTC')
3634 public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog): void
3636 $this->mob_ids = [];
3639 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Page Objects");
3640 $this->bench->start(
"ContentObjectExport",
"exportPageObjects");
3641 $this->exportXMLPageObjects($a_xml_writer, $a_inst, $expLog);
3642 $this->bench->stop(
"ContentObjectExport",
"exportPageObjects");
3643 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Page Objects");
3646 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Media Objects");
3647 $this->bench->start(
"ContentObjectExport",
"exportMediaObjects");
3648 $this->exportXMLMediaObjects($a_xml_writer, $a_inst, $a_target_dir, $expLog);
3649 $this->bench->stop(
"ContentObjectExport",
"exportMediaObjects");
3650 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Media Objects");
3653 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export File Items");
3654 $this->bench->start(
"ContentObjectExport",
"exportFileItems");
3655 $this->exportFileItems($a_target_dir, $expLog);
3656 $this->bench->stop(
"ContentObjectExport",
"exportFileItems");
3657 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export File Items");
3667 if ($a_tag ==
"Identifier" && $a_param ==
"Entry") {
3683 foreach ($this->questions as $question_id) {
3684 $this->bench->start(
"ContentObjectExport",
"exportPageObject");
3685 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Page Object " . $question_id);
3688 $a_xml_writer->xmlStartTag(
"PageObject", $attrs);
3692 $this->bench->start(
"ContentObjectExport",
"exportPageObject_XML");
3694 $page_object->buildDom();
3695 $page_object->insertInstIntoIDs((
string) $inst);
3696 $mob_ids = $page_object->collectMediaObjects(
false);
3698 $xml = $page_object->getXMLFromDom(
false,
false,
false,
"",
true);
3699 $xml = str_replace(
"&",
"&", $xml);
3700 $a_xml_writer->appendXML($xml);
3701 $page_object->freeDom();
3702 unset($page_object);
3704 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_XML");
3707 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectMedia");
3709 foreach ($mob_ids as $mob_id) {
3710 $this->mob_ids[$mob_id] = $mob_id;
3712 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectMedia");
3715 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
3717 foreach ($file_ids as $file_id) {
3718 $this->file_ids[$file_id] = $file_id;
3720 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
3722 $a_xml_writer->xmlEndTag(
"PageObject");
3725 $this->bench->stop(
"ContentObjectExport",
"exportPageObject");
3732 public function exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
3734 foreach ($this->mob_ids as $mob_id) {
3735 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Media Object " . $mob_id);
3740 $target_dir = $a_target_dir . DIRECTORY_SEPARATOR .
'objects'
3741 . DIRECTORY_SEPARATOR .
'il_' .
IL_INST_ID .
'_mob_' . $mob_id;
3744 $media_obj->exportXML($a_xml_writer, (
int) $a_inst);
3746 foreach ($media_obj->getMediaItems() as $item) {
3747 $rid = $this->media_object_repository->getById($item->getMobId())[
'rid'] ??
null;
3748 if ($rid ===
null || $this->irss->manage()->find($rid) ===
null) {
3749 $expLog->write(date(
'[y-m-d H:i:s] ') .
"The resource for Media Object {$item->getMobId()} does not exist (skipping)");
3752 $stream = $item->getLocationStream();
3753 file_put_contents($target_dir . DIRECTORY_SEPARATOR . $item->getLocation(), $stream);
3766 foreach ($this->file_ids as $file_id) {
3767 $expLog->write(date(
"[y-m-d H:i:s] ") .
"File Item " . $file_id);
3768 $file_dir = $target_dir .
'/objects/il_' .
IL_INST_ID .
'_file_' . $file_id;
3770 $file_obj =
new ilObjFile((
int) $file_id,
false);
3771 $source_file = $file_obj->getFile($file_obj->getVersion());
3772 if (!is_file($source_file)) {
3773 $source_file = $file_obj->getFile();
3775 if (is_file($source_file)) {
3776 copy($source_file, $file_dir .
'/' . $file_obj->getFileName());
3795 $this->saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
3797 if ($this->participantDataExist()) {
3798 $this->recalculateScores(
true);
3807 $total = $this->evalTotalPersons();
3808 $results_summary_settings = $this->getScoreSettings()->getResultSummarySettings();
3810 || $results_summary_settings->getScoreReporting()->isReportingEnabled() ===
false) {
3814 if ($results_summary_settings->getScoreReporting() === ScoreReportingTypes::SCORE_REPORTING_DATE) {
3815 return $results_summary_settings->getReportingDate()
3816 >=
new DateTimeImmutable(
'now',
new DateTimeZone(
'UTC'));
3833 $path_to_lifecycle = $this->lo_metadata->paths()->custom()->withNextStep(
'lifeCycle')->get();
3834 $path_to_authors = $this->lo_metadata->paths()->authors();
3836 $reader = $this->lo_metadata->read($this->
getId(), 0, $this->getType(), $path_to_lifecycle);
3837 if (!is_null($reader->allData($path_to_lifecycle)->current())) {
3841 if ($author ===
'') {
3842 $author = $this->
user->getFullname();
3844 $this->lo_metadata->manipulate($this->
getId(), 0, $this->getType())
3845 ->prepareCreateOrUpdate($path_to_authors, $author)
3854 $this->saveAuthorToMetadata();
3866 $path_to_authors = $this->lo_metadata->paths()->authors();
3867 $author_data = $this->lo_metadata->read($this->
getId(), 0, $this->getType(), $path_to_authors)
3868 ->allData($path_to_authors);
3870 return $this->lo_metadata->dataHelper()->makePresentableAsList(
', ', ...$author_data);
3884 $lo_metadata =
$DIC->learningObjectMetadata();
3886 $path_to_authors = $lo_metadata->paths()->authors();
3887 $author_data = $lo_metadata->read($obj_id, 0,
"tst", $path_to_authors)
3888 ->allData($path_to_authors);
3890 return $lo_metadata->dataHelper()->makePresentableAsList(
',', ...$author_data);
3902 $ilUser =
$DIC[
'ilUser'];
3905 $tests = array_slice(
3913 if (count($tests)) {
3916 if ($use_object_id) {
3918 $result_array[$obj_id] = $titles[
$ref_id];
3924 return $result_array;
3937 $this->loadFromDb();
3939 $new_obj = parent::cloneObject($target_id, $copy_id, $omit_tree);
3940 $new_obj->setTmpCopyWizardCopyId($copy_id);
3941 $this->cloneMetaData($new_obj);
3943 $new_obj->saveToDb();
3944 $new_obj->addToNewsOnOnline(
false, $new_obj->getObjectProperties()->getPropertyIsOnline()->getIsOnline());
3946 $new_main_settings = $this->getMainSettings()
3947 ->withIntroductionSettings(
3948 $this->getMainSettings()->getIntroductionSettings()->withIntroductionPageId(
3949 $this->cloneIntroduction()
3951 )->withFinishingSettings(
3952 $this->getMainSettings()->getFinishingSettings()->withConcludingRemarksPageId(
3953 $this->cloneConcludingRemarks()
3957 $new_main_settings = $this->getMainSettingsRepository()->store($new_main_settings, $new_obj->getTestId());
3958 $this->getScoreSettingsRepository()->store(
3959 $this->getScoreSettings()->withId($new_main_settings->getId())
3961 $this->marks_repository->storeMarkSchema(
3962 $this->getMarkSchema()->withTestId($new_obj->getTestId())
3965 $new_obj->setTemplate($this->getTemplate());
3974 $templateRepository,
3978 $cloneAction->cloneCertificate($this, $new_obj);
3980 $this->question_set_config_factory->getQuestionSetConfig()->cloneQuestionSetRelatedData($new_obj);
3981 $new_obj->saveQuestionsToDb();
3984 $skillLevelThresholdList->setTestId($this->getTestId());
3985 $skillLevelThresholdList->loadFromDb();
3986 $skillLevelThresholdList->cloneListForTest($new_obj->getTestId());
3989 $obj_settings->cloneSettings($new_obj->getId());
3991 if ($new_obj->getTestLogger()->isLoggingEnabled()) {
3992 $new_obj->getTestLogger()->logTestAdministrationInteraction(
3993 $new_obj->getTestLogger()->getInteractionFactory()->buildTestAdministrationInteraction(
3994 $new_obj->getRefId(),
3995 $this->user->getId(),
3996 TestAdministrationInteractionTypes::NEW_TEST_CREATED,
4009 if ($this->isRandomTest()) {
4015 $this->component_repository,
4017 $this->questionrepository
4020 $questionSetConfig->loadFromDb();
4022 if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
4029 $sourcePoolDefinitionList->loadDefinitions();
4031 if (is_int($sourcePoolDefinitionList->getQuestionAmount())) {
4032 $num = $sourcePoolDefinitionList->getQuestionAmount();
4034 } elseif (is_int($questionSetConfig->getQuestionAmountPerTest())) {
4035 $num = $questionSetConfig->getQuestionAmountPerTest();
4038 $this->loadQuestions();
4039 $num = count($this->questions);
4047 if ($this->isRandomTest()) {
4048 return $this->getQuestionCount();
4050 return count($this->questions);
4065 $result =
$ilDB->queryF(
4066 "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
4070 if ($result->numRows()) {
4071 $row =
$ilDB->fetchAssoc($result);
4072 $object_id = $row[
"obj_fi"];
4089 $result =
$ilDB->queryF(
4090 "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",
4094 if ($result->numRows()) {
4095 $row =
$ilDB->fetchAssoc($result);
4096 $object_id = $row[
"obj_fi"];
4113 $result =
$ilDB->queryF(
4114 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
4118 if ($result->numRows()) {
4119 $row =
$ilDB->fetchAssoc($result);
4120 $test_id = $row[
"test_id"];
4135 if (($active_id) && ($question_id)) {
4136 if ($pass ===
null) {
4139 if ($pass ===
null) {
4142 $query = $this->db->queryF(
4143 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
4144 [
'integer',
'integer',
'integer'],
4145 [$active_id, $question_id, $pass]
4147 $result = $this->db->fetchAll($query);
4148 if (count($result) == 1) {
4149 return $result[0][
"value1"];
4166 $result = $this->db->queryF(
4167 "SELECT question_text FROM qpl_questions WHERE question_id = %s",
4171 if ($result->numRows() == 1) {
4172 $row = $this->db->fetchAssoc($result);
4173 $res = $row[
"question_text"];
4182 $participant_list->initializeFromDbRows($this->getTestParticipants());
4184 return $participant_list;
4197 if ($this->getAnonymity()) {
4199 $result = $this->db->queryF(
4200 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
4201 "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 " .
4202 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4203 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4205 [
'text',
'text',
'text',
'integer',
'integer'],
4206 [
'', $this->
lng->txt(
'anonymous'),
'', $this->getTestId(),
$user_id]
4209 $result = $this->db->queryF(
4210 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
4211 "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 " .
4212 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4213 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4215 [
'text',
'text',
'text',
'integer'],
4216 [
'', $this->
lng->txt(
'anonymous'),
'', $this->getTestId()]
4221 $result = $this->db->queryF(
4222 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
4223 "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 " .
4224 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4225 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4227 [
'integer',
'integer'],
4231 $result = $this->db->queryF(
4232 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
4233 "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 " .
4234 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4235 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4238 [$this->getTestId()]
4243 while ($row = $this->db->fetchAssoc($result)) {
4244 $result_array[$row[
'usr_id']] = $row;
4246 return $result_array;
4253 SELECT tst_active.active_id,
4255 tst_active.user_fi usr_id,
4259 tst_active.submitted test_finished,
4260 usr_data.matriculation,
4262 tst_active.lastindex,
4263 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
4266 ON tst_active.user_fi = usr_data.usr_id
4267 WHERE tst_active.test_fi = %s
4268 ORDER BY usr_data.lastname
4270 $result = $this->db->queryF(
4272 [
'text',
'text',
'text',
'integer'],
4273 [
'', $this->
lng->txt(
"anonymous"),
"", $this->getTestId()]
4277 SELECT tst_active.active_id,
4279 tst_active.user_fi usr_id,
4283 tst_active.submitted test_finished,
4284 usr_data.matriculation,
4286 tst_active.lastindex,
4287 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes
4290 ON tst_active.user_fi = usr_data.usr_id
4291 WHERE tst_active.test_fi = %s
4292 ORDER BY usr_data.lastname
4294 $result = $this->db->queryF(
4297 [$this->getTestId()]
4301 while ($row = $this->db->fetchAssoc($result)) {
4302 $data[$row[
'active_id']] = $row;
4304 foreach (
$data as $index => $participant) {
4305 if (strlen(trim($participant[
"firstname"] . $participant[
"lastname"])) == 0) {
4306 $data[$index][
"lastname"] = $this->
lng->txt(
"deleted_user");
4314 if (!$this->getGlobalSettings()->isManualScoringEnabled()) {
4318 $filtered_participants = [];
4319 foreach ($this->getTestParticipants() as $active_id => $participant) {
4320 if ($participant[
'tries'] > 0) {
4323 if ($this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
4324 $filtered_participants[$active_id] = $participant;
4328 if (!$this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
4329 $filtered_participants[$active_id] = $participant;
4333 $filtered_participants[$active_id] = $participant;
4337 return $filtered_participants;
4348 if (!is_array($ids) || count($ids) == 0) {
4352 if ($this->getAnonymity()) {
4353 $result = $this->db->queryF(
4354 "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",
4355 [
'text',
'text',
'text'],
4356 [
"", $this->lng->txt(
"anonymous"),
""]
4359 $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");
4363 while ($row = $this->db->fetchAssoc($result)) {
4364 $result_array[$row[
"usr_id"]] = $row;
4366 return $result_array;
4371 if (!is_array($ids) || count($ids) == 0) {
4384 if (!is_array($ids) || count($ids) == 0) {
4388 foreach ($ids as $obj_id) {
4402 $this->db->manipulateF(
4403 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
4404 [
'integer',
'integer'],
4407 $this->db->manipulateF(
4408 "INSERT INTO tst_invited_user (test_fi, user_fi, ip_range_from, ip_range_to, tstamp) VALUES (%s, %s, %s, %s, %s)",
4409 [
'integer',
'integer',
'text',
'text',
'integer'],
4410 [$this->getTestId(),
$user_id, (strlen($client_ip)) ? $client_ip :
null, (strlen($client_ip)) ? $client_ip :
null,time()]
4423 if (is_numeric($question_fi)) {
4424 $result =
$ilDB->queryF(
4425 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
4426 [
'integer',
'integer'],
4427 [$active_id, $question_fi]
4430 $result =
$ilDB->queryF(
4431 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
4437 while ($row =
$ilDB->fetchAssoc($result)) {
4438 $result_array[$row[
"question_fi"]] = $row;
4440 return $result_array;
4449 $active_id = $this->getActiveIdOfUser(
$user_id);
4450 $this->db->manipulateF(
4451 "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
4452 [
'integer',
'integer'],
4453 [$active_id, $question_id]
4455 $this->db->manipulateF(
4456 "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
4457 [
'integer',
'integer',
'integer'],
4458 [$value, $question_id, $active_id]
4467 $result = $this->db->queryF(
4468 "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
4469 [
'integer',
'integer'],
4472 return $result->numRows() == 1;
4484 $result = $this->db->queryF(
4485 "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
4486 [
'integer',
'integer',
'integer'],
4489 return $result->numRows() == 1;
4497 return $this->getNrOfTries() != 0;
4508 return $tries >= $this->getNrOfTries();
4523 "user_id" => $this->
lng->txt(
"user_id"),
4524 "matriculation" => $this->
lng->txt(
"matriculation"),
4525 "lastname" => $this->
lng->txt(
"lastname"),
4526 "firstname" => $this->
lng->txt(
"firstname"),
4527 "login" => $this->
lng->txt(
"login"),
4528 "reached_points" => $this->
lng->txt(
"tst_reached_points"),
4529 "max_points" => $this->
lng->txt(
"tst_maximum_points"),
4530 "percent_value" => $this->
lng->txt(
"tst_percent_solved"),
4531 "mark" => $this->
lng->txt(
"tst_mark"),
4532 "passed" => $this->
lng->txt(
"tst_mark_passed"),
4535 if (count($participants)) {
4536 foreach ($participants as $active_id => $user_rec) {
4539 $reached_points = 0;
4543 if (!is_int($pass)) {
4546 foreach ($this->questions as $value) {
4548 if (is_object($question)) {
4549 $max_points += $question->getMaximumPoints();
4550 $reached_points += $question->getReachedPoints($active_id, $pass);
4553 if ($max_points > 0) {
4554 $percentvalue = $reached_points / $max_points;
4555 if ($percentvalue < 0) {
4556 $percentvalue = 0.0;
4561 $mark_obj = $this->getMarkSchema()->getMatchingMark($percentvalue * 100);
4563 if ($mark_obj !==
null) {
4564 $mark = $mark_obj->getOfficialName();
4566 if ($this->getAnonymity()) {
4567 $user_rec[
'firstname'] =
"";
4568 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
4571 "user_id" => $user_rec[
'usr_id'],
4572 "matriculation" => $user_rec[
'matriculation'],
4573 "lastname" => $user_rec[
'lastname'],
4574 "firstname" => $user_rec[
'firstname'],
4575 "login" => $user_rec[
'login'],
4576 "reached_points" => $reached_points,
4577 "max_points" => $max_points,
4578 "percent_value" => $percentvalue,
4580 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
4599 $result =
$ilDB->queryF(
4600 "SELECT tries FROM tst_active WHERE active_id = %s",
4604 if ($result->numRows()) {
4605 $row =
$ilDB->fetchAssoc($result);
4606 return $row[
"tries"];
4625 $result =
$ilDB->queryF(
4626 "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
4631 if ($result->numRows()) {
4632 $row =
$ilDB->fetchAssoc($result);
4633 return $row[
"maxpass"];
4649 $result =
$ilDB->queryF(
4650 "SELECT * FROM tst_pass_result WHERE active_fi = %s",
4655 if (!$result->numRows()) {
4661 while ($row =
$ilDB->fetchAssoc($result)) {
4662 if ($row[
"maxpoints"] > 0.0) {
4663 $factor = (float) ($row[
"points"] / $row[
"maxpoints"]);
4667 if ($factor === 0.0 && $bestfactor === 0.0
4668 || $factor > $bestfactor) {
4670 $bestfactor = $factor;
4674 if (is_array($bestrow)) {
4675 return $bestrow[
"pass"];
4691 $counted_pass =
null;
4697 return $counted_pass;
4711 if ($this->isRandomTest()) {
4712 $this->loadQuestions($active_id, $pass);
4715 foreach ($this->questions as $value) {
4716 if ($this->questionrepository->lookupResultRecordExist($active_id, $value, $pass)) {
4717 $workedthrough += 1;
4720 return $workedthrough;
4734 if (is_null($pass)) {
4739 SELECT tst_pass_result.tstamp pass_res_tstamp,
4740 tst_test_result.tstamp quest_res_tstamp
4742 FROM tst_pass_result
4744 LEFT JOIN tst_test_result
4745 ON tst_test_result.active_fi = tst_pass_result.active_fi
4746 AND tst_test_result.pass = tst_pass_result.pass
4748 WHERE tst_pass_result.active_fi = %s
4749 AND tst_pass_result.pass = %s
4751 ORDER BY tst_test_result.tstamp DESC
4754 $result =
$ilDB->queryF(
4756 [
'integer',
'integer'],
4760 while ($row =
$ilDB->fetchAssoc($result)) {
4761 if ($row[
'quest_res_tstamp']) {
4762 return $row[
'quest_res_tstamp'];
4765 return $row[
'pass_res_tstamp'];
4782 "executable" =>
true,
4783 "errormessage" =>
""
4786 if (!$this->getObjectProperties()->getPropertyIsOnline()->getIsOnline()) {
4787 $result[
"executable"] =
false;
4788 $result[
"errormessage"] = $this->
lng->txt(
'autosave_failed') .
': ' . $this->
lng->txt(
'offline');
4792 if (!$this->startingTimeReached()) {
4793 $result[
"executable"] =
false;
4797 if ($this->endingTimeReached()) {
4798 $result[
"executable"] =
false;
4803 $active_id = $this->getActiveIdOfUser(
$user_id);
4805 if ($this->getEnableProcessingTime()
4807 && ($starting_time = $this->getStartingTimeOfUser($active_id)) !==
false
4808 && $this->isMaxProcessingTimeReached($starting_time, $active_id)) {
4809 $result[
"executable"] =
false;
4810 $result[
"errormessage"] = $this->
lng->txt(
"detail_max_processing_time_reached");
4815 $testPassesSelector->setActiveId($active_id);
4816 $testPassesSelector->setLastFinishedPass($test_session->getLastFinishedPass());
4818 if ($this->hasNrOfTriesRestriction() && ($active_id > 0)) {
4819 $closedPasses = $testPassesSelector->getClosedPasses();
4821 if (count($closedPasses) >= $this->getNrOfTries()) {
4822 $result[
"executable"] =
false;
4823 $result[
"errormessage"] = $this->
lng->txt(
"maximum_nr_of_tries_reached");
4827 if ($this->isBlockPassesAfterPassedEnabled() && !$testPassesSelector->openPassExists()) {
4828 if ($this->test_result_repository->isPassed(
$user_id, $this->getId())) {
4829 $result[
'executable'] =
false;
4830 $result[
'errormessage'] = $this->
lng->txt(
"tst_addit_passes_blocked_after_passed_msg");
4836 $next_pass_allowed_timestamp = 0;
4837 if (!$this->isNextPassAllowed($testPassesSelector, $next_pass_allowed_timestamp)) {
4840 $result[
'executable'] =
false;
4841 $result[
'errormessage'] = sprintf($this->
lng->txt(
'wait_for_next_pass_hint_msg'), $date);
4849 $waiting_between_passes = $this->getMainSettings()->getTestBehaviourSettings()->getPassWaiting();
4853 $this->getMainSettings()->getTestBehaviourSettings()->getPassWaitingEnabled()
4854 && ($waiting_between_passes !==
'')
4856 && ($last_finished_pass_timestamp !==
null)
4858 $time_values = explode(
':', $waiting_between_passes);
4859 $next_pass_allowed_timestamp = strtotime(
'+ ' . $time_values[0] .
' Days + ' . $time_values[1] .
' Hours' . $time_values[2] .
' Minutes', $last_finished_pass_timestamp);
4860 return (time() > $next_pass_allowed_timestamp);
4870 $pass_selector->setActiveId($test_session->
getActiveId());
4873 return $pass_selector->hasReportablePasses();
4880 $pass_selector->setActiveId($test_session->
getActiveId());
4883 return $pass_selector->hasExistingPasses();
4895 if ($active_id < 1) {
4898 if ($pass ===
null) {
4899 $pass = ($this->getResetProcessingTime()) ? self::_getPass($active_id) : 0;
4901 $result = $this->db->queryF(
4902 "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
4903 [
'integer',
'integer'],
4906 if ($result->numRows()) {
4907 $row = $this->db->fetchAssoc($result);
4908 if (preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches)) {
4933 if (!$this->getEnableProcessingTime()) {
4937 $processing_time = $this->getProcessingTimeInSeconds($active_id);
4939 if ($now > ($starting_time + $processing_time)) {
4948 $tags_trafo = $this->
refinery->string()->stripTags();
4952 questtypes.type_tag,
4954 origquest.obj_fi orig_obj_fi
4956 FROM qpl_questions questions
4958 INNER JOIN qpl_qst_type questtypes
4959 ON questtypes.question_type_id = questions.question_type_fi
4961 INNER JOIN tst_test_question tstquest
4962 ON tstquest.question_fi = questions.question_id
4964 LEFT JOIN qpl_questions origquest
4965 ON origquest.question_id = questions.original_id
4967 WHERE tstquest.test_fi = %s
4969 ORDER BY tstquest.sequence
4972 $query_result = $this->db->queryF(
4975 [$this->getTestId()]
4980 while ($row = $this->db->fetchAssoc($query_result)) {
4981 $row[
'title'] = $tags_trafo->transform($row[
'title']);
4982 $row[
'description'] = $tags_trafo->transform($row[
'description'] !==
'' && $row[
'description'] !==
null ? $row[
'description'] :
' ');
4983 $row[
'author'] = $tags_trafo->transform($row[
'author']);
4985 $questions[] = $row;
4993 foreach ($this->getTestQuestions() as $questionData) {
4994 if ($questionData[
'question_id'] != $question_id) {
5006 $row = $this->db->fetchAssoc($this->db->queryF(
5007 "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
5008 [
'integer',
'integer'],
5009 [$question_id, $this->getId()]
5012 return (
bool) $row[
'cnt'];
5019 foreach ($this->getTestQuestions() as $question_data) {
5020 $points += $question_data[
'points'];
5033 questtypes.type_tag,
5034 origquest.obj_fi orig_obj_fi
5036 FROM qpl_questions questions
5038 INNER JOIN qpl_qst_type questtypes
5039 ON questtypes.question_type_id = questions.question_type_fi
5041 INNER JOIN tst_rnd_cpy tstquest
5042 ON tstquest.qst_fi = questions.question_id
5044 LEFT JOIN qpl_questions origquest
5045 ON origquest.question_id = questions.original_id
5047 WHERE tstquest.tst_fi = %s
5050 $query_result = $this->db->queryF(
5053 [$this->getTestId()]
5056 return $this->db->fetchAll($query_result);
5061 return $this->getMainSettings()->getQuestionBehaviourSettings()->getShuffleQuestions();
5077 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewMode();
5082 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getQuestionListEnabled();
5087 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewEnabled();
5092 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtBeginning();
5097 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtEnd();
5102 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getShowDescriptionInQuestionList();
5110 return $this->getScoreSettings()->getResultDetailsSettings()->getShowPassDetails();
5118 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionPrintview();
5125 return $this->getShowSolutionPrintview();
5133 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionFeedback();
5141 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionAnswersOnly();
5149 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionSignature();
5157 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionSuggested();
5166 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionListComparison();
5171 return $this->getScoreSettings()->getResultDetailsSettings()->getShowSolutionListOwnAnswers();
5181 $result =
$ilDB->queryF(
5182 "SELECT user_fi FROM tst_active WHERE active_id = %s",
5186 if ($result->numRows()) {
5187 $row =
$ilDB->fetchAssoc($result);
5188 return $row[
"user_fi"];
5196 $result = $this->db->queryF(
5197 "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
5201 if ($result->numRows()) {
5202 $row = $this->db->fetchAssoc($result);
5203 return $row[
"finished"];
5208 public static function lookupLastTestPassAccess(
int $active_id,
int $pass_index): ?
int
5215 SELECT MAX(tst_times.tstamp) as last_pass_access
5217 WHERE active_fi = %s
5223 [
'integer',
'integer'],
5224 [$active_id, $pass_index]
5227 while ($row =
$ilDB->fetchAssoc(
$res)) {
5228 return $row[
'last_pass_access'];
5243 if (preg_match(
"/<[^>]*?>/", $a_text)) {
5260 for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
5261 $material = $a_material->getMaterial($i);
5262 if ($material[
'type'] ===
'mattext') {
5263 $result .= $material[
'material']->getContent();
5265 if ($material[
'type'] ===
'matimage') {
5266 $matimage = $material[
'material'];
5267 if (preg_match(
'/(il_([0-9]+)_mob_([0-9]+))/', $matimage->getLabel(), $matches)) {
5269 'mob' => $matimage->getLabel(),
5270 'uri' => $matimage->getUri()
5276 $decoded_result = base64_decode($result);
5277 if (str_starts_with($decoded_result,
'<PageObject>')) {
5278 $result = $decoded_result;
5291 'texttype' =>
'text/plain'
5295 if ($page_id !==
null) {
5296 $attrs[
'texttype'] =
'text/xml';
5299 $page_object->buildDom();
5300 $page_object->insertInstIntoIDs((
string)
IL_INST_ID);
5301 $material = base64_encode($page_object->getXMLFromDom());
5303 foreach ($file_ids as $file_id) {
5304 $this->file_ids[] = (
int) $file_id;
5307 } elseif ($this->isHTML($material)) {
5308 $attrs[
'texttype'] =
'text/xhtml';
5310 $mob_string =
'mm_';
5313 $xml_writer->
xmlElement(
'mattext', $attrs, $material);
5314 foreach ($mobs as $mob) {
5315 $mob_id_string = (string) $mob;
5316 $moblabel =
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string;
5317 if (strpos($material, $mob_string . $mob_id_string) !==
false) {
5321 'label' => $moblabel,
5322 'uri' =>
'objects/' .
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string .
'/' . $mob_obj->getTitle()
5325 $xml_writer->
xmlElement(
'matimage', $imgattrs,
null);
5339 if ($txt_output ==
null) {
5344 $prepare_for_latex_output,
5345 $omitNl2BrWhenTextArea
5351 return $this->getMainSettings()->getGeneralSettings()->getAnonymity();
5356 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getSuspendTestAllowed();
5361 return $this->getMainSettings()->getParticipantFunctionalitySettings()->getQuestionMarkingEnabled();
5366 return $this->getMainSettings()->getAccessSettings()->getFixedParticipants();
5371 return $this->main_settings_repository->getFor(
5372 self::_getTestIDFromObjectID(self::_getObjectIDFromActiveID($active_id)),
5373 )->getGeneralSettings()->getQuestionSetType();
5388 if ($this->getAnonymity() && !$overwrite_anonymity) {
5389 return $this->
lng->txt(
"anonymous") . $suffix;
5392 if (strlen($uname[
"firstname"] . $uname[
"lastname"]) == 0) {
5393 $uname[
"firstname"] = $this->
lng->txt(
"deleted_user");
5395 if ($sorted_order) {
5396 return trim($uname[
"lastname"] .
", " . $uname[
"firstname"]) . $suffix;
5398 return trim($uname[
"firstname"] .
" " . $uname[
"lastname"]) . $suffix;
5404 DateTimeImmutable|
int|
null $date_time
5405 ): ?DateTimeImmutable {
5406 if ($date_time === null || $date_time instanceof DateTimeImmutable) {
5410 return DateTimeImmutable::createFromFormat(
'U', (
string) $date_time);
5422 if (extension_loaded(
"tidy")) {
5425 "output-xml" =>
true,
5426 "numeric-entities" =>
true
5429 $tidy->parseString($print_output, $config,
'utf8');
5430 $tidy->cleanRepair();
5431 $print_output = tidy_get_output($tidy);
5432 $print_output = preg_replace(
"/^.*?(<html)/",
"\\1", $print_output);
5434 $print_output = str_replace(
" ",
" ", $print_output);
5435 $print_output = str_replace(
"⊗",
"X", $print_output);
5437 $xsl = file_get_contents(
"./components/ILIAS/Test/xml/question2fo.xsl");
5442 'font-family="Helvetica, unifont"',
5443 'font-family="' . $this->
settings->get(
'rpc_pdf_font',
'Helvetica, unifont') .
'"',
5447 $args = [
'/_xml' => $print_output,
'/_xsl' => $xsl ];
5448 $xh = xslt_create();
5450 $output = xslt_process($xh,
"arg:/_xml",
"arg:/_xsl",
null, $args,
$params);
5464 $content = preg_replace(
"/href=\".*?\"/",
"", $content);
5465 $printbody =
new ilTemplate(
"tpl.il_as_tst_print_body.html",
true,
true,
"components/ILIAS/Test");
5467 $printbody->setVariable(
"ADM_CONTENT", $content);
5468 $printbody->setCurrentBlock(
"css_file");
5470 $printbody->parseCurrentBlock();
5471 $printoutput = $printbody->get();
5472 $html = str_replace(
"href=\"./",
"href=\"" . ILIAS_HTTP_PATH .
"/", $printoutput);
5473 $html = preg_replace(
"/<div id=\"dontprint\">.*?<\\/div>/ims",
"", $html);
5474 if (extension_loaded(
"tidy")) {
5477 "output-xml" =>
true,
5478 "numeric-entities" =>
true
5481 $tidy->parseString($html, $config,
'utf8');
5482 $tidy->cleanRepair();
5483 $html = tidy_get_output($tidy);
5484 $html = preg_replace(
"/^.*?(<html)/",
"\\1", $html);
5486 $html = str_replace(
" ",
" ", $html);
5487 $html = str_replace(
"⊗",
"X", $html);
5489 $html = preg_replace(
"/src=\".\\//ims",
"src=\"" . ILIAS_HTTP_PATH .
"/", $html);
5490 $this->deliverPDFfromFO($this->processPrintoutput2FO($html), $title);
5501 $fp = fopen($fo_file,
"w");
5510 $pdf_base64->scalar,
5515 }
catch (Exception
$e) {
5516 $this->
logger->info(__METHOD__ .
': ' .
$e->getMessage());
5532 if ($pass ===
null) {
5536 $row = self::getSingleManualFeedback((
int) $active_id, (
int) $question_id, (
int) $pass);
5539 $feedback = $row[
'feedback'] ??
'';
5550 $result =
$ilDB->queryF(
5551 "SELECT * FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
5552 [
'integer',
'integer',
'integer'],
5553 [$active_id, $question_id, $pass]
5556 if (
$ilDB->numRows($result) === 1) {
5557 $row =
$ilDB->fetchAssoc($result);
5559 } elseif (
$ilDB->numRows($result) > 1) {
5560 $DIC->logger()->root()->warning(
5561 "WARNING: Multiple feedback entries on tst_manual_fb for " .
5562 "active_fi = $active_id , question_fi = $question_id and pass = $pass"
5582 $result =
$ilDB->queryF(
5583 "SELECT * FROM tst_manual_fb WHERE question_fi = %s",
5588 while ($row =
$ilDB->fetchAssoc($result)) {
5589 $active = $row[
'active_fi'];
5590 $pass = $row[
'pass'];
5591 $question = $row[
'question_fi'];
5595 $feedback[$active][$pass][$question] = $row;
5606 bool $finalized =
false
5608 $feedback_old = self::getSingleManualFeedback($active_id, $question_id, $pass);
5609 $this->db->manipulateF(
5610 'DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s',
5611 [
'integer',
'integer',
'integer'],
5612 [$active_id, $question_id, $pass]
5615 $this->insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old);
5627 $next_id = $this->db->nextId(
'tst_manual_fb');
5628 $user = $this->
user->getId();
5629 $finalized_time = time();
5632 'manual_feedback_id' => [
'integer', $next_id],
5633 'active_fi' => [
'integer', $active_id],
5634 'question_fi' => [
'integer', $question_id],
5635 'pass' => [
'integer', $pass],
5637 'tstamp' => [
'integer', time()]
5640 if ($feedback_old !== [] && (
int) $feedback_old[
'finalized_evaluation'] === 1) {
5641 $user = $feedback_old[
'finalized_by_usr_id'];
5642 $finalized_time = $feedback_old[
'finalized_tstamp'];
5645 if ($finalized ===
false) {
5646 $update_default[
'finalized_evaluation'] = [
'integer', 0];
5647 $update_default[
'finalized_by_usr_id'] = [
'integer', 0];
5648 $update_default[
'finalized_tstamp'] = [
'integer', 0];
5649 } elseif ($finalized ===
true) {
5650 $update_default[
'finalized_evaluation'] = [
'integer', 1];
5651 $update_default[
'finalized_by_usr_id'] = [
'integer', $user];
5652 $update_default[
'finalized_tstamp'] = [
'integer', $finalized_time];
5655 $this->db->insert(
'tst_manual_fb', $update_default);
5672 $this->test_sequence =
new ilTestSequence($active_id, $pass, $this->isRandomTest(), $this->questionrepository);
5682 $this->test_id = $a_id;
5695 if (count($participants)) {
5696 foreach ($participants as $active_id => $user_rec) {
5698 $reached_points = 0;
5701 foreach ($this->questions as $value) {
5703 if (is_object($question)) {
5704 $max_points += $question->getMaximumPoints();
5705 $reached_points += $question->getReachedPoints($active_id, $pass);
5706 if ($max_points > 0) {
5707 $percentvalue = $reached_points / $max_points;
5708 if ($percentvalue < 0) {
5709 $percentvalue = 0.0;
5714 if ($this->getAnonymity()) {
5715 $user_rec[
'firstname'] =
"";
5716 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
5719 "user_id" => $user_rec[
'usr_id'],
5720 "matriculation" => $user_rec[
'matriculation'],
5721 "lastname" => $user_rec[
'lastname'],
5722 "firstname" => $user_rec[
'firstname'],
5723 "login" => $user_rec[
'login'],
5724 "question_id" => $question->getId(),
5725 "question_title" => $question->getTitle(),
5726 "reached_points" => $reached_points,
5727 "max_points" => $max_points,
5728 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
5745 $result =
$ilDB->queryF(
5746 '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',
5750 $rec =
$ilDB->fetchAssoc($result);
5751 return $rec[
'obj_id'] ??
null;
5762 if (!$this->component_repository->getComponentByTypeAndName(
5765 )->getPluginSlotById(
'qst')->hasPluginName($a_pname)) {
5769 return $this->component_repository
5770 ->getComponentByTypeAndName(
5774 ->getPluginSlotById(
5788 SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass
5789 FROM tst_test_result
5790 INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s
5791 INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi
5792 LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi
5793 WHERE tst_test_result.question_fi = %s
5794 ORDER BY usr_data.lastname ASC, usr_data.firstname ASC
5797 $result = $this->db->queryF(
5799 [
'integer',
'integer'],
5800 [$test_id, $question_id]
5804 while ($row = $this->db->fetchAssoc($result)) {
5805 if ($this->getAccessFilteredParticipantList() && !$this->getAccessFilteredParticipantList()->isActiveIdInList($row[
"active_fi"])) {
5809 if (!array_key_exists($row[
"active_fi"], $foundusers)) {
5810 $foundusers[$row[
"active_fi"]] = [];
5812 array_push($foundusers[$row[
"active_fi"]], [
"pass" => $row[
"pass"],
"qid" => $row[
"question_fi"]]);
5819 $data = $this->getCompleteEvaluationData();
5820 $found_participants =
$data->getParticipants();
5821 $results = [
'overview' => [],
'questions' => []];
5822 if ($found_participants !== []) {
5823 $results[
'overview'][
'tst_stat_result_mark_median'] =
$data->getStatistics()->getEvaluationDataOfMedianUser()?->getMark()?->getShortName() ??
'';
5824 $results[
'overview'][
'tst_stat_result_rank_median'] =
$data->getStatistics()->rankMedian();
5825 $results[
'overview'][
'tst_stat_result_total_participants'] =
$data->getStatistics()->count();
5826 $results[
'overview'][
'tst_stat_result_median'] =
$data->getStatistics()->median();
5827 $results[
'overview'][
'tst_eval_total_persons'] = count($found_participants);
5828 $total_finished =
$data->getTotalFinishedParticipants();
5829 $results[
'overview'][
'tst_eval_total_finished'] = $total_finished;
5830 $results[
'overview'][
'tst_eval_total_finished_average_time'] =
5831 $this->secondsToHoursMinutesSecondsString(
5832 $this->evalTotalStartedAverageTime(
$data->getParticipantIds())
5835 $total_passed_reached = 0;
5836 $total_passed_max = 0;
5837 $total_passed_time = 0;
5838 foreach ($found_participants as $userdata) {
5839 if ($userdata->getMark()?->getPassed()) {
5841 $total_passed_reached += $userdata->getReached();
5842 $total_passed_max += $userdata->getMaxpoints();
5843 $total_passed_time += $userdata->getTimeOnTask();
5846 $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
5847 $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
5848 $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
5849 $results[
'overview'][
'tst_eval_total_passed'] = $total_passed;
5850 $results[
'overview'][
'tst_eval_total_passed_average_points'] = sprintf(
'%2.2f', $average_passed_reached)
5851 .
' ' . strtolower(
'of') .
' ' . sprintf(
'%2.2f', $average_passed_max);
5852 $results[
'overview'][
'tst_eval_total_passed_average_time'] =
5853 $this->secondsToHoursMinutesSecondsString((
int) $average_passed_time);
5856 foreach (
$data->getQuestionTitles() as $question_id => $question_title) {
5860 foreach ($found_participants as $userdata) {
5861 for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
5862 if (is_object($userdata->getPass($i))) {
5863 $question = $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
5864 if (is_array($question)) {
5866 $reached += $question[
'reached'];
5867 $max += $question[
'points'];
5872 $percent = $max ? $reached / $max * 100.0 : 0;
5873 $results[
'questions'][$question_id] = [
5875 sprintf(
'%.2f', $answered ? $reached / $answered : 0) .
' ' . strtolower($this->
lng->txt(
'of')) .
' ' . sprintf(
'%.2f', $answered ? $max / $answered : 0),
5876 sprintf(
'%.2f', $percent) .
'%',
5878 sprintf(
'%.2f', $answered ? $reached / $answered : 0),
5879 sprintf(
'%.2f', $answered ? $max / $answered : 0),
5888 $diff_hours = floor($seconds / 3600);
5889 $seconds -= $diff_hours * 3600;
5890 $diff_minutes = floor($seconds / 60);
5891 $seconds -= $diff_minutes * 60;
5892 return sprintf(
'%02d:%02d:%02d', $diff_hours, $diff_minutes, $seconds);
5900 return $this->export_factory->getExporter($this,
'xml')
5906 return $this->getScoreSettings()->getResultDetailsSettings()->getExportSettings();
5911 $this->template_id = $template_id;
5916 return $this->template_id;
5921 $question_set_config = $this->question_set_config_factory->getQuestionSetConfig();
5922 $reindexed_sequence_position_map = $question_set_config->reindexQuestionOrdering();
5924 $this->loadQuestions();
5926 return $reindexed_sequence_position_map;
5935 foreach (array_keys($order) as
$id) {
5939 UPDATE tst_test_question
5941 WHERE question_fi = %s
5944 $this->db->manipulateF(
5946 [
'integer',
'integer'],
5951 if ($this->
logger->isLoggingEnabled()) {
5952 $this->
logger->logTestAdministrationInteraction(
5953 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
5955 $this->user->getId(),
5956 TestAdministrationInteractionTypes::QUESTION_MOVED,
5958 AdditionalInformationGenerator::KEY_QUESTION_ORDER => $order
5964 $this->loadQuestions();
5969 $questions = $this->getQuestionTitlesAndIndexes();
5971 $IN_questions = $this->db->in(
'q1.question_id', array_keys($questions),
false,
'integer');
5974 SELECT count(q1.question_id) cnt
5976 FROM qpl_questions q1
5978 INNER JOIN qpl_questions q2
5979 ON q2.question_id = q1.original_id
5982 AND q1.obj_fi = q2.obj_fi
5984 $rset = $this->db->query($query);
5985 $row = $this->db->fetchAssoc($rset);
5987 return $row[
'cnt'] > 0;
6001 $result =
$ilDB->queryF(
6002 "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
6003 " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
6004 " WHERE user_fi=%s" .
6005 " GROUP BY test_fi",
6006 [
'integer',
'integer'],
6010 while ($row =
$ilDB->fetchAssoc($result)) {
6011 $obj_id = self::_getObjectIDFromTestID($row[
"test_fi"]);
6012 $all[$obj_id] = (bool) $row[
"pass"];
6019 return $this->questions;
6024 return $this->online;
6029 $page_id = $this->getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
6030 if ($page_id !==
null) {
6035 $page_object->setParentId($this->
getId());
6036 $new_page_id = $page_object->createPageWithNextId();
6037 $settings = $this->getMainSettings()->getIntroductionSettings()
6038 ->withIntroductionPageId($new_page_id);
6039 $this->getMainSettingsRepository()->store(
6040 $this->getMainSettings()->withIntroductionSettings($settings)
6042 return $new_page_id;
6047 $page_id = $this->getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
6048 if ($page_id !==
null) {
6053 $page_object->setParentId($this->
getId());
6054 $new_page_id = $page_object->createPageWithNextId();
6055 $settings = $this->getMainSettings()->getFinishingSettings()
6056 ->withConcludingRemarksPageId($new_page_id);
6057 $this->getMainSettingsRepository()->store(
6058 $this->getMainSettings()->withFinishingSettings($settings)
6060 return $new_page_id;
6065 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreEnabled();
6079 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreAnon();
6092 return $this->getAnonymity() == 1 || $this->getHighscoreAnon();
6100 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreAchievedTS();
6108 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreScore();
6116 return $this->getScoreSettings()->getGamificationSettings()->getHighscorePercentage();
6124 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreWTime();
6132 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreOwnTable();
6140 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreTopTable();
6149 return $this->getScoreSettings()->getGamificationSettings()->getHighscoreTopNum();
6154 return $this->getScoreSettings()->getGamificationSettings()->getHighScoreMode();
6159 return $this->getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled();
6164 return $this->getMainSettings()->getQuestionBehaviourSettings()->getAutosaveEnabled();
6169 return $this->getScoreSettings()->getResultSummarySettings()->getPassDeletionAllowed();
6174 return $this->getMainSettings()->getFinishingSettings()->getShowAnswerOverview();
6186 $result = $this->db->queryF(
6187 "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",
6189 [$this->getTestId()]
6191 while ($row = $this->db->fetchAssoc($result)) {
6192 $times[$row[
'active_fi']] = $row[
'started'];
6200 $result = $this->db->queryF(
6201 "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",
6203 [$this->getTestId()]
6205 while ($row = $this->db->fetchAssoc($result)) {
6206 $times[$row[
'active_fi']] = $row[
'additionaltime'];
6213 if ($active_id === 0) {
6216 return $this->participant_repository
6217 ->getParticipantByActiveId($this->getTestId(), $active_id)
6218 ?->getExtraTime() ?? 0;
6224 SELECT MAX(tst_pass_result.pass) + 1 max_res
6225 FROM tst_pass_result
6226 INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi
6227 WHERE test_fi = ' . $this->db->quote($this->getTestId(),
'integer') .
'
6229 $res = $this->db->query($query);
6231 return (
int)
$data[
'max_res'];
6239 $exam_id_query =
'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
6240 $exam_id_result =
$ilDB->queryF($exam_id_query, [
'integer',
'integer' ], [ $active_id, $pass ]);
6241 if (
$ilDB->numRows($exam_id_result) == 1) {
6242 $exam_id_row =
$ilDB->fetchAssoc($exam_id_result);
6244 if ($exam_id_row[
'exam_id'] !=
null) {
6245 return $exam_id_row[
'exam_id'];
6252 public static function buildExamId($active_id, $pass, $test_obj_id =
null): string
6259 if ($test_obj_id ===
null) {
6260 $obj_id = self::_getObjectIDFromActiveID($active_id);
6262 $obj_id = $test_obj_id;
6265 $examId =
'I' . $inst_id .
'_T' . $obj_id .
'_A' . $active_id .
'_P' . $pass;
6272 return $this->getMainSettings()->getTestBehaviourSettings()->getExamIdInTestAttemptEnabled();
6277 return $this->getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults();
6283 $this->main_settings = $this->getMainSettings()->withGeneralSettings(
6285 ->withQuestionSetType($question_set_type)
6291 return $this->getMainSettings()->getGeneralSettings()->getQuestionSetType();
6301 return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_FIXED;
6311 return $this->getQuestionSetType() == self::QUESTION_SET_TYPE_RANDOM;
6316 switch ($questionSetType) {
6318 return $lng->txt(
'tst_question_set_type_fixed');
6321 return $lng->txt(
'tst_question_set_type_random');
6324 throw new ilTestException(
'invalid question set type value given: ' . $questionSetType);
6329 if ($this->participantDataExist ===
null) {
6330 $this->participantDataExist = (bool) $this->evalTotalPersons();
6333 return $this->participantDataExist;
6342 $this->test_result_repository
6344 $scoring->setPreserveManualScores($preserve_manscoring);
6345 $scoring->recalculateSolutions();
6356 INNER JOIN tst_tests
6357 ON test_id = test_fi
6361 $res =
$ilDB->queryF($query, [
'integer'], [$userId]);
6365 while ($row =
$ilDB->fetchAssoc(
$res)) {
6366 $objIds[] = (
int) $row[
'obj_fi'];
6374 return $this->getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled();
6390 if (!$this->getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled()) {
6394 if (!self::isSkillManagementGloballyActivated()) {
6401 private static $isSkillManagementGloballyActivated =
null;
6405 if (self::$isSkillManagementGloballyActivated ===
null) {
6408 self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
6411 return self::$isSkillManagementGloballyActivated;
6416 return $this->getScoreSettings()->getResultSummarySettings()->getShowGradingStatusEnabled();
6421 return $this->getScoreSettings()->getResultSummarySettings()->getShowGradingMarkEnabled();
6426 return $this->getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled();
6431 return $this->getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled();
6436 return $this->getMainSettings()->getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion();
6444 $ilUser =
$DIC[
'ilUser'];
6448 $active_id = $test_obj->getActiveIdOfUser(
$user_id);
6453 $test_session_factory->reset();
6455 $test_sequence_factory =
new ilTestSequenceFactory($test_obj,
$ilDB, TestDIC::dic()[
'question.general_properties.repository']);
6457 $test_session = $test_session_factory->getSession($active_id);
6458 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $test_session->getPass());
6459 $test_sequence->loadFromDb();
6461 return $test_sequence->hasSequence();
6467 SELECT COUNT(test_question_id) cnt
6468 FROM tst_test_question
6473 $questRes = $this->db->queryF($query, [
'integer'], [$this->getTestId()]);
6475 $row = $this->db->fetchAssoc($questRes);
6476 $questCount = $row[
'cnt'];
6478 if ($this->getShuffleQuestions()) {
6482 INNER JOIN tst_sequence tseq
6483 ON tseq.active_fi = tac.active_id
6484 WHERE tac.test_fi = %s
6487 $partRes = $this->db->queryF(
6490 [$this->getTestId()]
6493 while ($row = $this->db->fetchAssoc($partRes)) {
6494 $sequence = @unserialize($row[
'sequence']);
6500 $sequence = array_filter($sequence,
function ($value) use ($questCount) {
6501 return $value <= $questCount;
6504 $num_seq = count($sequence);
6505 if ($questCount > $num_seq) {
6506 $diff = $questCount - $num_seq;
6507 for ($i = 1; $i <= $diff; $i++) {
6508 $sequence[$num_seq + $i - 1] = $num_seq + $i;
6512 $new_sequence = serialize($sequence);
6514 $this->db->update(
'tst_sequence', [
6515 'sequence' => [
'clob', $new_sequence]
6517 'active_fi' => [
'integer', $row[
'active_fi']],
6518 'pass' => [
'integer', $row[
'pass']]
6522 $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : []);
6527 INNER JOIN tst_sequence tseq
6528 ON tseq.active_fi = tac.active_id
6529 WHERE tac.test_fi = %s
6532 $part_rest = $this->db->queryF(
6535 [$this->getTestId()]
6538 while ($row = $this->db->fetchAssoc($part_rest)) {
6539 $this->db->update(
'tst_sequence', [
6540 'sequence' => [
'clob', $new_sequence]
6542 'active_fi' => [
'integer', $row[
'active_fi']],
6543 'pass' => [
'integer', $row[
'pass']]
6559 return $this->questionrepository;
6564 return $this->global_settings_repo->getGlobalSettings();
6569 if (!$this->main_settings) {
6570 $this->main_settings = $this->getMainSettingsRepository()
6571 ->getFor($this->getTestId());
6573 return $this->main_settings;
6578 return $this->main_settings_repository;
6583 if (!$this->score_settings) {
6584 $this->score_settings = $this->getScoreSettingsRepository()
6585 ->getFor($this->getTestId());
6587 return $this->score_settings;
6592 return $this->score_settings_repository;
6596 bool $old_online_status,
6597 bool $new_online_status
6599 if (!$old_online_status && $new_online_status) {
6601 $newsItem->setContext($this->
getId(),
'tst');
6603 $newsItem->setTitle(
'new_test_online');
6604 $newsItem->setContentIsLangVar(
true);
6605 $newsItem->setContent(
'');
6606 $newsItem->setUserId($this->
user->getId());
6608 $newsItem->create();
6612 if ($old_online_status && !$new_online_status) {
6618 if (!$new_online_status && $newsId > 0) {
6620 $newsItem->setTitle(
'new_test_online');
6621 $newsItem->setContentIsLangVar(
true);
6622 $newsItem->setContent(
'');
6623 $newsItem->update();
6632 return TestDIC::dic()[
'settings.main.repository']->getFor(
6634 )->getGeneralSettings()->getQuestionSetType() === self::QUESTION_SET_TYPE_RANDOM;
6639 return $this->participant_repository->getFirstAndLastVisitForActiveId($active_id);
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
Class ResourceIdentification.
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()
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.
isPreviousSolutionReuseEnabled()
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.
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.
MediaObjectRepository $media_object_repository
getPotentialRandomTestQuestions()
getScoreSettingsRepository()
inviteUser($user_id, $client_ip="")
Invites a user to a test.
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)
processPrintoutput2FO($print_output)
Convert a print output to XSL-FO.
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.
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.
getPassScoring()
Gets the pass scoring type.
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
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.
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()
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)
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.
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()
MainSettingsRepository $main_settings_repository
int $activation_starting_time
addConcludingRemarksToSettingsFromImport(SettingsFinishing $settings, array $material, array $mappings)
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
SettingsFactory $settings_factory
getHighscoreTopNum(int $a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
Repository $test_result_repository
static _getCountSystem(int $active_id)
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 ...
static _getScoreSettingsByActiveId(int $active_id)
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)
setTemplate(int $template_id)
getAllTestResults($participants)
returns all test results for all participants
GlobalSettingsRepository $global_settings_repo
static _getPassScoring(int $active_id)
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
ScoreSettingsRepository $score_settings_repository
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
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()
addIntroductionToSettingsFromImport(SettingsIntroduction $settings, array $material, array $mappings)
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.
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 $package, int $timeout=0)
static get(string $a_var)
Skill management settings.
special template class to simplify handling of ITX/PEAR
Base Exception for all Exceptions relating to Modules/Test.
@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
TestAdministrationInteractionTypes
TestScoringInteractionTypes
Class ilObjForumAdministration.
if(!file_exists('../ilias.ini.php'))