19 declare(strict_types=1);
158 public function __construct(
int $id = 0,
bool $a_call_by_reference =
true)
164 $this->
ctrl = $DIC[
'ilCtrl'];
166 $this->
settings = $DIC[
'ilSetting'];
167 $this->bench = $DIC[
'ilBench'];
168 $this->component_repository = $DIC[
'component.repository'];
169 $this->component_factory = $DIC[
'component.factory'];
170 $this->filesystem_web = $DIC->filesystem()->web();
171 $this->lo_metadata = $DIC->learningObjectMetadata();
174 $this->participant_access_filter = $local_dic[
'participant.access_filter.factory'];
175 $this->test_man_scoring_done_helper = $local_dic[
'scoring.manual.done_helper'];
176 $this->
logger = $local_dic[
'logging.logger'];
177 $this->log_viewer = $local_dic[
'logging.viewer'];
178 $this->global_settings_repo = $local_dic[
'settings.global.repository'];
179 $this->marks_repository = $local_dic[
'marks.repository'];
180 $this->questionrepository = $local_dic[
'question.general_properties.repository'];
181 $this->testrequest = $local_dic[
'request_data_collector'];
182 $this->participant_repository = $local_dic[
'participant.repository'];
183 $this->export_factory = $local_dic[
'exportimport.factory'];
187 $this->
lng->loadLanguageModule(
"assessment");
188 $this->score_settings =
null;
195 $this->component_repository,
197 $this->questionrepository
203 return TestDIC::dic();
218 return $this->question_set_config_factory->getQuestionSetConfig();
241 $id = parent::create();
248 if (!parent::update()) {
260 $this->main_settings =
null;
261 $this->score_settings =
null;
262 $this->mark_schema =
null;
266 public function delete():
bool 269 if (!parent::delete()) {
280 $qsaImportFails->deleteRegisteredImportFails();
282 $sltImportFails->deleteRegisteredImportFails();
284 if ($this->
logger->isLoggingEnabled()) {
285 $this->
logger->logTestAdministrationInteraction(
286 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
288 $this->
user->getId(),
291 AdditionalInformationGenerator::KEY_TEST_TITLE => $test_title =
$this->title 303 $participantData->load($this->
getTestId());
306 $this->db->manipulateF(
307 "DELETE FROM tst_mark WHERE test_fi = %s",
312 $this->db->manipulateF(
313 "DELETE FROM tst_tests WHERE test_id = %s",
319 $directory = $tst_data_dir .
"/tst_" . $this->
getId();
320 if (is_dir($directory)) {
328 foreach ($mobs as $mob) {
346 if (!is_writable($tst_data_dir)) {
347 $this->
ilias->raiseError(
"Test Data Directory (" . $tst_data_dir
348 .
") not writeable.", $this->
ilias->error_obj->MESSAGE);
352 $tst_dir = $tst_data_dir .
"/tst_" . $this->
getId();
354 if (!@is_dir($tst_dir)) {
355 $this->
ilias->raiseError(
"Creation of Test Directory failed.", $this->
ilias->error_obj->MESSAGE);
358 $export_dir = $tst_dir .
"/export";
360 if (!@is_dir($export_dir)) {
361 $this->
ilias->raiseError(
"Creation of Export Directory failed.", $this->
ilias->error_obj->MESSAGE);
371 public function getExportFiles(
string $dir =
''): array
374 if (!@is_dir($dir) || !is_writable($dir)) {
383 if ($file->isDir()) {
387 $files[] = $file->getBasename();
407 if (!is_writable($tst_data_dir)) {
409 .
") not writeable.",
$ilias->error_obj->FATAL);
413 $tst_dir = $tst_data_dir .
"/tst_import";
415 if (!@is_dir($tst_dir)) {
442 if ($this->
isComplete($test_question_set_config)) {
446 $this->db->manipulateF(
447 'UPDATE tst_tests SET complete = %s WHERE test_id = %s',
449 [$complete, $this->test_id]
454 public function saveToDb(
bool $properties_only =
false): void
456 if ($this->test_id === -1) {
458 $next_id = $this->db->nextId(
'tst_tests');
463 'test_id' => [
'integer', $next_id],
464 'obj_fi' => [
'integer', $this->
getId()],
465 'created' => [
'integer', time()],
466 'tstamp' => [
'integer', time()],
471 $this->test_id = $next_id;
477 $aresult = $this->db->queryF(
478 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
479 [
'integer',
'integer',
'integer'],
482 while ($row = $this->db->fetchAssoc($aresult)) {
483 $this->db->manipulateF(
484 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
485 [
'integer',
'timestamp',
'integer'],
486 [1, date(
'Y-m-d H:i:s'), $row[
"active_id"]]
491 $aresult = $this->db->queryF(
492 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
493 [
'integer',
'integer',
'integer'],
496 while ($row = $this->db->fetchAssoc($aresult)) {
497 $this->db->manipulateF(
498 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
499 [
'integer',
'timestamp',
'integer'],
500 [0,
null, $row[
"active_id"]]
505 $aresult = $this->db->queryF(
506 "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
507 [
'integer',
'integer'],
510 while ($row = $this->db->fetchAssoc($aresult)) {
511 $this->db->manipulateF(
512 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
513 [
'integer',
'timestamp',
'integer'],
514 [0,
null, $row[
"active_id"]]
528 if ($properties_only) {
536 $this->marks_repository->storeMarkSchema($this->
getMarkSchema());
541 $this->db->manipulateF(
542 'DELETE FROM tst_test_question WHERE test_fi = %s',
546 foreach ($this->questions as $key => $value) {
547 $next_id = $this->db->nextId(
'tst_test_question');
548 $this->db->insert(
'tst_test_question', [
549 'test_question_id' => [
'integer', $next_id],
550 'test_fi' => [
'integer', $this->
getTestId()],
551 'question_fi' => [
'integer', $value],
552 'sequence' => [
'integer', $key],
553 'tstamp' => [
'integer', time()]
566 foreach ($question_ids as
$id) {
567 $question = assQuestion::instantiateQuestionGUI($id);
569 $title = $question->getObject()->getTitle();
571 while (in_array(
$title .
' (' . $i .
')', $question_titles)) {
575 $title .=
' (' . $i .
')';
577 $question_titles[] =
$title;
579 $new_id = $question->getObject()->duplicate(
false,
$title);
581 $clone = assQuestion::instantiateQuestionGUI($new_id);
582 $question = $clone->getObject();
583 $question->setObjId($this->
getId());
584 $clone->setObject($question);
585 $clone->getObject()->saveToDb();
599 $result = $this->db->queryF(
600 "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
601 [
'integer',
'integer'],
604 return $result->numRows();
609 $result = $this->db->queryF(
610 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
614 if ($result->numRows() === 1) {
615 $data = $this->db->fetchObject($result);
621 if (isset($this->ref_id)) {
623 switch ($activation[
"timing_type"]) {
644 $this->questions = [];
646 if ($active_id === 0) {
649 if (is_null($pass)) {
650 $pass = self::_getPass($active_id);
652 $result = $this->db->queryF(
653 'SELECT tst_test_rnd_qst.* ' 654 .
'FROM tst_test_rnd_qst, qpl_questions ' 655 .
'WHERE tst_test_rnd_qst.active_fi = %s ' 656 .
'AND qpl_questions.question_id = tst_test_rnd_qst.question_fi ' 657 .
'AND tst_test_rnd_qst.pass = %s ' 658 .
'ORDER BY sequence',
659 [
'integer',
'integer'],
663 $result = $this->db->queryF(
664 'SELECT tst_test_question.* ' 665 .
'FROM tst_test_question, qpl_questions ' 666 .
'WHERE tst_test_question.test_fi = %s ' 667 .
'AND qpl_questions.question_id = tst_test_question.question_fi ' 668 .
'ORDER BY sequence',
674 if ($this->test_id !== -1) {
676 while (
$data = $this->db->fetchAssoc($result)) {
677 $this->questions[$index++] =
$data[
"question_fi"];
684 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
685 if ($page_id !==
null) {
689 return $this->
getMainSettings()->getIntroductionSettings()->getIntroductionText();
694 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
695 if ($page_id ===
null) {
703 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
704 if ($page_id !==
null) {
707 return $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksText();
712 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
713 if ($page_id ===
null) {
722 $page_object->setParentId($this->
getId());
723 $new_page_id = $page_object->createPageWithNextId();
724 (
new ilTestPage($source_page_id))->copy($new_page_id);
738 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getPostponedQuestionsMoveToEnd();
743 return $this->
getScoreSettings()->getResultSummarySettings()->getScoreReporting()->isReportingEnabled();
748 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled();
753 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled();
758 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled();
769 $ilDB = $DIC[
'ilDB'];
770 $result =
$ilDB->queryF(
771 "SELECT tst_tests.count_system FROM tst_tests, tst_active WHERE tst_active.active_id = %s AND tst_active.test_fi = tst_tests.test_id",
775 if ($result->numRows()) {
776 $row =
$ilDB->fetchAssoc($result);
777 return $row[
"count_system"];
804 $ilDB = $DIC[
'ilDB'];
805 $result =
$ilDB->queryF(
806 "SELECT tst_tests.pass_scoring FROM tst_tests, tst_active WHERE tst_tests.test_id = tst_active.test_fi AND tst_active.active_id = %s",
810 if ($result->numRows()) {
811 $row =
$ilDB->fetchAssoc($result);
812 return (
int) $row[
"pass_scoring"];
823 $ilDB = $DIC[
'ilDB'];
824 $result =
$ilDB->queryF(
825 "SELECT tst_tests.score_cutting FROM tst_tests, tst_active WHERE tst_active.active_id = %s AND tst_tests.test_id = tst_active.test_fi",
829 if ($result->numRows()) {
830 $row =
$ilDB->fetchAssoc($result);
831 return (
bool) $row[
"score_cutting"];
838 if ($this->mark_schema ===
null) {
839 $this->mark_schema = $this->marks_repository->getMarkSchemaFor($this->
getTestId());
847 $this->marks_repository->storeMarkSchema($mark_schema);
848 $this->mark_schema =
null;
853 return $this->
getMainSettings()->getTestBehaviourSettings()->getNumberOfTries();
858 return $this->
getMainSettings()->getTestBehaviourSettings()->getBlockAfterPassedEnabled();
863 return $this->
getMainSettings()->getTestBehaviourSettings()->getKioskModeEnabled();
868 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowTitleInKioskMode();
872 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowParticipantNameInKioskMode();
877 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed();
882 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getQuestionTitleOutputMode();
887 $result = $this->db->queryF(
888 "SELECT tst_tests.use_previous_answers FROM tst_tests, tst_active WHERE tst_tests.test_id = tst_active.test_fi AND tst_active.active_id = %s",
892 if ($result->numRows()) {
893 $row = $this->db->fetchAssoc($result);
894 $test_allows_reuse = $row[
"use_previous_answers"];
897 if ($test_allows_reuse ===
'1') {
898 $res = $this->
user->getPref(
"tst_use_previous_answers");
908 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
913 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
914 if ($processing_time ===
null 915 || $processing_time ===
'' 916 || !preg_match(
'/(\d{2}):(\d{2}):(\d{2})/is', $processing_time, $matches)
931 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime() ??
'';
932 if (preg_match(
"/(\d{2}):(\d{2}):(\d{2})/", (
string) $processing_time, $matches)) {
934 return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
942 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTimeEnabled();
947 return $this->
getMainSettings()->getTestBehaviourSettings()->getResetProcessingTime();
952 return $this->
getMainSettings()->getAccessSettings()->getStartTimeEnabled();
957 $start_time = $this->
getMainSettings()->getAccessSettings()->getStartTime();
958 return $start_time !==
null ? $start_time->getTimestamp() : 0;
963 return $this->
getMainSettings()->getAccessSettings()->getEndTimeEnabled();
968 $end_time = $this->
getMainSettings()->getAccessSettings()->getEndTime();
969 return $end_time !==
null ? $end_time->getTimestamp() : 0;
974 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode();
979 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode() === self::REDIRECT_KIOSK;
984 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode() === self::REDIRECT_NONE;
989 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionUrl() ??
'';
994 return $this->
getMainSettings()->getAccessSettings()->getPasswordEnabled();
1022 $participant_data->load($this->test_id);
1024 $question->removeAllExistingSolutions();
1031 $participant_data->getActiveIds(),
1038 $question->delete($question_id);
1047 if ($this->
logger->isLoggingEnabled()) {
1048 $this->
logger->logTestAdministrationInteraction(
1049 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1051 $this->
user->getId(),
1052 TestAdministrationInteractionTypes::QUESTION_REMOVED_IN_CORRECTIONS,
1054 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question->getTitleForHTMLOutput(),
1055 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $question->getQuestion(),
1056 AdditionalInformationGenerator::KEY_QUESTION_ID => $question->getId(),
1057 AdditionalInformationGenerator::KEY_QUESTION_TYPE => $question->getQuestionType()
1075 $this->questionrepository
1078 foreach ($active_ids as $active_id) {
1080 $passSelector->setActiveId($active_id);
1082 foreach ($passSelector->getExistingPasses() as $pass) {
1083 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $pass);
1086 $test_sequence->removeQuestion($question_id, $reindexed_sequence_position_map);
1097 foreach ($question_ids as $question_id) {
1107 $question = self::_instanciateQuestion($question_id);
1108 $question_title = $question->getTitleForHTMLOutput();
1109 $question->delete($question_id);
1110 if ($this->
logger->isLoggingEnabled()) {
1111 $this->
logger->logTestAdministrationInteraction(
1112 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1114 $this->
user->getId(),
1115 TestAdministrationInteractionTypes::QUESTION_REMOVED,
1117 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question_title
1123 $this->
logger->error($e->getMessage());
1124 $this->
logger->error($e->getTraceAsString());
1141 $participantData->setUserIdsFilter($user_ids);
1142 $participantData->load($this->
getTestId());
1147 if ($this->
logger->isLoggingEnabled()) {
1148 $this->
logger->logTestAdministrationInteraction(
1149 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1151 $this->
user->getId(),
1152 TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
1154 AdditionalInformationGenerator::KEY_USERS => $participantData->getUserIds()
1170 $this->participant_repository->removeExtraTimeByUserId($this->
getTestId(), $user_ids);
1173 if ($participant_data->
getUserIds() !== []) {
1176 if ($test_lp instanceof
ilTestLP) {
1177 $test_lp->setTestObject($this);
1178 $test_lp->resetLPDataForUserIds($participant_data->
getUserIds(),
false);
1181 $this->participant_repository->removeExtraTimeByUserId($this->
getTestId(), $participant_data->
getUserIds());
1191 $this->participant_repository->removeExtraTimeByUserId($this->
getTestId(), $user_ids);
1194 if ($this->
logger->isLoggingEnabled()) {
1195 $this->
logger->logTestAdministrationInteraction(
1196 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1198 $this->
user->getId(),
1199 TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
1201 AdditionalInformationGenerator::KEY_USERS => $participant_data->
getUserIds(),
1212 $participantData->setUserIdsFilter($user_ids);
1213 $participantData->load($this->
getTestId());
1215 $in_user_ids = $this->db->in(
'usr_id', $participantData->getUserIds(),
false,
'integer');
1216 $this->db->manipulateF(
1217 "DELETE FROM usr_pref WHERE {$in_user_ids} AND keyword = %s",
1222 if ($participantData->getActiveIds() !== []) {
1229 $in_active_ids = $this->db->in(
'active_fi', $active_ids,
false,
'integer');
1231 $this->db->manipulate(
"DELETE FROM tst_solutions WHERE {$in_active_ids}");
1232 $this->db->manipulate(
"DELETE FROM tst_qst_solved WHERE {$in_active_ids}");
1233 $this->db->manipulate(
"DELETE FROM tst_test_result WHERE {$in_active_ids}");
1234 $this->db->manipulate(
"DELETE FROM tst_pass_result WHERE {$in_active_ids}");
1235 $this->db->manipulate(
"DELETE FROM tst_result_cache WHERE {$in_active_ids}");
1236 $this->db->manipulate(
"DELETE FROM tst_sequence WHERE {$in_active_ids}");
1237 $this->db->manipulate(
"DELETE FROM tst_times WHERE {$in_active_ids}");
1238 $this->db->manipulate(
1240 .
' WHERE ' . $this->db->in(
'active_id', $active_ids,
false,
'integer')
1244 $this->db->manipulate(
"DELETE FROM tst_test_rnd_qst WHERE {$in_active_ids}");
1247 foreach ($active_ids as $active_id) {
1262 $IN_activeIds = $this->db->in(
'active_id', $active_ids,
false,
'integer');
1263 $this->db->manipulate(
"DELETE FROM tst_active WHERE $IN_activeIds");
1276 $result = $this->db->queryF(
1277 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1278 [
'integer',
'integer'],
1281 $data = $this->db->fetchObject($result);
1282 if (
$data->sequence > 1) {
1284 $result = $this->db->queryF(
1285 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1286 [
'integer',
'integer'],
1289 $data_previous = $this->db->fetchObject($result);
1291 $this->db->manipulateF(
1292 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1293 [
'integer',
'integer'],
1294 [
$data->sequence, $data_previous->test_question_id]
1297 $this->db->manipulateF(
1298 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1299 [
'integer',
'integer'],
1300 [
$data->sequence - 1,
$data->test_question_id]
1315 $current_question_result = $this->db->queryF(
1316 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1317 [
'integer',
'integer'],
1320 $current_question_data = $this->db->fetchObject($current_question_result);
1321 $next_question_result = $this->db->queryF(
1322 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1323 [
'integer',
'integer'],
1324 [$this->
getTestId(), $current_question_data->sequence + 1]
1326 if ($this->db->numRows($next_question_result) === 1) {
1328 $next_question_data = $this->db->fetchObject($next_question_result);
1330 $this->db->manipulateF(
1331 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1332 [
'integer',
'integer'],
1333 [$current_question_data->sequence, $next_question_data->test_question_id]
1336 $this->db->manipulateF(
1337 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1338 [
'integer',
'integer'],
1339 [$current_question_data->sequence + 1, $current_question_data->test_question_id]
1354 $duplicate_id = $question->duplicate(
true,
'',
'', -1, $this->
getId());
1355 return $duplicate_id;
1361 $duplicate_id = $question_id;
1367 $result = $this->db->queryF(
1368 "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
1374 if ($result->numRows() == 1) {
1375 $data = $this->db->fetchObject($result);
1376 $sequence =
$data->seq + 1;
1379 $next_id = $this->db->nextId(
'tst_test_question');
1380 $this->db->manipulateF(
1381 "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
1382 [
'integer',
'integer',
'integer',
'integer',
'integer'],
1383 [$next_id, $this->
getTestId(), $duplicate_id, $sequence, time()]
1386 $this->db->manipulateF(
1387 "DELETE FROM tst_active WHERE test_fi = %s",
1392 $this->
saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
1394 if ($this->
logger->isLoggingEnabled()) {
1395 $this->
logger->logTestAdministrationInteraction(
1396 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1398 $this->
user->getId(),
1399 TestAdministrationInteractionTypes::QUESTION_ADDED,
1401 AdditionalInformationGenerator::KEY_QUESTION_ID => $question_id
1403 ->toLog($this->
logger->getAdditionalInformationGenerator())
1408 return $duplicate_id;
1415 $result = $this->db->queryF(
1416 'SELECT qpl_questions.title FROM tst_test_question, qpl_questions ' 1417 .
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ' 1418 .
'ORDER BY tst_test_question.sequence',
1422 while ($row = $this->db->fetchAssoc($result)) {
1423 array_push($titles, $row[
'title']);
1440 $result = $this->db->queryF(
1441 'SELECT qpl_questions.title, qpl_questions.question_id ' 1442 .
'FROM tst_test_question, qpl_questions ' 1443 .
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ' 1444 .
'ORDER BY tst_test_question.sequence',
1448 while ($row = $this->db->fetchAssoc($result)) {
1449 $titles[$row[
'question_id']] = $row[
"title"];
1474 return $this->
lng->txt(
"ass_question") .
' ' . $nr;
1476 return $this->
lng->txt(
"ass_question");
1480 $txt = $this->
lng->txt(
"ass_question") .
' ' . $nr;
1482 $txt = $this->
lng->txt(
"ass_question");
1484 if ($points !=
'') {
1485 $lngv = $this->
lng->txt(
'points');
1487 $lngv = $this->
lng->txt(
'point');
1489 $txt .=
' - ' . $points .
' ' . $lngv;
1495 return $this->
lng->txt(
"ass_question");
1509 $result = $this->db->queryF(
1510 "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",
1514 $row = $this->db->fetchObject($result);
1526 $existing_questions = [];
1529 if (is_null($pass)) {
1532 $result = $this->db->queryF(
1533 "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",
1534 [
'integer',
'integer'],
1538 $result = $this->db->queryF(
1539 "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",
1544 while (
$data = $this->db->fetchObject($result)) {
1549 array_push($existing_questions,
$data->original_id);
1551 return $existing_questions;
1563 if ($question_id < 1) {
1566 $result = $this->db->queryF(
1567 "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",
1571 if ($result->numRows() == 1) {
1572 $data = $this->db->fetchObject($result);
1573 return $data->type_tag;
1587 $next_id = $this->db->nextId(
'tst_times');
1588 $affectedRows = $this->db->manipulateF(
1589 "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
1590 [
'integer',
'integer',
'timestamp',
'timestamp',
'integer',
'integer'],
1591 [$next_id, $active_id, date(
"Y-m-d H:i:s"), date(
"Y-m-d H:i:s"), $pass, time()]
1604 $affectedRows = $this->db->manipulateF(
1605 "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
1606 [
'timestamp',
'integer',
'integer'],
1607 [date(
'Y-m-d H:i:s'), time(), $times_id]
1619 if (is_null($pass)) {
1620 $result = $this->db->queryF(
1621 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1622 [
'integer',
'integer'],
1626 $result = $this->db->queryF(
1627 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1628 [
'integer',
'integer'],
1633 while ($row = $this->db->fetchAssoc($result)) {
1634 array_push($result_array, $row[
"question_fi"]);
1636 return $result_array;
1650 return ((($currentpass > 0) && ($num == 0)) || $this->
isTestFinished($active_id)) ? true :
false;
1663 if ($active_id ===
null) {
1667 if (count($this->questions) === 0) {
1670 if (is_null($pass)) {
1671 $pass = self::_getPass($active_id);
1673 $result = $this->db->queryF(
1674 "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'),
1675 [
'integer',
'integer'],
1679 if (count($this->questions) === 0) {
1682 $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'));
1685 while ($row = $this->db->fetchAssoc($result)) {
1686 $result_array[$row[
"question_id"]] = $row;
1688 return $result_array;
1706 if (is_array($tst_access_code) &&
1708 isset($tst_access_code[$this->
getTestId()]) &&
1709 $tst_access_code[$this->
getTestId()] !==
'') {
1710 $result = $this->db->queryF(
1711 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1712 [
'integer',
'integer',
'text'],
1715 } elseif ((
string) $anonymous_id !==
'') {
1716 $result = $this->db->queryF(
1717 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1718 [
'integer',
'integer',
'text'],
1719 [
$user_id, $this->test_id, $anonymous_id]
1725 $result = $this->db->queryF(
1726 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s',
1727 [
'integer',
'integer'],
1732 if ($result->numRows()) {
1733 $row = $this->db->fetchAssoc($result);
1734 return (
int) $row[
'active_id'];
1743 $ilDB = $DIC[
'ilDB'];
1744 $ilUser = $DIC[
'ilUser'];
1752 $result =
$ilDB->queryF(
1753 "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
1754 [
'integer',
'integer'],
1757 if ($result->numRows()) {
1758 $row =
$ilDB->fetchAssoc($result);
1759 return $row[
"active_id"];
1773 $keys = array_keys($array);
1776 foreach ($keys as $key) {
1777 $result[$key] = $array[$key];
1791 bool $ordered_sequence =
false,
1792 bool $consider_hidden_questions =
true,
1793 bool $consider_optional_questions =
true 1797 if ($pass ===
null) {
1802 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $pass);
1804 $test_sequence->setConsiderHiddenQuestionsEnabled($consider_hidden_questions);
1805 $test_sequence->setConsiderOptionalQuestionsEnabled($consider_optional_questions);
1810 if ($ordered_sequence) {
1820 tst_test_result.question_fi, 1821 tst_test_result.points reached, 1822 tst_test_result.hint_count requested_hints, 1823 tst_test_result.hint_points hint_points, 1824 tst_test_result.answered answered, 1825 tst_manual_fb.finalized_evaluation finalized_evaluation 1827 FROM tst_test_result 1829 LEFT JOIN tst_solutions 1830 ON tst_solutions.active_fi = tst_test_result.active_fi 1831 AND tst_solutions.question_fi = tst_test_result.question_fi 1833 LEFT JOIN tst_manual_fb 1834 ON tst_test_result.active_fi = tst_manual_fb.active_fi 1835 AND tst_test_result.question_fi = tst_manual_fb.question_fi 1837 WHERE tst_test_result.active_fi = %s 1838 AND tst_test_result.pass = %s 1841 $solutionresult = $this->db->queryF(
1843 [
'integer',
'integer'],
1847 while ($row = $this->db->fetchAssoc($solutionresult)) {
1848 $arr_results[ $row[
'question_fi'] ] = $row;
1851 $num_worked_through = count($arr_results);
1853 $IN_question_ids = $this->db->in(
'qpl_questions.question_id', $sequence,
false,
'integer');
1856 SELECT qpl_questions.*, 1857 qpl_qst_type.type_tag, 1858 qpl_sol_sug.question_fi has_sug_sol 1863 LEFT JOIN qpl_sol_sug 1864 ON qpl_sol_sug.question_fi = qpl_questions.question_id 1866 WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi 1867 AND $IN_question_ids 1870 $result = $this->db->query($query);
1873 while ($row = $this->db->fetchAssoc($result)) {
1874 if (!isset($arr_results[ $row[
'question_id'] ])) {
1875 $percentvalue = 0.0;
1878 $row[
'points'] ? $arr_results[$row[
'question_id']][
'reached'] / $row[
'points'] : 0
1881 if ($percentvalue < 0) {
1882 $percentvalue = 0.0;
1888 "max" => round($row[
'points'], 2),
1889 "reached" => round($arr_results[$row[
'question_id']][
'reached'] ?? 0, 2),
1890 'requested_hints' => $arr_results[$row[
'question_id']][
'requested_hints'] ?? 0,
1891 'hint_points' => $arr_results[$row[
'question_id']][
'hint_points'] ?? 0,
1892 "percent" => sprintf(
"%2.2f ", ($percentvalue) * 100) .
"%",
1894 "type" => $row[
"type_tag"],
1895 "qid" => $row[
'question_id'],
1896 "original_id" => $row[
"original_id"],
1897 "workedthrough" => isset($arr_results[$row[
'question_id']]) ? 1 : 0,
1898 'answered' => $arr_results[$row[
'question_id']][
'answered'] ?? 0,
1899 'finalized_evaluation' => $arr_results[$row[
'question_id']][
'finalized_evaluation'] ?? 0,
1902 $unordered[ $row[
'question_id'] ] =
$data;
1906 $numQuestionsTotal = count($unordered);
1910 $pass_requested_hints = 0;
1911 $pass_hint_points = 0;
1915 foreach ($sequence as $qid) {
1918 $pass_max += round($unordered[$qid][
'max'], 2);
1919 $pass_reached += round($unordered[$qid][
'reached'], 2);
1920 $pass_requested_hints += $unordered[$qid][
'requested_hints'];
1921 $pass_hint_points += $unordered[$qid][
'hint_points'];
1922 $found[] = $unordered[$qid];
1928 if (
$results[
'reached_points'] < 0) {
1932 if ($pass_reached < 0) {
1937 $found[
'pass'][
'total_max_points'] = $pass_max;
1938 $found[
'pass'][
'total_reached_points'] = $pass_reached;
1939 $found[
'pass'][
'total_requested_hints'] = $pass_requested_hints;
1940 $found[
'pass'][
'total_hint_points'] = $pass_hint_points;
1941 $found[
'pass'][
'percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
1942 $found[
'pass'][
'num_workedthrough'] = $num_worked_through;
1943 $found[
'pass'][
'num_questions_total'] = $numQuestionsTotal;
1945 $found[
"test"][
"total_max_points"] =
$results[
'max_points'];
1946 $found[
"test"][
"total_reached_points"] =
$results[
'reached_points'];
1947 $found[
"test"][
"total_requested_hints"] =
$results[
'hint_count'];
1948 $found[
"test"][
"total_hint_points"] =
$results[
'hint_points'];
1949 $found[
"test"][
"result_pass"] =
$results[
'pass'];
1950 $found[
'test'][
'result_tstamp'] =
$results[
'tstamp'];
1952 if ((!$found[
'pass'][
'total_reached_points']) or (!$found[
'pass'][
'total_max_points'])) {
1955 $percentage = ($found[
'pass'][
'total_reached_points'] / $found[
'pass'][
'total_max_points']) * 100.0;
1957 if ($percentage < 0) {
1962 $found[
"test"][
"passed"] =
$results[
'passed'];
1975 $result = $this->db->queryF(
1976 'SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s',
1980 $row = $this->db->fetchAssoc($result);
1981 return $row[
'total'];
1992 $result = $this->db->queryF(
1993 "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",
1994 [
'integer',
'integer'],
1998 while ($row = $this->db->fetchAssoc($result)) {
1999 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2008 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2017 $time += ($epoch_2 - $epoch_1);
2042 $result = $this->db->queryF(
2043 "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",
2049 while ($row = $this->db->fetchAssoc($result)) {
2050 if (!array_key_exists($row[
"active_fi"], $times)) {
2051 $times[$row[
"active_fi"]] = 0;
2053 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2062 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2071 $times[$row[
"active_fi"]] += ($epoch_2 - $epoch_1);
2084 $result = $this->db->queryF(
2085 "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",
2086 [
'integer',
'integer'],
2090 while ($row = $this->db->fetchAssoc($result)) {
2091 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2100 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2109 $time += ($epoch_2 - $epoch_1);
2116 $result = $this->db->queryF(
2117 "SELECT * FROM tst_times WHERE active_fi = %s AND pass = %s ORDER BY started",
2118 [
'integer',
'integer'],
2122 while ($row = $this->db->fetchAssoc($result)) {
2123 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2132 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2141 $time += ($epoch_2 - $epoch_1);
2153 $result = $this->db->queryF(
2154 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
2161 while ($row = $this->db->fetchObject($result)) {
2162 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2171 if (!$first_visit) {
2172 $first_visit = $epoch_1;
2174 if ($epoch_1 < $first_visit) {
2175 $first_visit = $epoch_1;
2177 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2187 $last_visit = $epoch_2;
2189 if ($epoch_2 > $last_visit) {
2190 $last_visit = $epoch_2;
2192 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2195 foreach ($times as $key => $value) {
2196 $max_time += $value;
2198 if ((!$test_result[
"test"][
"total_reached_points"]) or (!$test_result[
"test"][
"total_max_points"])) {
2201 $percentage = ($test_result[
"test"][
"total_reached_points"] / $test_result[
"test"][
"total_max_points"]) * 100.0;
2202 if ($percentage < 0) {
2206 $mark_obj = $this->
getMarkSchema()->getMatchingMark($percentage);
2207 $first_date = getdate($first_visit);
2208 $last_date = getdate($last_visit);
2209 $qworkedthrough = 0;
2210 foreach ($test_result as $key => $value) {
2211 if (preg_match(
"/\d+/", $key)) {
2212 $qworkedthrough += $value[
"workedthrough"];
2215 if (!$qworkedthrough) {
2218 $atimeofwork = $max_time / $qworkedthrough;
2224 if ($mark_obj !==
null) {
2225 $result_mark = $mark_obj->getShortName();
2227 if ($mark_obj->getPassed()) {
2233 $percent_worked_through = 0;
2234 if (count($this->questions)) {
2235 $percent_worked_through = $qworkedthrough / count($this->questions);
2238 "qworkedthrough" => $qworkedthrough,
2239 "qmax" => count($this->questions),
2240 "pworkedthrough" => $percent_worked_through,
2241 "timeofwork" => $max_time,
2242 "atimeofwork" => $atimeofwork,
2243 "firstvisit" => $first_date,
2244 "lastvisit" => $last_date,
2245 "resultspoints" => $test_result[
"test"][
"total_reached_points"],
2246 "maxpoints" => $test_result[
"test"][
"total_max_points"],
2247 "resultsmarks" => $result_mark,
2248 "passed" => $passed,
2249 "distancemedian" =>
"0" 2251 foreach ($test_result as $key => $value) {
2252 if (preg_match(
"/\d+/", $key)) {
2253 $result_array[$key] = $value;
2256 return $result_array;
2268 $totalpoints_array = [];
2270 foreach ($all_users as $active_id => $user_name) {
2272 $reached = $test_result[
"test"][
"total_reached_points"];
2273 $total = $test_result[
"test"][
"total_max_points"];
2274 $percentage = $total != 0 ? $reached / $total : 0;
2275 $mark = $this->
getMarkSchema()->getMatchingMark($percentage * 100.0);
2277 if ($mark !==
null && $mark->getPassed()) {
2278 array_push($totalpoints_array, $test_result[
"test"][
"total_reached_points"]);
2281 return $totalpoints_array;
2291 $result = $this->db->queryF(
2292 "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",
2296 $persons_array = [];
2297 while ($row = $this->db->fetchAssoc($result)) {
2298 $name = $this->
lng->txt(
"anonymous");
2299 $fullname = $this->
lng->txt(
"anonymous");
2302 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2303 $name = $this->
lng->txt(
"deleted_user");
2304 $fullname = $this->
lng->txt(
"deleted_user");
2305 $login = $this->
lng->txt(
"unknown");
2307 $login = $row[
"login"];
2309 $name = $this->
lng->txt(
"anonymous");
2310 $fullname = $this->
lng->txt(
"anonymous");
2312 $name = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2313 $fullname = trim($row[
"title"] .
" " . $row[
"firstname"] .
" " . $row[
"lastname"]);
2317 $persons_array[$row[
"active_id"]] = [
2319 "fullname" => $fullname,
2323 return $persons_array;
2328 $result = $this->db->queryF(
2329 "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),
2333 $persons_array = [];
2334 while ($row = $this->db->fetchAssoc($result)) {
2340 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"anonymous");
2342 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2343 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"deleted_user");
2346 $persons_array[$row[
"active_id"]] = $row[
"lastname"];
2348 $persons_array[$row[
"active_id"]] = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2353 return $persons_array;
2358 $result = $this->db->queryF(
2359 'SELECT tst_active.user_fi, tst_active.active_id, usr_data.login, ' 2360 .
'usr_data.firstname, usr_data.lastname, usr_data.title FROM tst_active ' 2361 .
'LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id ' 2362 .
'WHERE tst_active.test_fi = %s ' 2363 .
'ORDER BY usr_data.lastname ' . strtoupper($name_sort_order),
2367 $persons_array = [];
2368 while ($row = $this->db->fetchAssoc($result)) {
2370 $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
"anonymous")];
2372 if (strlen($row[
'firstname'] . $row[
'lastname'] . $row[
"title"]) == 0) {
2373 $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
'deleted_user')];
2376 $persons_array[$row[
'active_id']] = [
'name' => $row[
'lastname']];
2378 $persons_array[$row[
'active_id']] = [
2379 'name' => trim($row[
'lastname'] .
', ' . $row[
'firstname']
2380 .
' ' . $row[
'title']),
2381 'login' => $row[
'login']
2387 return $persons_array;
2394 $result = $this->db->queryF(
2395 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, ' 2396 .
'tst_test_rnd_qst.pass, qpl_questions.points ' 2397 .
'FROM tst_test_rnd_qst, qpl_questions ' 2398 .
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id ' 2399 .
'AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence',
2404 $result = $this->db->queryF(
2405 'SELECT tst_test_question.sequence, tst_test_question.question_fi, ' 2406 .
'qpl_questions.points ' 2407 .
'FROM tst_test_question, tst_active, qpl_questions ' 2408 .
'WHERE tst_test_question.question_fi = qpl_questions.question_id ' 2409 .
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
2415 if ($result->numRows()) {
2416 while ($row = $this->db->fetchAssoc($result)) {
2417 array_push($qtest, $row);
2427 $result = $this->db->queryF(
2428 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, ' 2429 .
'qpl_questions.points ' 2430 .
'FROM tst_test_rnd_qst, qpl_questions ' 2431 .
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id ' 2432 .
'AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s ' 2433 .
'ORDER BY tst_test_rnd_qst.sequence',
2434 [
'integer',
'integer'],
2438 $result = $this->db->queryF(
2439 'SELECT tst_test_question.sequence, tst_test_question.question_fi, ' 2440 .
'qpl_questions.points ' 2441 .
'FROM tst_test_question, tst_active, qpl_questions ' 2442 .
'WHERE tst_test_question.question_fi = qpl_questions.question_id ' 2443 .
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
2449 if ($result->numRows()) {
2450 while ($row = $this->db->fetchAssoc($result)) {
2451 array_push($qpass, $row);
2472 return $list->getAccessFilteredList(
2473 $this->participant_access_filter->getAccessStatisticsUserFilter($this->getRefId())
2480 ->getEvaluationData();
2487 switch ($question_set_type) {
2489 $res = $this->db->queryF(
2491 SELECT tst_test_rnd_qst.pass, 2492 COUNT(tst_test_rnd_qst.question_fi) qcount, 2493 SUM(qpl_questions.points) qsum 2495 FROM tst_test_rnd_qst, 2498 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id 2499 AND tst_test_rnd_qst.active_fi = %s 2502 GROUP BY tst_test_rnd_qst.active_fi, 2503 tst_test_rnd_qst.pass 2505 [
'integer',
'integer'],
2511 $res = $this->db->queryF(
2513 SELECT COUNT(tst_test_question.question_fi) qcount, 2514 SUM(qpl_questions.points) qsum 2516 FROM tst_test_question, 2520 WHERE tst_test_question.question_fi = qpl_questions.question_id 2521 AND tst_test_question.test_fi = tst_active.test_fi 2522 AND tst_active.active_id = %s 2524 GROUP BY tst_test_question.test_fi 2532 throw new ilTestException(
"not supported question set type: $question_set_type");
2535 $row = $this->db->fetchAssoc(
$res);
2537 if (is_array($row)) {
2538 return [
"count" => $row[
"qcount"],
"points" => $row[
"qsum"]];
2541 return [
"count" => 0,
"points" => 0];
2547 $data->setFilter($filterby, $filtertext);
2567 if ($user_id ===
null 2568 || $firstname . $lastname ===
'') {
2569 return $this->
lng->txt(
'deleted_user');
2573 return $this->
lng->txt(
'anonymous');
2580 return trim($lastname .
', ' . $firstname);
2585 $query =
"SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi";
2587 if ($active_ids_to_filter !==
null && $active_ids_to_filter !== []) {
2588 $query .=
" AND " . $this->db->in(
'active_id', $active_ids_to_filter,
false,
'integer');
2591 $result = $this->db->queryF($query, [
'integer'], [$this->
getTestId()]);
2593 while ($row = $this->db->fetchObject($result)) {
2594 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2603 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2612 if (isset($times[$row->active_fi])) {
2613 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2615 $times[$row->active_fi] = ($epoch_2 - $epoch_1);
2620 foreach ($times as $value) {
2621 $max_time += $value;
2624 if ($counter === 0) {
2627 return (
int) round($max_time / $counter);
2637 bool $use_object_id =
false,
2638 ?
bool $equal_points =
false,
2639 bool $could_be_offline =
false,
2640 bool $show_path =
false,
2641 bool $with_questioncount =
false,
2642 string $permission =
'read' 2646 $equal_points ??
false,
2649 $with_questioncount,
2691 if ((!$question_type) and ($question_id > 0)) {
2695 if (!strlen($question_type)) {
2699 if ($question_id > 0) {
2700 $question_gui = assQuestion::instantiateQuestionGUI($question_id);
2702 $question_type_gui = $question_type .
'GUI';
2703 $question_gui =
new $question_type_gui();
2706 return $question_gui;
2717 if (strcmp((
string) $question_id,
"") !== 0) {
2728 public function moveQuestions(array $move_questions,
int $target_index,
int $insert_mode): void
2730 $this->questions = array_values($this->questions);
2731 $array_pos = array_search($target_index, $this->questions);
2732 if ($insert_mode == 0) {
2733 $part1 = array_slice($this->questions, 0, $array_pos);
2734 $part2 = array_slice($this->questions, $array_pos);
2735 } elseif ($insert_mode == 1) {
2736 $part1 = array_slice($this->questions, 0, $array_pos + 1);
2737 $part2 = array_slice($this->questions, $array_pos + 1);
2739 foreach ($move_questions as $question_id) {
2740 if (!(array_search($question_id, $part1) ===
false)) {
2741 unset($part1[array_search($question_id, $part1)]);
2743 if (!(array_search($question_id, $part2) ===
false)) {
2744 unset($part2[array_search($question_id, $part2)]);
2747 $part1 = array_values($part1);
2748 $part2 = array_values($part2);
2749 $new_array = array_values(array_merge($part1, $move_questions, $part2));
2750 $this->questions = [];
2752 foreach ($new_array as $question_id) {
2753 $this->questions[$counter] = $question_id;
2758 if ($this->
logger->isLoggingEnabled()) {
2759 $this->
logger->logTestAdministrationInteraction(
2760 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
2762 $this->
user->getId(),
2763 TestAdministrationInteractionTypes::QUESTION_MOVED,
2818 if (count($available_pools)) {
2819 $available =
" AND " . $this->db->in(
'qpl_questions.obj_fi', $available_pools,
false,
'integer');
2823 if ($completeonly) {
2824 $available .=
" AND qpl_questions.complete = " . $this->db->quote(
"1",
'text');
2828 if (is_array($arr_filter)) {
2829 if (array_key_exists(
'title', $arr_filter) && strlen($arr_filter[
'title'])) {
2830 $where .=
" AND " . $this->db->like(
'qpl_questions.title',
'text',
"%%" . $arr_filter[
'title'] .
"%%");
2832 if (array_key_exists(
'description', $arr_filter) && strlen($arr_filter[
'description'])) {
2833 $where .=
" AND " . $this->db->like(
'qpl_questions.description',
'text',
"%%" . $arr_filter[
'description'] .
"%%");
2835 if (array_key_exists(
'author', $arr_filter) && strlen($arr_filter[
'author'])) {
2836 $where .=
" AND " . $this->db->like(
'qpl_questions.author',
'text',
"%%" . $arr_filter[
'author'] .
"%%");
2838 if (array_key_exists(
'type', $arr_filter) && strlen($arr_filter[
'type'])) {
2839 $where .=
" AND qpl_qst_type.type_tag = " . $this->db->quote($arr_filter[
'type'],
'text');
2841 if (array_key_exists(
'qpl', $arr_filter) && strlen($arr_filter[
'qpl'])) {
2842 $where .=
" AND " . $this->db->like(
'object_data.title',
'text',
"%%" . $arr_filter[
'qpl'] .
"%%");
2847 $original_clause =
" qpl_questions.original_id IS NULL";
2848 if (count($original_ids)) {
2849 $original_clause =
" qpl_questions.original_id IS NULL AND " . $this->db->in(
'qpl_questions.question_id', $original_ids,
true,
'integer');
2852 $query_result = $this->db->query(
" 2853 SELECT qpl_questions.*, qpl_questions.tstamp, 2854 qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name, 2855 object_data.title parent_title 2856 FROM qpl_questions, qpl_qst_type, object_data 2857 WHERE $original_clause $available 2858 AND object_data.obj_id = qpl_questions.obj_fi 2859 AND qpl_questions.tstamp > 0 2860 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id 2865 if ($query_result->numRows()) {
2866 while ($row = $this->db->fetchAssoc($query_result)) {
2869 if (!$row[
'plugin']) {
2870 $row[
'ttype' ] = $this->
lng->txt($row[
"type_tag" ]);
2876 $plugin = $this->component_repository->getPluginByName($row[
'plugin_name']);
2881 $pl = $this->component_factory->getPlugin(
$plugin->getId());
2882 $row[
'ttype' ] = $pl->getQuestionTypeTranslation();
2914 $introduction_settings = $introduction_settings->withIntroductionEnabled(
false);
2915 foreach ($assessment->objectives as
$objectives) {
2916 foreach ($objectives->materials as $material) {
2918 $introduction_settings,
2930 $finishing_settings,
2946 foreach ($assessment->qtimetadata as
$metadata) {
2947 switch ($metadata[
"label"]) {
2948 case "solution_details":
2949 $result_details_settings = $result_details_settings->withShowPassDetails((
bool) $metadata[
"entry"]);
2951 case "show_solution_list_comparison":
2952 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
2954 case "print_bs_with_res":
2955 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
2961 $test_behaviour_settings = $test_behaviour_settings->withNumberOfTries((
int) $metadata[
"entry"]);
2963 case 'block_after_passed':
2964 $test_behaviour_settings = $test_behaviour_settings->withBlockAfterPassedEnabled((
bool) $metadata[
'entry']);
2966 case "pass_waiting":
2967 $test_behaviour_settings = $test_behaviour_settings->withPassWaiting($metadata[
"entry"]);
2970 $test_behaviour_settings = $test_behaviour_settings->withKioskMode((
int) $metadata[
"entry"]);
2972 case 'show_introduction':
2973 $introduction_settings = $introduction_settings->withIntroductionEnabled((
bool) $metadata[
'entry']);
2975 case "showfinalstatement":
2976 case 'show_concluding_remarks':
2977 $finishing_settings = $finishing_settings->withConcludingRemarksEnabled((
bool) $metadata[
"entry"]);
2979 case "highscore_enabled":
2980 $gamification_settings = $gamification_settings->withHighscoreEnabled((
bool) $metadata[
"entry"]);
2983 case "highscore_anon":
2984 $gamification_settings = $gamification_settings->withHighscoreAnon((
bool) $metadata[
"entry"]);
2987 case "highscore_achieved_ts":
2988 $gamification_settings = $gamification_settings->withHighscoreAchievedTS((
bool) $metadata[
"entry"]);
2991 case "highscore_score":
2992 $gamification_settings = $gamification_settings->withHighscoreScore((
bool) $metadata[
"entry"]);
2995 case "highscore_percentage":
2996 $gamification_settings = $gamification_settings->withHighscorePercentage((
bool) $metadata[
"entry"]);
2999 case "highscore_hints":
3000 $gamification_settings = $gamification_settings->withHighscoreHints((
bool) $metadata[
"entry"]);
3003 case "highscore_wtime":
3004 $gamification_settings = $gamification_settings->withHighscoreWTime((
bool) $metadata[
"entry"]);
3007 case "highscore_own_table":
3008 $gamification_settings = $gamification_settings->withHighscoreOwnTable((
bool) $metadata[
"entry"]);
3011 case "highscore_top_table":
3012 $gamification_settings = $gamification_settings->withHighscoreTopTable((
bool) $metadata[
"entry"]);
3015 case "highscore_top_num":
3016 $gamification_settings = $gamification_settings->withHighscoreTopNum((
int) $metadata[
"entry"]);
3018 case "use_previous_answers":
3019 $participant_functionality_settings = $participant_functionality_settings->withUsePreviousAnswerAllowed((
bool) $metadata[
"entry"]);
3021 case "title_output":
3022 $question_behaviour_settings = $question_behaviour_settings->withQuestionTitleOutputMode((
int) $metadata[
"entry"]);
3024 case "question_set_type":
3025 $general_settings = $general_settings->withQuestionSetType($metadata[
"entry"]);
3028 $general_settings = $general_settings->withAnonymity((
bool) $metadata[
"entry"]);
3030 case "results_presentation":
3031 $result_details_settings = $result_details_settings->withResultsPresentation((
int) $metadata[
"entry"]);
3033 case "reset_processing_time":
3034 $test_behaviour_settings = $test_behaviour_settings->withResetProcessingTime((
bool) $metadata[
"entry"]);
3036 case "answer_feedback_points":
3037 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackPointsEnabled((
bool) $metadata[
"entry"]);
3039 case "answer_feedback":
3040 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackGenericEnabled((
bool) $metadata[
"entry"]);
3042 case 'instant_feedback_specific':
3043 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSpecificEnabled((
bool) $metadata[
'entry']);
3045 case "instant_verification":
3046 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSolutionEnabled((
bool) $metadata[
"entry"]);
3048 case "force_instant_feedback":
3049 $question_behaviour_settings = $question_behaviour_settings->withForceInstantFeedbackOnNextQuestion((
bool) $metadata[
"entry"]);
3051 case "follow_qst_answer_fixation":
3052 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnNextQuestionEnabled((
bool) $metadata[
"entry"]);
3054 case "instant_feedback_answer_fixation":
3055 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnInstantFeedbackEnabled((
bool) $metadata[
"entry"]);
3058 case "suspend_test_allowed":
3059 $participant_functionality_settings = $participant_functionality_settings->withSuspendTestAllowed((
bool) $metadata[
"entry"]);
3061 case "sequence_settings":
3062 $participant_functionality_settings = $participant_functionality_settings->withPostponedQuestionsMoveToEnd((
bool) $metadata[
"entry"]);
3065 $participant_functionality_settings = $participant_functionality_settings->withQuestionMarkingEnabled((
bool) $metadata[
"entry"]);
3067 case "fixed_participants":
3068 $access_settings = $access_settings->withFixedParticipants((
bool) $metadata[
"entry"]);
3070 case "score_reporting":
3071 if ($metadata[
'entry'] !==
null) {
3072 $result_summary_settings = $result_summary_settings->withScoreReporting(
3073 ScoreReportingTypes::tryFrom((
int) $metadata[
'entry']) ?? ScoreReportingTypes::SCORE_REPORTING_DISABLED
3077 case "shuffle_questions":
3078 $question_behaviour_settings = $question_behaviour_settings->withShuffleQuestions((
bool) $metadata[
"entry"]);
3080 case "count_system":
3081 $scoring_settings = $scoring_settings->withCountSystem((
int) $metadata[
"entry"]);
3083 case "mailnotification":
3084 $finishing_settings = $finishing_settings->withMailNotificationContentType((
int) $metadata[
"entry"]);
3087 $finishing_settings = $finishing_settings->withAlwaysSendMailNotification((
bool) $metadata[
"entry"]);
3089 case "exportsettings":
3090 $result_details_settings = $result_details_settings->withExportSettings((
int) $metadata[
"entry"]);
3092 case "score_cutting":
3093 $scoring_settings = $scoring_settings->withScoreCutting((
int) $metadata[
"entry"]);
3096 $access_settings = $access_settings->withPasswordEnabled(
3097 $metadata[
"entry"] !==
null && $metadata[
"entry"] !==
'' 3098 )->withPassword($metadata[
"entry"]);
3100 case 'ip_range_from':
3101 if ($metadata[
'entry'] !==
'') {
3102 $access_settings = $access_settings->withIpRangeFrom($metadata[
'entry']);
3106 if ($metadata[
'entry'] !==
'') {
3107 $access_settings = $access_settings->withIpRangeTo($metadata[
'entry']);
3110 case "pass_scoring":
3111 $scoring_settings = $scoring_settings->withPassScoring((
int) $metadata[
"entry"]);
3113 case 'pass_deletion_allowed':
3114 $result_summary_settings = $result_summary_settings->withPassDeletionAllowed((
bool) $metadata[
"entry"]);
3116 case "usr_pass_overview_mode":
3117 $participant_functionality_settings = $participant_functionality_settings->withUsrPassOverviewMode((
int) $metadata[
"entry"]);
3119 case "question_list":
3120 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
"entry"]);
3123 case "reporting_date":
3125 if ($reporting_date !==
null) {
3126 $result_summary_settings = $result_summary_settings->withReportingDate($reporting_date);
3129 case 'enable_processing_time':
3130 $test_behaviour_settings = $test_behaviour_settings->withProcessingTimeEnabled((
bool) $metadata[
'entry']);
3132 case "processing_time":
3133 $test_behaviour_settings = $test_behaviour_settings->withProcessingTime($metadata[
'entry']);
3135 case "starting_time":
3137 if ($starting_time !==
null) {
3138 $access_settings = $access_settings->withStartTime($starting_time)
3139 ->withStartTimeEnabled(
true);
3144 if ($ending_time !==
null) {
3145 $access_settings = $access_settings->withEndTime($ending_time)
3146 ->withStartTimeEnabled(
true);
3149 case "enable_examview":
3150 $finishing_settings = $finishing_settings->withShowAnswerOverview((
bool) $metadata[
"entry"]);
3152 case 'redirection_mode':
3153 $finishing_settings = $finishing_settings->withRedirectionMode((
int) $metadata[
'entry']);
3155 case 'redirection_url':
3156 $finishing_settings = $finishing_settings->withRedirectionUrl($metadata[
'entry']);
3158 case 'examid_in_test_pass':
3159 $test_behaviour_settings = $test_behaviour_settings->withExamIdInTestAttemptEnabled((
bool) $metadata[
'entry']);
3161 case 'examid_in_test_res':
3162 $result_details_settings = $result_details_settings->withShowExamIdInTestResults((
bool) $metadata[
"entry"]);
3164 case 'skill_service':
3165 $additional_settings = $additional_settings->withSkillsServiceEnabled((
bool) $metadata[
'entry']);
3167 case 'show_grading_status':
3168 $result_summary_settings = $result_summary_settings->withShowGradingStatusEnabled((
bool) $metadata[
"entry"]);
3170 case 'show_grading_mark':
3171 $result_summary_settings = $result_summary_settings->withShowGradingMarkEnabled((
bool) $metadata[
"entry"]);
3173 case 'activation_limited':
3176 case 'activation_start_time':
3179 case 'activation_end_time':
3182 case 'activation_visibility':
3186 $question_behaviour_settings = $question_behaviour_settings->withAutosaveEnabled((
bool) $metadata[
'entry']);
3188 case 'autosave_ival':
3189 $question_behaviour_settings = $question_behaviour_settings->withAutosaveInterval((
int) $metadata[
'entry']);
3191 case 'offer_question_hints':
3192 $question_behaviour_settings = $question_behaviour_settings->withQuestionHintsEnabled((
bool) $metadata[
'entry']);
3194 case 'show_summary':
3195 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled(($metadata[
'entry'] & 1) > 0)
3196 ->withUsrPassOverviewMode((
int) $metadata[
'entry']);
3198 if (preg_match(
"/mark_step_\d+/", $metadata[
"label"])) {
3199 $xmlmark = $metadata[
"entry"];
3200 preg_match(
"/<short>(.*?)<\/short>/", $xmlmark, $matches);
3201 $mark_short = $matches[1];
3202 preg_match(
"/<official>(.*?)<\/official>/", $xmlmark, $matches);
3203 $mark_official = $matches[1];
3204 preg_match(
"/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
3205 $mark_percentage = (float) $matches[1];
3206 preg_match(
"/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
3207 $mark_passed = (bool) $matches[1];
3208 $mark_steps[] =
new Mark($mark_short, $mark_official, $mark_percentage, $mark_passed);
3211 $this->mark_schema = $this->
getMarkSchema()->withMarkSteps($mark_steps);
3219 $main_settings = $main_settings
3221 ->withIntroductionSettings($introduction_settings)
3222 ->withAccessSettings($access_settings)
3223 ->withParticipantFunctionalitySettings($participant_functionality_settings)
3224 ->withTestBehaviourSettings($test_behaviour_settings)
3225 ->withQuestionBehaviourSettings($question_behaviour_settings)
3226 ->withFinishingSettings($finishing_settings)
3227 ->withAdditionalSettings($additional_settings);
3231 $score_settings = $score_settings
3233 ->withScoringSettings($scoring_settings)
3234 ->withResultDetailsSettings($result_details_settings)
3235 ->withResultSummarySettings($result_summary_settings);
3247 $text = $material[
'text'];
3248 $mobs = $material[
'mobs'];
3249 if (str_starts_with($text,
'<PageObject>')) {
3252 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
3256 $mappings[
'components/ILIAS/File'][
'file'] ?? []
3259 $page_object->setParentId($this->
getId());
3260 $page_object->setXMLContent($text);
3261 $new_page_id = $page_object->createPageWithNextId();
3281 $text = $material[
'text'];
3282 $mobs = $material[
'mobs'];
3283 if (str_starts_with($text,
'<PageObject>')) {
3286 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
3290 $mappings[
'components/ILIAS/File'][
'file'] ?? []
3293 $page_object->setParentId($this->
getId());
3294 $page_object->setXMLContent($text);
3295 $new_page_id = $page_object->createPageWithNextId();
3316 preg_match_all(
'/il_(\d+)_mob_(\d+)/', $text, $matches);
3317 foreach ($matches[0] as $index => $match) {
3318 if (empty($mappings[$matches[2][$index]])) {
3321 $text = str_replace($match,
"il__mob_{$mappings[$matches[2][$index]]}", $text);
3329 preg_match_all(
'/il_(\d+)_file_(\d+)/', $text, $matches);
3330 foreach ($matches[0] as $index => $match) {
3331 if (empty($mappings[$matches[2][$index]])) {
3334 $text = str_replace($match,
"il__file_{$mappings[$matches[2][$index]]}", $text);
3341 foreach ($mobs as $mob) {
3342 $importfile = $importdir . DIRECTORY_SEPARATOR . $mob[
'uri'];
3343 if (file_exists($importfile)) {
3348 'src="' . $mob[
'mob'] .
'"',
3349 'src="' .
'il_' .
IL_INST_ID .
'_mob_' . $media_object->getId() .
'"',
3369 $a_xml_writer->xmlHeader();
3370 $a_xml_writer->xmlSetDtdDef(
"<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
3371 $a_xml_writer->xmlStartTag(
"questestinterop");
3377 $a_xml_writer->xmlStartTag(
"assessment", $attrs);
3381 $a_xml_writer->xmlElement(
3388 $a_xml_writer->xmlStartTag(
"qtimetadata");
3389 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3390 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ILIAS_VERSION");
3392 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3394 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3395 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"anonymity");
3396 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $main_settings->
getGeneralSettings()->getAnonymity()));
3397 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3399 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3400 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"question_set_type");
3401 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getGeneralSettings()->getQuestionSetType());
3402 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3404 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3405 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"sequence_settings");
3407 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3409 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3410 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"author");
3411 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->
getAuthor());
3412 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3414 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3415 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"reset_processing_time");
3417 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3419 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3420 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"count_system");
3422 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3424 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3425 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"score_cutting");
3427 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3429 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3430 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"password");
3431 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getPassword() ??
'');
3432 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3434 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3435 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ip_range_from");
3436 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getIpRangeFrom());
3437 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3439 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3440 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ip_range_to");
3442 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3444 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3445 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"pass_scoring");
3447 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3449 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3450 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'pass_deletion_allowed');
3452 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3455 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3456 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"reporting_date");
3457 $a_xml_writer->xmlElement(
3464 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3467 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3468 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"nr_of_tries");
3470 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3472 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3473 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'block_after_passed');
3475 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3477 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3478 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"pass_waiting");
3480 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3482 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3483 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"kiosk");
3485 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3487 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3488 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"redirection_mode");
3490 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3492 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3493 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"redirection_url");
3495 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3497 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3498 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"use_previous_answers");
3500 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3502 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3503 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"title_output");
3505 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3507 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3508 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"results_presentation");
3509 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $this->
getScoreSettings()->getResultDetailsSettings()->getResultsPresentation()));
3510 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3512 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3513 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"examid_in_test_pass");
3514 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getExamIdInTestAttemptEnabled()));
3515 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3517 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3518 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"examid_in_test_res");
3519 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $this->
getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults()));
3520 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3522 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3523 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"usr_pass_overview_mode");
3525 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3527 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3528 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"score_reporting");
3529 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $this->
getScoreSettings()->getResultSummarySettings()->getScoreReporting()->value));
3530 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3532 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3533 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_solution_list_comparison");
3534 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $this->score_settings->getResultDetailsSettings()->getShowSolutionListComparison());
3535 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3537 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3538 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_verification");
3540 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3542 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3543 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"answer_feedback");
3545 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3547 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3548 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_specific");
3550 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3552 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3553 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"answer_feedback_points");
3555 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3557 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3558 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"follow_qst_answer_fixation");
3560 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3562 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3563 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_answer_fixation");
3565 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3567 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3568 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"force_instant_feedback");
3570 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3572 $highscore_metadata = [
3584 foreach ($highscore_metadata as $label =>
$data) {
3585 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3586 $a_xml_writer->xmlElement(
"fieldlabel",
null, $label);
3587 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d",
$data[
'value']));
3588 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3591 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3592 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"suspend_test_allowed");
3594 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3596 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3597 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_marker");
3599 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3601 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3602 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"fixed_participants");
3603 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getAccessSettings()->getFixedParticipants()));
3604 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3606 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3607 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_introduction");
3608 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getIntroductionSettings()->getIntroductionEnabled()));
3609 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3611 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3612 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_concluding_remarks");
3613 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getFinishingSettings()->getConcludingRemarksEnabled()));
3614 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3616 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3617 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mailnotification");
3618 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getFinishingSettings()->getMailNotificationContentType());
3619 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3621 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3622 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mailnottype");
3623 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getFinishingSettings()->getAlwaysSendMailNotification());
3624 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3626 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3627 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"exportsettings");
3629 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3631 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3632 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"shuffle_questions");
3634 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3636 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3637 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"processing_time");
3639 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3641 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3642 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"enable_examview");
3643 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getFinishingSettings()->getShowAnswerOverview());
3644 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3646 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3647 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"skill_service");
3648 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getAdditionalSettings()->getSkillsServiceEnabled());
3649 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3653 "solutionswitch" =>
"Yes" 3658 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs,
null);
3660 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3661 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_grading_status");
3663 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3665 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3666 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_grading_mark");
3668 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3671 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3672 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"starting_time");
3673 $a_xml_writer->xmlElement(
3680 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3684 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3685 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ending_time");
3686 $a_xml_writer->xmlElement(
3693 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3696 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3697 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"activation_limited");
3699 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3701 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3702 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"activation_start_time");
3704 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3706 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3707 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"activation_end_time");
3709 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3711 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3712 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"activation_visibility");
3714 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3716 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3717 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"autosave");
3719 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3721 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3722 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"autosave_ival");
3724 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3726 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3727 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"offer_question_hints");
3729 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3731 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3732 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_specific");
3734 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3736 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3737 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_answer_fixation");
3739 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3741 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3742 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"enable_processing_time");
3744 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3746 foreach ($this->
getMarkSchema()->getMarkSteps() as $index => $mark) {
3747 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3748 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mark_step_$index");
3749 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
3750 "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
3751 $mark->getShortName(),
3752 $mark->getOfficialName(),
3753 $mark->getMinimumLevel(),
3756 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3758 $a_xml_writer->xmlEndTag(
"qtimetadata");
3761 $introduction = $page_id !==
null 3762 ? (
new ilTestPage($page_id))->getXMLContent()
3765 $a_xml_writer->xmlStartTag(
"objectives");
3767 $a_xml_writer->xmlEndTag(
"objectives");
3771 "solutionswitch" =>
"Yes" 3776 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs,
null);
3780 $concluding_remarks = $page_id !==
null 3781 ? (
new ilTestPage($page_id))->getXMLContent()
3784 $a_xml_writer->xmlStartTag(
"presentation_material");
3785 $a_xml_writer->xmlStartTag(
"flow_mat");
3786 $this->
addQTIMaterial($a_xml_writer, $page_id, $concluding_remarks);
3787 $a_xml_writer->xmlEndTag(
"flow_mat");
3788 $a_xml_writer->xmlEndTag(
"presentation_material");
3794 $a_xml_writer->xmlElement(
"section", $attrs,
null);
3795 $a_xml_writer->xmlEndTag(
"assessment");
3796 $a_xml_writer->xmlEndTag(
"questestinterop");
3798 $xml = $a_xml_writer->xmlDumpMem(
false);
3804 return $date_time->setTimezone(
new DateTimeZone(
'UTC'))->format(
'\PY\Yn\Mj\D\TG\Hi\Ms\S');
3809 if ($period ===
null) {
3812 if (preg_match(
"/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $period, $matches)) {
3815 "%02d-%02d-%02d %02d:%02d:%02d",
3835 public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog): void
3837 $this->mob_ids = [];
3840 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Page Objects");
3841 $this->bench->start(
"ContentObjectExport",
"exportPageObjects");
3843 $this->bench->stop(
"ContentObjectExport",
"exportPageObjects");
3844 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Page Objects");
3847 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Media Objects");
3848 $this->bench->start(
"ContentObjectExport",
"exportMediaObjects");
3850 $this->bench->stop(
"ContentObjectExport",
"exportMediaObjects");
3851 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Media Objects");
3854 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export File Items");
3855 $this->bench->start(
"ContentObjectExport",
"exportFileItems");
3857 $this->bench->stop(
"ContentObjectExport",
"exportFileItems");
3858 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export File Items");
3868 if ($a_tag ==
"Identifier" && $a_param ==
"Entry") {
3884 foreach ($this->questions as $question_id) {
3885 $this->bench->start(
"ContentObjectExport",
"exportPageObject");
3886 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Page Object " . $question_id);
3889 $a_xml_writer->xmlStartTag(
"PageObject", $attrs);
3893 $this->bench->start(
"ContentObjectExport",
"exportPageObject_XML");
3895 $page_object->buildDom();
3896 $page_object->insertInstIntoIDs((
string) $inst);
3897 $mob_ids = $page_object->collectMediaObjects(
false);
3899 $xml = $page_object->getXMLFromDom(
false,
false,
false,
"",
true);
3900 $xml = str_replace(
"&",
"&", $xml);
3901 $a_xml_writer->appendXML($xml);
3902 $page_object->freeDom();
3903 unset($page_object);
3905 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_XML");
3908 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectMedia");
3910 foreach ($mob_ids as $mob_id) {
3911 $this->mob_ids[$mob_id] = $mob_id;
3913 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectMedia");
3916 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
3918 foreach ($file_ids as $file_id) {
3919 $this->file_ids[$file_id] = $file_id;
3921 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
3923 $a_xml_writer->xmlEndTag(
"PageObject");
3926 $this->bench->stop(
"ContentObjectExport",
"exportPageObject");
3935 foreach ($this->mob_ids as $mob_id) {
3936 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Media Object " . $mob_id);
3938 $target_dir = $a_target_dir . DIRECTORY_SEPARATOR .
'objects' 3939 . DIRECTORY_SEPARATOR .
'il_' .
IL_INST_ID .
'_mob_' . $mob_id;
3942 $media_obj->exportXML($a_xml_writer, (
int) $a_inst);
3943 foreach ($media_obj->getMediaItems() as $item) {
3944 $stream = $item->getLocationStream();
3945 file_put_contents($target_dir . DIRECTORY_SEPARATOR . $item->getLocation(), $stream);
3959 foreach ($this->file_ids as $file_id) {
3960 $expLog->write(date(
"[y-m-d H:i:s] ") .
"File Item " . $file_id);
3961 $file_dir = $target_dir .
'/objects/il_' .
IL_INST_ID .
'_file_' . $file_id;
3963 $file_obj =
new ilObjFile((
int) $file_id,
false);
3964 $source_file = $file_obj->getFile($file_obj->getVersion());
3965 if (!is_file($source_file)) {
3966 $source_file = $file_obj->getFile();
3968 if (is_file($source_file)) {
3969 copy($source_file, $file_dir .
'/' . $file_obj->getFileName());
3988 $this->
saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
4001 $results_summary_settings = $this->
getScoreSettings()->getResultSummarySettings();
4003 || $results_summary_settings->getScoreReporting()->isReportingEnabled() ===
false) {
4007 if ($results_summary_settings->getScoreReporting() === ScoreReportingTypes::SCORE_REPORTING_DATE) {
4008 return $results_summary_settings->getReportingDate()
4026 $path_to_lifecycle = $this->lo_metadata->paths()->custom()->withNextStep(
'lifeCycle')->get();
4027 $path_to_authors = $this->lo_metadata->paths()->authors();
4029 $reader = $this->lo_metadata->read($this->
getId(), 0, $this->
getType(), $path_to_lifecycle);
4030 if (!is_null($reader->allData($path_to_lifecycle)->current())) {
4034 if ($author ===
'') {
4035 $author = $this->
user->getFullname();
4037 $this->lo_metadata->manipulate($this->
getId(), 0, $this->
getType())
4038 ->prepareCreateOrUpdate($path_to_authors, $author)
4059 $path_to_authors = $this->lo_metadata->paths()->authors();
4060 $author_data = $this->lo_metadata->read($this->
getId(), 0, $this->
getType(), $path_to_authors)
4061 ->allData($path_to_authors);
4063 return $this->lo_metadata->dataHelper()->makePresentableAsList(
', ', ...$author_data);
4077 $lo_metadata = $DIC->learningObjectMetadata();
4079 $path_to_authors = $lo_metadata->paths()->authors();
4080 $author_data = $lo_metadata->read($obj_id, 0,
"tst", $path_to_authors)
4081 ->allData($path_to_authors);
4083 return $lo_metadata->dataHelper()->makePresentableAsList(
',', ...$author_data);
4095 $ilUser = $DIC[
'ilUser'];
4098 $tests = array_slice(
4106 if (count($tests)) {
4109 if ($use_object_id) {
4111 $result_array[$obj_id] = $titles[
$ref_id];
4117 return $result_array;
4132 $new_obj = parent::cloneObject($target_id, $copy_id, $omit_tree);
4133 $new_obj->setTmpCopyWizardCopyId($copy_id);
4136 $new_obj->saveToDb();
4137 $new_obj->addToNewsOnOnline(
false, $new_obj->getObjectProperties()->getPropertyIsOnline()->getIsOnline());
4140 ->withIntroductionSettings(
4141 $this->
getMainSettings()->getIntroductionSettings()->withIntroductionPageId(
4143 )->withTestId($new_obj->getTestId())
4144 )->withFinishingSettings(
4145 $this->
getMainSettings()->getFinishingSettings()->withConcludingRemarksPageId(
4147 )->withTestId($new_obj->getTestId())
4153 $this->marks_repository->storeMarkSchema(
4166 $templateRepository,
4170 $cloneAction->cloneCertificate($this, $new_obj);
4172 $this->question_set_config_factory->getQuestionSetConfig()->cloneQuestionSetRelatedData($new_obj);
4173 $new_obj->saveQuestionsToDb();
4176 $skillLevelThresholdList->setTestId($this->
getTestId());
4177 $skillLevelThresholdList->loadFromDb();
4178 $skillLevelThresholdList->cloneListForTest($new_obj->getTestId());
4181 $obj_settings->cloneSettings($new_obj->getId());
4183 if ($new_obj->getTestLogger()->isLoggingEnabled()) {
4184 $new_obj->getTestLogger()->logTestAdministrationInteraction(
4185 $new_obj->getTestLogger()->getInteractionFactory()->buildTestAdministrationInteraction(
4186 $new_obj->getRefId(),
4187 $this->
user->getId(),
4188 TestAdministrationInteractionTypes::NEW_TEST_CREATED,
4207 $this->component_repository,
4209 $this->questionrepository
4212 $questionSetConfig->loadFromDb();
4214 if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
4221 $sourcePoolDefinitionList->loadDefinitions();
4223 if (is_int($sourcePoolDefinitionList->getQuestionAmount())) {
4224 $num = $sourcePoolDefinitionList->getQuestionAmount();
4226 } elseif (is_int($questionSetConfig->getQuestionAmountPerTest())) {
4227 $num = $questionSetConfig->getQuestionAmountPerTest();
4231 $num = count($this->questions);
4242 return count($this->questions);
4255 $ilDB = $DIC[
'ilDB'];
4257 $result =
$ilDB->queryF(
4258 "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
4262 if ($result->numRows()) {
4263 $row =
$ilDB->fetchAssoc($result);
4264 $object_id = $row[
"obj_fi"];
4279 $ilDB = $DIC[
'ilDB'];
4281 $result =
$ilDB->queryF(
4282 "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",
4286 if ($result->numRows()) {
4287 $row =
$ilDB->fetchAssoc($result);
4288 $object_id = $row[
"obj_fi"];
4303 $ilDB = $DIC[
'ilDB'];
4305 $result =
$ilDB->queryF(
4306 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
4310 if ($result->numRows()) {
4311 $row =
$ilDB->fetchAssoc($result);
4312 $test_id = $row[
"test_id"];
4327 if (($active_id) && ($question_id)) {
4328 if ($pass ===
null) {
4331 if ($pass ===
null) {
4334 $query = $this->db->queryF(
4335 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
4336 [
'integer',
'integer',
'integer'],
4337 [$active_id, $question_id, $pass]
4339 $result = $this->db->fetchAll($query);
4340 if (count($result) == 1) {
4341 return $result[0][
"value1"];
4358 $result = $this->db->queryF(
4359 "SELECT question_text FROM qpl_questions WHERE question_id = %s",
4363 if ($result->numRows() == 1) {
4364 $row = $this->db->fetchAssoc($result);
4365 $res = $row[
"question_text"];
4376 return $participant_list;
4391 $result = $this->db->queryF(
4392 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
4393 "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 " .
4394 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4395 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4397 [
'text',
'text',
'text',
'integer',
'integer'],
4401 $result = $this->db->queryF(
4402 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
4403 "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 " .
4404 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4405 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4407 [
'text',
'text',
'text',
'integer'],
4408 [
'', $this->
lng->txt(
'anonymous'),
'', $this->
getTestId()]
4413 $result = $this->db->queryF(
4414 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
4415 "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 " .
4416 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4417 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4419 [
'integer',
'integer'],
4423 $result = $this->db->queryF(
4424 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
4425 "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 " .
4426 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4427 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4435 while ($row = $this->db->fetchAssoc($result)) {
4436 $result_array[$row[
'usr_id']] = $row;
4438 return $result_array;
4445 SELECT tst_active.active_id, 4447 tst_active.user_fi usr_id, 4451 tst_active.submitted test_finished, 4452 usr_data.matriculation, 4454 tst_active.lastindex, 4455 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes 4458 ON tst_active.user_fi = usr_data.usr_id 4459 WHERE tst_active.test_fi = %s 4460 ORDER BY usr_data.lastname 4462 $result = $this->db->queryF(
4464 [
'text',
'text',
'text',
'integer'],
4465 [
'', $this->
lng->txt(
"anonymous"),
"", $this->
getTestId()]
4469 SELECT tst_active.active_id, 4471 tst_active.user_fi usr_id, 4475 tst_active.submitted test_finished, 4476 usr_data.matriculation, 4478 tst_active.lastindex, 4479 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes 4482 ON tst_active.user_fi = usr_data.usr_id 4483 WHERE tst_active.test_fi = %s 4484 ORDER BY usr_data.lastname 4486 $result = $this->db->queryF(
4493 while ($row = $this->db->fetchAssoc($result)) {
4494 $data[$row[
'active_id']] = $row;
4496 foreach (
$data as $index => $participant) {
4497 if (strlen(trim($participant[
"firstname"] . $participant[
"lastname"])) == 0) {
4498 $data[$index][
"lastname"] = $this->
lng->txt(
"deleted_user");
4510 $filtered_participants = [];
4512 if ($participant[
'tries'] > 0) {
4515 if ($this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
4516 $filtered_participants[$active_id] = $participant;
4520 if (!$this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
4521 $filtered_participants[$active_id] = $participant;
4525 $filtered_participants[$active_id] = $participant;
4529 return $filtered_participants;
4540 if (!is_array($ids) || count($ids) == 0) {
4545 $result = $this->db->queryF(
4546 "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",
4547 [
'text',
'text',
'text'],
4548 [
"", $this->
lng->txt(
"anonymous"),
""]
4551 $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");
4555 while ($row = $this->db->fetchAssoc($result)) {
4556 $result_array[$row[
"usr_id"]] = $row;
4558 return $result_array;
4563 if (!is_array($ids) || count($ids) == 0) {
4576 if (!is_array($ids) || count($ids) == 0) {
4580 foreach ($ids as $obj_id) {
4594 $this->db->manipulateF(
4595 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
4596 [
'integer',
'integer'],
4599 $this->db->manipulateF(
4600 "INSERT INTO tst_invited_user (test_fi, user_fi, ip_range_from, ip_range_to, tstamp) VALUES (%s, %s, %s, %s, %s)",
4601 [
'integer',
'integer',
'text',
'text',
'integer'],
4602 [$this->
getTestId(),
$user_id, (strlen($client_ip)) ? $client_ip :
null, (strlen($client_ip)) ? $client_ip : null,time()]
4614 $ilDB = $DIC[
'ilDB'];
4615 if (is_numeric($question_fi)) {
4616 $result =
$ilDB->queryF(
4617 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
4618 [
'integer',
'integer'],
4619 [$active_id, $question_fi]
4622 $result =
$ilDB->queryF(
4623 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
4629 while ($row =
$ilDB->fetchAssoc($result)) {
4630 $result_array[$row[
"question_fi"]] = $row;
4632 return $result_array;
4642 $this->db->manipulateF(
4643 "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
4644 [
'integer',
'integer'],
4645 [$active_id, $question_id]
4647 $this->db->manipulateF(
4648 "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
4649 [
'integer',
'integer',
'integer'],
4650 [$value, $question_id, $active_id]
4659 $result = $this->db->queryF(
4660 "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
4661 [
'integer',
'integer'],
4664 return $result->numRows() == 1;
4676 $result = $this->db->queryF(
4677 "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
4678 [
'integer',
'integer',
'integer'],
4681 return $result->numRows() == 1;
4715 "user_id" => $this->
lng->txt(
"user_id"),
4716 "matriculation" => $this->
lng->txt(
"matriculation"),
4717 "lastname" => $this->
lng->txt(
"lastname"),
4718 "firstname" => $this->
lng->txt(
"firstname"),
4719 "login" => $this->
lng->txt(
"login"),
4720 "reached_points" => $this->
lng->txt(
"tst_reached_points"),
4721 "max_points" => $this->
lng->txt(
"tst_maximum_points"),
4722 "percent_value" => $this->
lng->txt(
"tst_percent_solved"),
4723 "mark" => $this->
lng->txt(
"tst_mark"),
4724 "passed" => $this->
lng->txt(
"tst_mark_passed"),
4727 if (count($participants)) {
4728 foreach ($participants as $active_id => $user_rec) {
4731 $reached_points = 0;
4735 if (!is_int($pass)) {
4738 foreach ($this->questions as $value) {
4740 if (is_object($question)) {
4741 $max_points += $question->getMaximumPoints();
4742 $reached_points += $question->getReachedPoints($active_id, $pass);
4745 if ($max_points > 0) {
4746 $percentvalue = $reached_points / $max_points;
4747 if ($percentvalue < 0) {
4748 $percentvalue = 0.0;
4753 $mark_obj = $this->
getMarkSchema()->getMatchingMark($percentvalue * 100);
4755 if ($mark_obj !==
null) {
4756 $mark = $mark_obj->getOfficialName();
4759 $user_rec[
'firstname'] =
"";
4760 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
4763 "user_id" => $user_rec[
'usr_id'],
4764 "matriculation" => $user_rec[
'matriculation'],
4765 "lastname" => $user_rec[
'lastname'],
4766 "firstname" => $user_rec[
'firstname'],
4767 "login" => $user_rec[
'login'],
4768 "reached_points" => $reached_points,
4769 "max_points" => $max_points,
4770 "percent_value" => $percentvalue,
4772 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
4790 $ilDB = $DIC[
'ilDB'];
4791 $result =
$ilDB->queryF(
4792 "SELECT tries FROM tst_active WHERE active_id = %s",
4796 if ($result->numRows()) {
4797 $row =
$ilDB->fetchAssoc($result);
4798 return $row[
"tries"];
4816 $ilDB = $DIC[
'ilDB'];
4817 $result =
$ilDB->queryF(
4818 "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
4823 if ($result->numRows()) {
4824 $row =
$ilDB->fetchAssoc($result);
4825 return $row[
"maxpass"];
4839 $ilDB = $DIC[
'ilDB'];
4841 $result =
$ilDB->queryF(
4842 "SELECT * FROM tst_pass_result WHERE active_fi = %s",
4847 if (!$result->numRows()) {
4853 while ($row =
$ilDB->fetchAssoc($result)) {
4854 if ($row[
"maxpoints"] > 0.0) {
4855 $factor = (float) ($row[
"points"] / $row[
"maxpoints"]);
4859 if ($factor === 0.0 && $bestfactor === 0.0
4860 || $factor > $bestfactor) {
4862 $bestfactor = $factor;
4866 if (is_array($bestrow)) {
4867 return $bestrow[
"pass"];
4883 $counted_pass =
null;
4889 return $counted_pass;
4907 foreach ($this->questions as $value) {
4908 if ($this->questionrepository->lookupResultRecordExist($active_id, $value, $pass)) {
4909 $workedthrough += 1;
4912 return $workedthrough;
4924 $ilDB = $DIC[
'ilDB'];
4926 if (is_null($pass)) {
4931 SELECT tst_pass_result.tstamp pass_res_tstamp, 4932 tst_test_result.tstamp quest_res_tstamp 4934 FROM tst_pass_result 4936 LEFT JOIN tst_test_result 4937 ON tst_test_result.active_fi = tst_pass_result.active_fi 4938 AND tst_test_result.pass = tst_pass_result.pass 4940 WHERE tst_pass_result.active_fi = %s 4941 AND tst_pass_result.pass = %s 4943 ORDER BY tst_test_result.tstamp DESC 4946 $result =
$ilDB->queryF(
4948 [
'integer',
'integer'],
4952 while ($row =
$ilDB->fetchAssoc($result)) {
4953 if ($row[
'quest_res_tstamp']) {
4954 return $row[
'quest_res_tstamp'];
4957 return $row[
'pass_res_tstamp'];
4974 "executable" =>
true,
4975 "errormessage" =>
"" 4979 $result[
"executable"] =
false;
4980 $result[
"errormessage"] = $this->
lng->txt(
'autosave_failed') .
': ' . $this->
lng->txt(
'offline');
4985 $result[
"executable"] =
false;
4990 $result[
"executable"] =
false;
5001 $result[
"executable"] =
false;
5002 $result[
"errormessage"] = $this->
lng->txt(
"detail_max_processing_time_reached");
5007 $testPassesSelector->setActiveId($active_id);
5008 $testPassesSelector->setLastFinishedPass($test_session->getLastFinishedPass());
5011 $closedPasses = $testPassesSelector->getClosedPasses();
5014 $result[
"executable"] =
false;
5015 $result[
"errormessage"] = $this->
lng->txt(
"maximum_nr_of_tries_reached");
5021 $result[
'executable'] =
false;
5022 $result[
'errormessage'] = $this->
lng->txt(
"tst_addit_passes_blocked_after_passed_msg");
5028 $next_pass_allowed_timestamp = 0;
5029 if (!$this->
isNextPassAllowed($testPassesSelector, $next_pass_allowed_timestamp)) {
5032 $result[
'executable'] =
false;
5033 $result[
'errormessage'] = sprintf($this->
lng->txt(
'wait_for_next_pass_hint_msg'), $date);
5041 $waiting_between_passes = $this->
getMainSettings()->getTestBehaviourSettings()->getPassWaiting();
5045 $this->
getMainSettings()->getTestBehaviourSettings()->getPassWaitingEnabled()
5046 && ($waiting_between_passes !==
'')
5048 && ($last_finished_pass_timestamp !==
null)
5050 $time_values = explode(
':', $waiting_between_passes);
5051 $next_pass_allowed_timestamp = strtotime(
'+ ' . $time_values[0] .
' Days + ' . $time_values[1] .
' Hours' . $time_values[2] .
' Minutes', $last_finished_pass_timestamp);
5052 return (time() > $next_pass_allowed_timestamp);
5062 $passSelector->setActiveId($test_session->
getActiveId());
5065 return $passSelector->hasReportablePasses();
5072 $passSelector->setActiveId($test_session->
getActiveId());
5075 return $passSelector->hasExistingPasses();
5087 if ($active_id < 1) {
5090 if ($pass ===
null) {
5093 $result = $this->db->queryF(
5094 "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
5095 [
'integer',
'integer'],
5098 if ($result->numRows()) {
5099 $row = $this->db->fetchAssoc($result);
5100 if (preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches)) {
5131 if ($now > ($starting_time + $processing_time)) {
5140 $tags_trafo = $this->
refinery->string()->stripTags();
5144 questtypes.type_tag, 5146 origquest.obj_fi orig_obj_fi 5148 FROM qpl_questions questions 5150 INNER JOIN qpl_qst_type questtypes 5151 ON questtypes.question_type_id = questions.question_type_fi 5153 INNER JOIN tst_test_question tstquest 5154 ON tstquest.question_fi = questions.question_id 5156 LEFT JOIN qpl_questions origquest 5157 ON origquest.question_id = questions.original_id 5159 WHERE tstquest.test_fi = %s 5161 ORDER BY tstquest.sequence 5164 $query_result = $this->db->queryF(
5172 while ($row = $this->db->fetchAssoc($query_result)) {
5173 $row[
'title'] = $tags_trafo->transform($row[
'title']);
5174 $row[
'description'] = $tags_trafo->transform($row[
'description'] !==
'' && $row[
'description'] !==
null ? $row[
'description'] :
' ');
5175 $row[
'author'] = $tags_trafo->transform($row[
'author']);
5177 $questions[] = $row;
5186 if ($questionData[
'question_id'] != $question_id) {
5198 $row = $this->db->fetchAssoc($this->db->queryF(
5199 "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
5200 [
'integer',
'integer'],
5201 [$question_id, $this->getId()]
5204 return (
bool) $row[
'cnt'];
5212 $points += $question_data[
'points'];
5225 questtypes.type_tag, 5226 origquest.obj_fi orig_obj_fi 5228 FROM qpl_questions questions 5230 INNER JOIN qpl_qst_type questtypes 5231 ON questtypes.question_type_id = questions.question_type_fi 5233 INNER JOIN tst_rnd_cpy tstquest 5234 ON tstquest.qst_fi = questions.question_id 5236 LEFT JOIN qpl_questions origquest 5237 ON origquest.question_id = questions.original_id 5239 WHERE tstquest.tst_fi = %s 5242 $query_result = $this->db->queryF(
5248 return $this->db->fetchAll($query_result);
5253 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getShuffleQuestions();
5269 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewMode();
5274 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getQuestionListEnabled();
5279 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewEnabled();
5284 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtBeginning();
5289 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtEnd();
5294 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShowDescriptionInQuestionList();
5302 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowPassDetails();
5310 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionPrintview();
5325 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionFeedback();
5333 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionAnswersOnly();
5341 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionSignature();
5349 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionSuggested();
5358 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionListComparison();
5363 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionListOwnAnswers();
5372 $ilDB = $DIC[
'ilDB'];
5373 $result =
$ilDB->queryF(
5374 "SELECT user_fi FROM tst_active WHERE active_id = %s",
5378 if ($result->numRows()) {
5379 $row =
$ilDB->fetchAssoc($result);
5380 return $row[
"user_fi"];
5388 $result = $this->db->queryF(
5389 "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
5393 if ($result->numRows()) {
5394 $row = $this->db->fetchAssoc($result);
5395 return $row[
"finished"];
5400 public static function lookupLastTestPassAccess(
int $active_id,
int $pass_index): ?
int 5404 $ilDB = $DIC[
'ilDB'];
5407 SELECT MAX(tst_times.tstamp) as last_pass_access 5409 WHERE active_fi = %s 5415 [
'integer',
'integer'],
5416 [$active_id, $pass_index]
5419 while ($row =
$ilDB->fetchAssoc(
$res)) {
5420 return $row[
'last_pass_access'];
5435 if (preg_match(
"/<[^>]*?>/", $a_text)) {
5452 for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
5453 $material = $a_material->getMaterial($i);
5454 if ($material[
'type'] ===
'mattext') {
5455 $result .= $material[
'material']->getContent();
5457 if ($material[
'type'] ===
'matimage') {
5458 $matimage = $material[
'material'];
5459 if (preg_match(
'/(il_([0-9]+)_mob_([0-9]+))/', $matimage->getLabel(), $matches)) {
5461 'mob' => $matimage->getLabel(),
5462 'uri' => $matimage->getUri()
5468 $decoded_result = base64_decode($result);
5469 if (str_starts_with($decoded_result,
'<PageObject>')) {
5470 $result = $decoded_result;
5484 'texttype' =>
'text/plain' 5488 if ($page_id !==
null) {
5489 $attrs[
'texttype'] =
'text/xml';
5492 $page_object->buildDom();
5493 $page_object->insertInstIntoIDs((
string)
IL_INST_ID);
5494 $material = base64_encode($page_object->getXMLFromDom());
5496 foreach ($file_ids as $file_id) {
5497 $this->file_ids[] = (
int) $file_id;
5499 $mob_string =
'il_' . IL_INST_ID .
'_mob_';
5500 } elseif ($this->
isHTML($material)) {
5501 $attrs[
'texttype'] =
'text/xhtml';
5503 $mob_string =
'mm_';
5506 $xml_writer->
xmlElement(
'mattext', $attrs, $material);
5507 foreach ($mobs as $mob) {
5508 $mob_id_string = (string) $mob;
5509 $moblabel =
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string;
5510 if (strpos($material, $mob_string . $mob_id_string) !==
false) {
5514 'label' => $moblabel,
5515 'uri' =>
'objects/' .
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string .
'/' . $mob_obj->getTitle()
5532 if ($txt_output ==
null) {
5537 $prepare_for_latex_output,
5538 $omitNl2BrWhenTextArea
5544 return $this->
getMainSettings()->getGeneralSettings()->getAnonymity();
5551 $ilDB = $DIC[
'ilDB'];
5553 $result =
$ilDB->queryF(
5554 "SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
5558 while ($row =
$ilDB->fetchAssoc($result)) {
5559 return (
int) $row[
'anonymity'];
5566 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getSuspendTestAllowed();
5571 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getQuestionMarkingEnabled();
5576 return $this->
getMainSettings()->getAccessSettings()->getFixedParticipants();
5582 SELECT tst_tests.question_set_type 5584 INNER JOIN tst_tests 5585 ON tst_active.test_fi = tst_tests.test_id 5586 WHERE tst_active.active_id = %s 5589 $res = $this->db->queryF($query, [
'integer'], [$active_id]);
5591 while ($row = $this->db->fetchAssoc(
$res)) {
5592 return $row[
'question_set_type'];
5611 return $this->
lng->txt(
"anonymous") . $suffix;
5614 if (strlen($uname[
"firstname"] . $uname[
"lastname"]) == 0) {
5615 $uname[
"firstname"] = $this->
lng->txt(
"deleted_user");
5617 if ($sorted_order) {
5618 return trim($uname[
"lastname"] .
", " . $uname[
"firstname"]) . $suffix;
5620 return trim($uname[
"firstname"] .
" " . $uname[
"lastname"]) . $suffix;
5632 $result = $this->db->queryF(
5633 "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
5635 [$this->
user->getId()]
5638 while ($row = $this->db->fetchAssoc($result)) {
5639 $defaults[$row[
"test_defaults_id"]] = $row;
5646 $result = $this->db->queryF(
5647 "SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
5651 if ($result->numRows() == 1) {
5652 $row = $this->db->fetchAssoc($result);
5661 $this->db->manipulateF(
5662 "DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
5730 'mailnotification' => $main_settings->
getFinishingSettings()->getMailNotificationContentType(),
5764 fn(
Mark $v): array => [
5773 $next_id = $this->db->nextId(
'tst_test_defaults');
5775 'tst_test_defaults',
5777 'test_defaults_id' => [
'integer', $next_id],
5778 'name' => [
'text', $a_name],
5779 'user_fi' => [
'integer', $this->
user->getId()],
5780 'defaults' => [
'clob', serialize($testsettings)],
5781 'marks' => [
'clob', json_encode($marks)],
5782 'tstamp' => [
'integer', time()]
5789 $testsettings = unserialize($test_defaults[
'defaults'], [
'allowed_classes' => [DateTimeImmutable::class]]);
5790 $activation_starting_time = is_numeric($testsettings[
'activation_starting_time'] ??
false)
5791 ? (
int) $testsettings[
'activation_starting_time']
5793 $activation_ending_time = is_numeric($testsettings[
'activation_ending_time'] ??
false)
5794 ? (
int) $testsettings[
'activation_ending_time']
5796 $unserialized_marks = json_decode($test_defaults[
'marks'],
true);
5799 if (is_array($unserialized_marks)
5800 && is_array($unserialized_marks[0])) {
5805 $v[
'official_name'],
5806 $v[
'minimum_level'],
5813 $info =
'old_mark_default_not_applied';
5818 (
bool) ($testsettings[
'is_activation_limited'] ??
false),
5819 $activation_starting_time,
5820 $activation_ending_time,
5821 (
bool) ($testsettings[
'activation_visibility'] ??
false),
5825 $main_settings = $main_settings
5828 ->withQuestionSetType($testsettings[
'questionSetType'])
5829 ->withAnonymity((
bool) $testsettings[
'Anonymity'])
5831 ->withIntroductionSettings(
5833 ->withIntroductionEnabled((
bool) $testsettings[
'IntroEnabled'])
5834 ->withExamConditionsCheckboxEnabled((
bool) ($testsettings[
'ExamConditionsCheckboxEnabled'] ??
false))
5836 ->withAccessSettings(
5838 ->withStartTimeEnabled((
bool) $testsettings[
'StartingTimeEnabled'])
5840 ->withEndTimeEnabled((
bool) $testsettings[
'EndingTimeEnabled'])
5842 ->withPasswordEnabled((
bool) $testsettings[
'password_enabled'])
5843 ->withPassword($testsettings[
'password'])
5844 ->withFixedParticipants((
bool) $testsettings[
'fixed_participants'])
5846 ->withTestBehaviourSettings(
5848 ->withNumberOfTries($testsettings[
'NrOfTries'])
5849 ->withBlockAfterPassedEnabled((
bool) $testsettings[
'BlockAfterPassed'])
5850 ->withPassWaiting($testsettings[
'pass_waiting'])
5851 ->withKioskMode($testsettings[
'Kiosk'])
5852 ->withProcessingTimeEnabled((
bool) $testsettings[
'EnableProcessingTime'])
5853 ->withProcessingTime($testsettings[
'ProcessingTime'])
5854 ->withResetProcessingTime((
bool) $testsettings[
'ResetProcessingTime'])
5855 ->withExamIdInTestAttemptEnabled((
bool) ($testsettings[
'examid_in_test_pass'] ?? 0))
5857 ->withQuestionBehaviourSettings(
5859 ->withQuestionTitleOutputMode($testsettings[
'TitleOutput'])
5860 ->withAutosaveEnabled((
bool) $testsettings[
'autosave'])
5861 ->withAutosaveInterval($testsettings[
'autosave_ival'])
5862 ->withShuffleQuestions((
bool) $testsettings[
'Shuffle'])
5863 ->withQuestionHintsEnabled((
bool) $testsettings[
'offer_question_hints'])
5864 ->withInstantFeedbackPointsEnabled((
bool) $testsettings[
'AnswerFeedbackPoints'])
5865 ->withInstantFeedbackGenericEnabled((
bool) $testsettings[
'AnswerFeedback'])
5866 ->withInstantFeedbackSpecificEnabled((
bool) $testsettings[
'SpecificAnswerFeedback'])
5867 ->withInstantFeedbackSolutionEnabled((
bool) $testsettings[
'InstantFeedbackSolution'])
5868 ->withForceInstantFeedbackOnNextQuestion((
bool) $testsettings[
'force_inst_fb'])
5869 ->withLockAnswerOnInstantFeedbackEnabled((
bool) $testsettings[
'inst_fb_answer_fixation'])
5870 ->withLockAnswerOnNextQuestionEnabled((
bool) $testsettings[
'follow_qst_answer_fixation'])
5872 ->withParticipantFunctionalitySettings(
5874 ->withUsePreviousAnswerAllowed((
bool) $testsettings[
'use_previous_answers'])
5875 ->withSuspendTestAllowed((
bool) $testsettings[
'ShowCancel'])
5876 ->withPostponedQuestionsMoveToEnd((
bool) $testsettings[
'SequenceSettings'])
5877 ->withUsrPassOverviewMode((
int) $testsettings[
'ListOfQuestionsSettings'])
5878 ->withQuestionMarkingEnabled((
bool) $testsettings[
'ShowMarker'])
5880 ->withFinishingSettings(
5882 ->withShowAnswerOverview((
bool) $testsettings[
'enable_examview'])
5883 ->withConcludingRemarksEnabled((
bool) $testsettings[
'ShowFinalStatement'])
5884 ->withRedirectionMode((
int) $testsettings[
'redirection_mode'])
5885 ->withRedirectionUrl($testsettings[
'redirection_url'])
5886 ->withMailNotificationContentType((
int) $testsettings[
'mailnotification'])
5887 ->withAlwaysSendMailNotification((
bool) $testsettings[
'mailnottype'])
5889 ->withAdditionalSettings(
5891 ->withSkillsServiceEnabled((
bool) $testsettings[
'skill_service'])
5892 ->withHideInfoTab((
bool) ($testsettings[
'HideInfoTab'] ??
false))
5897 $score_reporting = ScoreReportingTypes::SCORE_REPORTING_DISABLED;
5898 if ($testsettings[
'ScoreReporting'] !==
null) {
5899 $score_reporting = ScoreReportingTypes::tryFrom($testsettings[
'ScoreReporting'])
5900 ?? ScoreReportingTypes::SCORE_REPORTING_DISABLED;
5903 $reporting_date = $testsettings[
'ReportingDate'];
5904 if (is_string($reporting_date)) {
5909 $score_settings = $score_settings
5912 ->withPassScoring($testsettings[
'PassScoring'])
5913 ->withScoreCutting($testsettings[
'ScoreCutting'])
5914 ->withCountSystem($testsettings[
'CountSystem'])
5916 ->withResultSummarySettings(
5918 ->withPassDeletionAllowed((
bool) $testsettings[
'pass_deletion_allowed'])
5919 ->withShowGradingStatusEnabled((
bool) $testsettings[
'show_grading_status'])
5920 ->withShowGradingMarkEnabled((
bool) $testsettings[
'show_grading_mark'])
5921 ->withScoreReporting($score_reporting)
5922 ->withReportingDate($reporting_date)
5924 ->withResultDetailsSettings(
5926 ->withResultsPresentation((
int) $testsettings[
'ResultsPresentation'])
5927 ->withShowSolutionListComparison((
bool) ($testsettings[
'show_solution_list_comparison'] ?? 0))
5928 ->withShowExamIdInTestResults((
bool) $testsettings[
'examid_in_test_res'])
5930 ->withGamificationSettings(
5932 ->withHighscoreEnabled((
bool) $testsettings[
'highscore_enabled'])
5933 ->withHighscoreAnon((
bool) $testsettings[
'highscore_anon'])
5934 ->withHighscoreAchievedTS($testsettings[
'highscore_achieved_ts'])
5935 ->withHighscoreScore((
bool) $testsettings[
'highscore_score'])
5936 ->withHighscorePercentage($testsettings[
'highscore_percentage'])
5937 ->withHighscoreHints((
bool) $testsettings[
'highscore_hints'])
5938 ->withHighscoreWTime((
bool) $testsettings[
'highscore_wtime'])
5939 ->withHighscoreOwnTable((
bool) $testsettings[
'highscore_own_table'])
5940 ->withHighscoreTopTable((
bool) $testsettings[
'highscore_top_table'])
5941 ->withHighscoreTopNum($testsettings[
'highscore_top_num'])
5957 return DateTimeImmutable::createFromFormat(
'U', (
string) $date_time);
5969 if (extension_loaded(
"tidy")) {
5972 "output-xml" =>
true,
5973 "numeric-entities" => true
5976 $tidy->parseString($print_output, $config,
'utf8');
5977 $tidy->cleanRepair();
5978 $print_output = tidy_get_output($tidy);
5979 $print_output = preg_replace(
"/^.*?(<html)/",
"\\1", $print_output);
5981 $print_output = str_replace(
" ",
" ", $print_output);
5982 $print_output = str_replace(
"⊗",
"X", $print_output);
5984 $xsl = file_get_contents(
"./components/ILIAS/Test/xml/question2fo.xsl");
5989 'font-family="Helvetica, unifont"',
5990 'font-family="' . $this->
settings->get(
'rpc_pdf_font',
'Helvetica, unifont') .
'"',
5994 $args = [
'/_xml' => $print_output,
'/_xsl' => $xsl ];
5995 $xh = xslt_create();
5997 $output = xslt_process($xh,
"arg:/_xml",
"arg:/_xsl",
null, $args,
$params);
6011 $content = preg_replace(
"/href=\".*?\"/",
"", $content);
6012 $printbody =
new ilTemplate(
"tpl.il_as_tst_print_body.html",
true,
true,
"components/ILIAS/Test");
6014 $printbody->setVariable(
"ADM_CONTENT", $content);
6015 $printbody->setCurrentBlock(
"css_file");
6017 $printbody->parseCurrentBlock();
6018 $printoutput = $printbody->get();
6019 $html = str_replace(
"href=\"./",
"href=\"" . ILIAS_HTTP_PATH .
"/", $printoutput);
6020 $html = preg_replace(
"/<div id=\"dontprint\">.*?<\\/div>/ims",
"", $html);
6021 if (extension_loaded(
"tidy")) {
6024 "output-xml" =>
true,
6025 "numeric-entities" => true
6028 $tidy->parseString($html, $config,
'utf8');
6029 $tidy->cleanRepair();
6030 $html = tidy_get_output($tidy);
6031 $html = preg_replace(
"/^.*?(<html)/",
"\\1", $html);
6033 $html = str_replace(
" ",
" ", $html);
6034 $html = str_replace(
"⊗",
"X", $html);
6036 $html = preg_replace(
"/src=\".\\//ims",
"src=\"" . ILIAS_HTTP_PATH .
"/", $html);
6048 $fp = fopen($fo_file,
"w");
6057 $pdf_base64->scalar,
6063 $this->
logger->info(__METHOD__ .
': ' . $e->getMessage());
6079 if ($pass ===
null) {
6083 $row = self::getSingleManualFeedback((
int) $active_id, (
int) $question_id, (
int) $pass);
6086 $feedback = $row[
'feedback'] ??
'';
6095 $ilDB = $DIC[
'ilDB'];
6097 $result =
$ilDB->queryF(
6098 "SELECT * FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
6099 [
'integer',
'integer',
'integer'],
6100 [$active_id, $question_id, $pass]
6103 if (
$ilDB->numRows($result) === 1) {
6104 $row =
$ilDB->fetchAssoc($result);
6106 } elseif (
$ilDB->numRows($result) > 1) {
6107 $DIC->logger()->root()->warning(
6108 "WARNING: Multiple feedback entries on tst_manual_fb for " .
6109 "active_fi = $active_id , question_fi = $question_id and pass = $pass" 6126 $ilDB = $DIC[
'ilDB'];
6129 $result =
$ilDB->queryF(
6130 "SELECT * FROM tst_manual_fb WHERE question_fi = %s",
6135 while ($row =
$ilDB->fetchAssoc($result)) {
6136 $active = $row[
'active_fi'];
6137 $pass = $row[
'pass'];
6138 $question = $row[
'question_fi'];
6142 $feedback[$active][$pass][$question] = $row;
6153 bool $finalized =
false 6155 $feedback_old = self::getSingleManualFeedback($active_id, $question_id, $pass);
6156 $this->db->manipulateF(
6157 'DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s',
6158 [
'integer',
'integer',
'integer'],
6159 [$active_id, $question_id, $pass]
6162 $this->
insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old);
6174 $next_id = $this->db->nextId(
'tst_manual_fb');
6176 $finalized_time = time();
6179 'manual_feedback_id' => [
'integer', $next_id],
6180 'active_fi' => [
'integer', $active_id],
6181 'question_fi' => [
'integer', $question_id],
6182 'pass' => [
'integer', $pass],
6184 'tstamp' => [
'integer', time()]
6187 if ($feedback_old !== [] && (
int) $feedback_old[
'finalized_evaluation'] === 1) {
6188 $user = $feedback_old[
'finalized_by_usr_id'];
6189 $finalized_time = $feedback_old[
'finalized_tstamp'];
6192 if ($finalized ===
false) {
6193 $update_default[
'finalized_evaluation'] = [
'integer', 0];
6194 $update_default[
'finalized_by_usr_id'] = [
'integer', 0];
6195 $update_default[
'finalized_tstamp'] = [
'integer', 0];
6196 } elseif ($finalized ===
true) {
6197 $update_default[
'finalized_evaluation'] = [
'integer', 1];
6198 $update_default[
'finalized_by_usr_id'] = [
'integer',
$user];
6199 $update_default[
'finalized_tstamp'] = [
'integer', $finalized_time];
6202 $this->db->insert(
'tst_manual_fb', $update_default);
6204 if ($this->
logger->isLoggingEnabled()) {
6205 $this->
logger->logScoringInteraction(
6206 $this->
logger->getInteractionFactory()->buildScoringInteraction(
6209 $this->
user->getId(),
6210 self::_getUserIdFromActiveId($active_id),
6211 TestScoringInteractionTypes::QUESTION_GRADED,
6213 AdditionalInformationGenerator::KEY_EVAL_FINALIZED => $this->
logger 6214 ->getAdditionalInformationGenerator()->getTrueFalseTagForBool($finalized),
6246 $this->test_id = $a_id;
6259 if (count($participants)) {
6260 foreach ($participants as $active_id => $user_rec) {
6262 $reached_points = 0;
6265 foreach ($this->questions as $value) {
6267 if (is_object($question)) {
6268 $max_points += $question->getMaximumPoints();
6269 $reached_points += $question->getReachedPoints($active_id, $pass);
6270 if ($max_points > 0) {
6271 $percentvalue = $reached_points / $max_points;
6272 if ($percentvalue < 0) {
6273 $percentvalue = 0.0;
6279 $user_rec[
'firstname'] =
"";
6280 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
6283 "user_id" => $user_rec[
'usr_id'],
6284 "matriculation" => $user_rec[
'matriculation'],
6285 "lastname" => $user_rec[
'lastname'],
6286 "firstname" => $user_rec[
'firstname'],
6287 "login" => $user_rec[
'login'],
6288 "question_id" => $question->getId(),
6289 "question_title" => $question->getTitle(),
6290 "reached_points" => $reached_points,
6291 "max_points" => $max_points,
6292 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
6307 $ilDB = $DIC[
'ilDB'];
6309 $result =
$ilDB->queryF(
6310 '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',
6314 $rec =
$ilDB->fetchAssoc($result);
6315 return $rec[
'obj_id'] ??
null;
6326 if (!$this->component_repository->getComponentByTypeAndName(
6329 )->getPluginSlotById(
'qst')->hasPluginName($a_pname)) {
6333 return $this->component_repository
6334 ->getComponentByTypeAndName(
6338 ->getPluginSlotById(
6348 $result = $this->db->queryF(
6349 "SELECT passed FROM tst_result_cache WHERE active_fi = %s",
6353 if ($result->numRows()) {
6354 $row = $this->db->fetchAssoc($result);
6355 return $row[
'passed'];
6358 $result_array = &$this->
getTestResult($active_id, $counted_pass);
6359 return $result_array[
"test"][
"passed"];
6369 SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass 6370 FROM tst_test_result 6371 INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s 6372 INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi 6373 LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi 6374 WHERE tst_test_result.question_fi = %s 6375 ORDER BY usr_data.lastname ASC, usr_data.firstname ASC 6378 $result = $this->db->queryF(
6380 [
'integer',
'integer'],
6381 [$test_id, $question_id]
6385 while ($row = $this->db->fetchAssoc($result)) {
6390 if (!array_key_exists($row[
"active_fi"], $foundusers)) {
6391 $foundusers[$row[
"active_fi"]] = [];
6393 array_push($foundusers[$row[
"active_fi"]], [
"pass" => $row[
"pass"],
"qid" => $row[
"question_fi"]]);
6401 $found_participants =
$data->getParticipants();
6402 $results = [
'overview' => [],
'questions' => []];
6403 if ($found_participants !== []) {
6404 $results[
'overview'][
'tst_stat_result_mark_median'] =
$data->getStatistics()->getEvaluationDataOfMedianUser()?->getMark()?->getShortName() ??
'';
6405 $results[
'overview'][
'tst_stat_result_rank_median'] =
$data->getStatistics()->rankMedian();
6406 $results[
'overview'][
'tst_stat_result_total_participants'] =
$data->getStatistics()->count();
6407 $results[
'overview'][
'tst_stat_result_median'] =
$data->getStatistics()->median();
6408 $results[
'overview'][
'tst_eval_total_persons'] = count($found_participants);
6409 $total_finished =
$data->getTotalFinishedParticipants();
6410 $results[
'overview'][
'tst_eval_total_finished'] = $total_finished;
6411 $results[
'overview'][
'tst_eval_total_finished_average_time'] =
6416 $total_passed_reached = 0;
6417 $total_passed_max = 0;
6418 $total_passed_time = 0;
6419 foreach ($found_participants as $userdata) {
6420 if ($userdata->getMark()?->getPassed()) {
6422 $total_passed_reached += $userdata->getReached();
6423 $total_passed_max += $userdata->getMaxpoints();
6424 $total_passed_time += $userdata->getTimeOnTask();
6427 $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
6428 $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
6429 $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
6430 $results[
'overview'][
'tst_eval_total_passed'] = $total_passed;
6431 $results[
'overview'][
'tst_eval_total_passed_average_points'] = sprintf(
'%2.2f', $average_passed_reached)
6432 .
' ' . strtolower(
'of') .
' ' . sprintf(
'%2.2f', $average_passed_max);
6433 $results[
'overview'][
'tst_eval_total_passed_average_time'] =
6437 foreach (
$data->getQuestionTitles() as $question_id => $question_title) {
6441 foreach ($found_participants as $userdata) {
6442 for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
6443 if (is_object($userdata->getPass($i))) {
6444 $question = $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
6445 if (is_array($question)) {
6447 $reached += $question[
'reached'];
6448 $max += $question[
'points'];
6453 $percent = $max ? $reached / $max * 100.0 : 0;
6454 $results[
'questions'][$question_id] = [
6456 sprintf(
'%.2f', $answered ? $reached / $answered : 0) .
' ' . strtolower($this->
lng->txt(
'of')) .
' ' . sprintf(
'%.2f', $answered ? $max / $answered : 0),
6457 sprintf(
'%.2f', $percent) .
'%',
6459 sprintf(
'%.2f', $answered ? $reached / $answered : 0),
6460 sprintf(
'%.2f', $answered ? $max / $answered : 0),
6469 $diff_hours = floor($seconds / 3600);
6470 $seconds -= $diff_hours * 3600;
6471 $diff_minutes = floor($seconds / 60);
6472 $seconds -= $diff_minutes * 60;
6473 return sprintf(
'%02d:%02d:%02d', $diff_hours, $diff_minutes, $seconds);
6481 return $this->export_factory->getExporter($this,
'xml')
6487 return $this->
getMainSettings()->getFinishingSettings()->getMailNotificationContentType();
6495 $mail->sendSimpleNotification($owner_id, $this->
getTitle(), $usr_data);
6504 $path = $this->export_factory->getExporter(
6506 ExportImportTypes::SCORED_ATTEMPT
6507 )->withFilterByActiveId($active_id)
6512 $delivered_file_name =
'result_' . $active_id .
'.xlsx';
6514 $fd->copyAttachmentFile(
$path, $delivered_file_name);
6515 $file_names[] = $delivered_file_name;
6517 $mail->sendAdvancedNotification($owner_id, $this->
getTitle(), $usr_data, $file_names);
6519 if (count($file_names)) {
6520 $fd->unlinkFiles($file_names);
6530 FROM tst_result_cache 6531 WHERE active_fi = %s 6534 $result = $this->db->queryF(
6540 if (!$result->numRows()) {
6545 FROM tst_result_cache 6546 WHERE active_fi = %s 6549 $result = $this->db->queryF(
6556 $row = $this->db->fetchAssoc($result);
6563 return $this->
getMainSettings()->getFinishingSettings()->getAlwaysSendMailNotification();
6568 return $this->
getScoreSettings()->getResultDetailsSettings()->getExportSettings();
6583 $question_set_config = $this->question_set_config_factory->getQuestionSetConfig();
6584 $reindexed_sequence_position_map = $question_set_config->reindexQuestionOrdering();
6588 return $reindexed_sequence_position_map;
6597 foreach (array_keys($order) as
$id) {
6601 UPDATE tst_test_question 6603 WHERE question_fi = %s 6606 $this->db->manipulateF(
6608 [
'integer',
'integer'],
6613 if ($this->
logger->isLoggingEnabled()) {
6614 $this->
logger->logTestAdministrationInteraction(
6615 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
6617 $this->
user->getId(),
6618 TestAdministrationInteractionTypes::QUESTION_MOVED,
6620 AdditionalInformationGenerator::KEY_QUESTION_ORDER => $order
6633 $IN_questions = $this->db->in(
'q1.question_id', array_keys($questions),
false,
'integer');
6636 SELECT count(q1.question_id) cnt 6638 FROM qpl_questions q1 6640 INNER JOIN qpl_questions q2 6641 ON q2.question_id = q1.original_id 6644 AND q1.obj_fi = q2.obj_fi 6646 $rset = $this->db->query($query);
6647 $row = $this->db->fetchAssoc($rset);
6649 return $row[
'cnt'] > 0;
6661 $ilDB = $DIC[
'ilDB'];
6663 $result =
$ilDB->queryF(
6664 "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
6665 " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
6666 " WHERE user_fi=%s" .
6667 " GROUP BY test_fi",
6668 [
'integer',
'integer'],
6672 while ($row =
$ilDB->fetchAssoc($result)) {
6673 $obj_id = self::_getObjectIDFromTestID($row[
"test_fi"]);
6674 $all[$obj_id] = (bool) $row[
"pass"];
6691 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getQuestionHintsEnabled();
6696 $this->activation_visibility = (bool) $a_value;
6711 $this->activation_limited = (bool) $a_value;
6715 ?
bool $is_activation_limited =
false,
6716 ?
int $activation_starting_time =
null,
6717 ?
int $activation_ending_time =
null,
6718 bool $activation_visibility =
false,
6720 if (!$this->ref_id) {
6725 $is_activation_limited ??=
false;
6727 if (!$is_activation_limited) {
6731 $item->setTimingStart($activation_starting_time);
6732 $item->setTimingEnd($activation_ending_time);
6733 $item->toggleVisible($activation_visibility);
6736 $item->update($this->ref_id);
6746 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
6747 if ($page_id !==
null) {
6752 $page_object->setParentId($this->
getId());
6753 $new_page_id = $page_object->createPageWithNextId();
6755 ->withIntroductionPageId($new_page_id);
6759 return $new_page_id;
6764 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
6765 if ($page_id !==
null) {
6770 $page_object->setParentId($this->
getId());
6771 $new_page_id = $page_object->createPageWithNextId();
6773 ->withConcludingRemarksPageId($new_page_id);
6777 return $new_page_id;
6782 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreEnabled();
6796 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreAnon();
6817 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreAchievedTS();
6825 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreScore();
6833 return $this->
getScoreSettings()->getGamificationSettings()->getHighscorePercentage();
6841 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreHints();
6849 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreWTime();
6857 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreOwnTable();
6865 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreTopTable();
6874 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreTopNum();
6879 return $this->
getScoreSettings()->getGamificationSettings()->getHighScoreMode();
6884 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled();
6889 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getAutosaveEnabled();
6894 return $this->
getScoreSettings()->getResultSummarySettings()->getPassDeletionAllowed();
6899 return $this->
getMainSettings()->getFinishingSettings()->getShowAnswerOverview();
6904 $this->activation_starting_time = $starting_time;
6909 $this->activation_ending_time = $ending_time;
6931 $result = $this->db->queryF(
6932 "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",
6936 while ($row = $this->db->fetchAssoc($result)) {
6937 $times[$row[
'active_fi']] = $row[
'started'];
6945 $result = $this->db->queryF(
6946 "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",
6950 while ($row = $this->db->fetchAssoc($result)) {
6951 $times[$row[
'active_fi']] = $row[
'additionaltime'];
6958 if ($active_id === 0) {
6961 return $this->participant_repository
6962 ->getParticipantByActiveId($this->
getTestId(), $active_id)
6963 ?->getExtraTime() ?? 0;
6969 SELECT MAX(tst_pass_result.pass) + 1 max_res 6970 FROM tst_pass_result 6971 INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi 6972 WHERE test_fi = ' . $this->db->quote($this->
getTestId(),
'integer') .
' 6974 $res = $this->db->query($query);
6976 return (
int)
$data[
'max_res'];
6982 $ilDB = $DIC[
'ilDB'];
6984 $exam_id_query =
'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
6985 $exam_id_result =
$ilDB->queryF($exam_id_query, [
'integer',
'integer' ], [ $active_id, $pass ]);
6986 if (
$ilDB->numRows($exam_id_result) == 1) {
6987 $exam_id_row =
$ilDB->fetchAssoc($exam_id_result);
6989 if ($exam_id_row[
'exam_id'] !=
null) {
6990 return $exam_id_row[
'exam_id'];
7004 if ($test_obj_id ===
null) {
7005 $obj_id = self::_getObjectIDFromActiveID($active_id);
7007 $obj_id = $test_obj_id;
7010 $examId =
'I' . $inst_id .
'_T' . $obj_id .
'_A' . $active_id .
'_P' . $pass;
7017 return $this->
getMainSettings()->getTestBehaviourSettings()->getExamIdInTestAttemptEnabled();
7022 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults();
7030 ->withQuestionSetType($question_set_type)
7036 return $this->
getMainSettings()->getGeneralSettings()->getQuestionSetType();
7061 switch ($questionSetType) {
7063 return $lng->
txt(
'tst_question_set_type_fixed');
7066 return $lng->
txt(
'tst_question_set_type_random');
7069 throw new ilTestException(
'invalid question set type value given: ' . $questionSetType);
7084 $scoring->setPreserveManualScores($preserve_manscoring);
7085 $scoring->recalculateSolutions();
7092 $ilDB = $DIC[
'ilDB'];
7097 INNER JOIN tst_tests 7098 ON test_id = test_fi 7102 $res =
$ilDB->queryF($query, [
'integer'], [$userId]);
7106 while ($row =
$ilDB->fetchAssoc(
$res)) {
7107 $objIds[] = (
int) $row[
'obj_fi'];
7115 return $this->
getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled();
7131 if (!$this->
getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled()) {
7135 if (!self::isSkillManagementGloballyActivated()) {
7146 if (self::$isSkillManagementGloballyActivated ===
null) {
7149 self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
7152 return self::$isSkillManagementGloballyActivated;
7157 return $this->
getScoreSettings()->getResultSummarySettings()->getShowGradingStatusEnabled();
7162 return $this->
getScoreSettings()->getResultSummarySettings()->getShowGradingMarkEnabled();
7167 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled();
7172 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled();
7177 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion();
7184 $ilDB = $DIC[
'ilDB'];
7185 $ilUser = $DIC[
'ilUser'];
7189 $active_id = $test_obj->getActiveIdOfUser($user_id);
7194 $test_session_factory->reset();
7196 $test_sequence_factory =
new ilTestSequenceFactory($test_obj,
$ilDB, TestDIC::dic()[
'question.general_properties.repository']);
7198 $test_session = $test_session_factory->getSession($active_id);
7199 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $test_session->getPass());
7208 SELECT COUNT(test_question_id) cnt 7209 FROM tst_test_question 7214 $questRes = $this->db->queryF($query, [
'integer'], [$this->
getTestId()]);
7216 $row = $this->db->fetchAssoc($questRes);
7217 $questCount = $row[
'cnt'];
7223 INNER JOIN tst_sequence tseq 7224 ON tseq.active_fi = tac.active_id 7225 WHERE tac.test_fi = %s 7228 $partRes = $this->db->queryF(
7234 while ($row = $this->db->fetchAssoc($partRes)) {
7235 $sequence = @unserialize($row[
'sequence']);
7241 $sequence = array_filter($sequence,
function ($value) use ($questCount) {
7242 return $value <= $questCount;
7245 $num_seq = count($sequence);
7246 if ($questCount > $num_seq) {
7247 $diff = $questCount - $num_seq;
7248 for ($i = 1; $i <= $diff; $i++) {
7249 $sequence[$num_seq + $i - 1] = $num_seq + $i;
7253 $new_sequence = serialize($sequence);
7255 $this->db->update(
'tst_sequence', [
7256 'sequence' => [
'clob', $new_sequence]
7258 'active_fi' => [
'integer', $row[
'active_fi']],
7259 'pass' => [
'integer', $row[
'pass']]
7263 $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : []);
7268 INNER JOIN tst_sequence tseq 7269 ON tseq.active_fi = tac.active_id 7270 WHERE tac.test_fi = %s 7273 $part_rest = $this->db->queryF(
7279 while ($row = $this->db->fetchAssoc($part_rest)) {
7280 $this->db->update(
'tst_sequence', [
7281 'sequence' => [
'clob', $new_sequence]
7283 'active_fi' => [
'integer', $row[
'active_fi']],
7284 'pass' => [
'integer', $row[
'pass']]
7305 return $this->global_settings_repo->getGlobalSettings();
7310 if (!$this->main_settings) {
7319 if (!$this->main_settings_repo) {
7327 if (!$this->score_settings) {
7336 if (!$this->score_settings_repo) {
7346 if ($pass !==
null) {
7348 SELECT tst_pass_result.*, 7349 tst_active.last_finished_pass 7350 FROM tst_pass_result 7351 INNER JOIN tst_active 7352 on tst_pass_result.active_fi = tst_active.active_id 7353 WHERE active_fi = %s 7357 $result = $this->db->queryF(
7359 [
'integer',
'integer'],
7363 $test_pass_result_row = $this->db->fetchAssoc($result);
7365 if (!is_array($test_pass_result_row)) {
7366 $test_pass_result_row = [];
7368 $max = (float) ($test_pass_result_row[
'maxpoints'] ?? 0);
7369 $reached = (float) ($test_pass_result_row[
'points'] ?? 0);
7370 $percentage = ($max <= 0.0 || $reached <= 0.0) ? 0 : ($reached / $max) * 100.0;
7372 $mark = $this->
getMarkSchema()->getMatchingMark($percentage);
7373 $is_passed = $pass <= $test_pass_result_row[
'last_finished_pass'] && $mark->getPassed();
7375 $hint_count = $test_pass_result_row[
'hint_count'] ?? 0;
7376 $hint_points = $test_pass_result_row[
'hint_points'] ?? 0.0;
7378 $user_test_result_update_callback =
function () use ($active_id, $pass, $max, $reached, $is_passed, $hint_count, $hint_points, $mark) {
7379 $passed_once_before = 0;
7380 $query =
'SELECT passed_once FROM tst_result_cache WHERE active_fi = %s';
7381 $res = $this->db->queryF($query, [
'integer'], [$active_id]);
7382 while ($passed_once_result_row = $this->db->fetchAssoc(
$res)) {
7383 $passed_once_before = (
int) $passed_once_result_row[
'passed_once'];
7386 $passed_once = (
int) ($is_passed || $passed_once_before);
7388 $this->db->manipulateF(
7389 'DELETE FROM tst_result_cache WHERE active_fi = %s',
7394 if ($reached < 0.0) {
7398 $mark_short_name = $mark->getShortName();
7399 if ($mark_short_name ===
'') {
7400 $mark_short_name =
' ';
7403 $mark_official_name = $mark->getOfficialName();
7404 if ($mark_official_name ===
'') {
7405 $mark_official_name =
' ';
7411 'active_fi' => [
'integer', $active_id],
7412 'pass' => [
'integer', $pass ?? 0],
7413 'max_points' => [
'float', $max],
7414 'reached_points' => [
'float', $reached],
7415 'mark_short' => [
'text', $mark_short_name],
7416 'mark_official' => [
'text', $mark_official_name],
7417 'passed_once' => [
'integer', $passed_once],
7418 'passed' => [
'integer', (
int) $is_passed],
7419 'failed' => [
'integer', (
int) !$is_passed],
7420 'tstamp' => [
'integer', time()],
7421 'hint_count' => [
'integer', $hint_count],
7422 'hint_points' => [
'float', $hint_points]
7427 if (is_object($process_locker)) {
7428 $process_locker->executeUserTestResultUpdateLockOperation($user_test_result_update_callback);
7430 $user_test_result_update_callback();
7439 ?
int $test_obj_id =
null 7444 $result = $this->db->queryF(
7446 SELECT SUM(points) reachedpoints, 7447 SUM(hint_count) hint_count, 7448 SUM(hint_points) hint_points, 7449 COUNT(DISTINCT(question_fi)) answeredquestions 7450 FROM tst_test_result 7451 WHERE active_fi = %s 7454 [
'integer',
'integer'],
7458 if ($result->numRows() > 0) {
7459 $row = $this->db->fetchAssoc($result);
7461 if ($row[
'reachedpoints'] ===
null 7462 || $row[
'reachedpoints'] < 0.0) {
7463 $row[
'reachedpoints'] = 0.0;
7465 if ($row[
'hint_count'] ===
null) {
7466 $row[
'hint_count'] = 0;
7468 if ($row[
'hint_points'] ===
null) {
7469 $row[
'hint_points'] = 0.0;
7474 $update_pass_result_callback =
function () use (
$data, $active_id, $pass, $row, $time, $exam_identifier) {
7478 'active_fi' => [
'integer', $active_id],
7479 'pass' => [
'integer', $pass]
7482 'points' => [
'float', $row[
'reachedpoints']],
7483 'maxpoints' => [
'float',
$data[
'points']],
7484 'questioncount' => [
'integer',
$data[
'count']],
7485 'answeredquestions' => [
'integer', $row[
'answeredquestions']],
7486 'workingtime' => [
'integer', $time],
7487 'tstamp' => [
'integer', time()],
7488 'hint_count' => [
'integer', $row[
'hint_count']],
7489 'hint_points' => [
'float', $row[
'hint_points']],
7490 'exam_id' => [
'text', $exam_identifier]
7496 $process_locker->executeUserPassResultUpdateLockOperation($update_pass_result_callback);
7498 $update_pass_result_callback();
7505 'active_fi' => $active_id,
7507 'points' => $row[
'reachedpoints'],
7508 'maxpoints' =>
$data[
'points'],
7509 'questioncount' =>
$data[
'count'],
7510 'answeredquestions' => $row[
'answeredquestions'],
7511 'workingtime' => $time,
7513 'hint_count' => $row[
'hint_count'],
7514 'hint_points' => $row[
'hint_points'],
7515 'exam_id' => $exam_identifier
7520 bool $old_online_status,
7521 bool $new_online_status
7523 if (!$old_online_status && $new_online_status) {
7525 $newsItem->setContext($this->
getId(),
'tst');
7527 $newsItem->setTitle(
'new_test_online');
7528 $newsItem->setContentIsLangVar(
true);
7529 $newsItem->setContent(
'');
7530 $newsItem->setUserId($this->
user->getId());
7532 $newsItem->create();
7536 if ($old_online_status && !$new_online_status) {
7542 if (!$new_online_status && $newsId > 0) {
7544 $newsItem->setTitle(
'new_test_online');
7545 $newsItem->setContentIsLangVar(
true);
7546 $newsItem->setContent(
'');
7547 $newsItem->update();
7558 $query =
'SELECT question_set_type FROM tst_tests WHERE obj_fi = %s';
7560 $res = $DIC[
'ilDB']->queryF($query, [
'integer'], [$obj_id]);
7562 $question_set_type =
null;
7564 while ($row = $DIC[
'ilDB']->fetchAssoc(
$res)) {
7565 $question_set_type = $row[
'question_set_type'];
7568 return $question_set_type === self::QUESTION_SET_TYPE_RANDOM;
7573 return $this->participant_repository->getFirstAndLastVisitForActiveId($active_id);
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...
isShowGradingMarkEnabled()
static isParticipantsLastPassActive(int $test_ref_id, int $user_id)
replaceFilesInPageImports(string $text, array $mappings)
addConcludingRemarksToSettingsFromImport(SettingsFinishing $settings, array $material, string $importdir, array $mappings)
withGamificationSettings(SettingsGamification $settings)
setQuestionSetType(string $question_set_type)
& getWorkedQuestions($active_id, $pass=null)
Gets the id's of all questions a user already worked through.
isNextPassAllowed(ilTestPassesSelector $testPassesSelector, int &$next_pass_allowed_timestamp)
getListOfQuestionsDescription()
raiseError(string $a_msg, int $a_err_obj)
wrapper for downward compability
static get(string $a_var)
buildStatisticsAccessFilteredParticipantList()
getTimeExtensionsOfParticipants()
isHTML($a_text)
Checks if a given string contains HTML or not.
static getStyleSheetLocation(string $mode="output", string $a_css_name="")
get full style sheet file name (path inclusive) of current user
static completeMissingPluginName(array $question_type_data)
isBlockPassesAfterPassedEnabled()
isTestFinished($active_id)
returns if the active for user_id has been submitted
MainSettingsRepository $main_settings_repo
getExtraTime(int $active_id)
Readable part of repository interface to ilComponentDataDB.
getActivationVisibility()
getHighscoreOwnTable()
Gets if the own rankings table should be shown.
int $activation_starting_time
getHighscoreTopNum(int $a_retval=10)
Gets the number of entries which are to be shown in the top-rankings table.
exportFileItems($target_dir, &$expLog)
export files of file itmes
TestAdministrationInteractionTypes
static _getObjectIDFromTestID($test_id)
Returns the ILIAS test object id for a given test id.
A class defining mark schemas for assessment test objects.
deliverPDFfromFO($fo, $title=null)
Delivers a PDF file from a XSL-FO string.
isComplete(ilTestQuestionSetConfig $test_question_set_config)
storePropertyIsOnline(ilObjectPropertyIsOnline $property_is_online)
ilComponentRepository $component_repository
static _getPass($active_id)
Retrieves the actual pass of a given user for a given test.
exportXMLPageObjects(&$a_xml_writer, $inst, &$expLog)
export page objects to xml (see ilias_co.dtd)
getUnfilteredEvaluationData()
isShowExamIdInTestPassEnabled()
processPrintoutput2FO($print_output)
Convert a print output to XSL-FO.
static deleteNewsOfContext(int $a_context_obj_id, string $a_context_obj_type, int $a_context_sub_obj_id=0, string $a_context_sub_obj_type="")
Delete all news of a context.
applyDefaults(array $test_defaults)
getTestBehaviourSettings()
txt(string $a_topic, string $a_default_lang_fallback_mod="")
gets the text for a given topic if the topic is not in the list, the topic itself with "-" will be re...
updateTestPassResults(int $active_id, int $pass, ?ilAssQuestionProcessLocker $process_locker=null, ?int $test_obj_id=null)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
getEnableProcessingTime()
const QUESTION_SET_TYPE_RANDOM
static _getSuggestedSolutionOutput(int $question_id)
getListOfQuestionsStart()
MarksRepository $marks_repository
Skill management settings.
A class defining marks for assessment test objects.
getCompleteWorkingTimeOfParticipant($active_id)
Returns the complete working time in seconds for a test participant.
This class handles all operations on files (attachments) in directory ilias_data/mail.
setActivationStartingTime(?int $starting_time=null)
qtiMaterialToArray($a_material)
Reads an QTI material tag and creates a text string.
TestManScoringDoneHelper $test_man_scoring_done_helper
if(! $DIC->user() ->getId()||!ilLTIConsumerAccess::hasCustomProviderCreationAccess()) $params
getShowSolutionListOwnAnswers()
getPresentationMaterial()
getShowSolutionFeedback()
Returns if the feedback should be presented to the solution or not.
removeTestResults(ilTestParticipantData $participant_data)
static lookupPassResultsUpdateTimestamp($active_id, $pass)
& getExistingQuestions($pass=null)
Get the id's of the questions which are already part of the test.
bool $print_best_solution_with_result
isExecutable($test_session, $user_id, $allow_pass_increase=false)
Checks if the test is executable by the given user.
loadQuestions(int $active_id=0, ?int $pass=null)
Load the test question id's from the database.
getShowKioskModeParticipant()
static $isSkillManagementGloballyActivated
buildDateTimeImmutableFromPeriod(?string $period)
getQuestionSetTypeTranslation(ilLanguage $lng, $questionSetType)
saveCompleteStatus(ilTestQuestionSetConfig $test_question_set_config)
getHighscoreAchievedTS()
Returns if date and time of the scores achievement should be displayed.
getTestId()
Gets the database id of the additional test data.
moveQuestions(array $move_questions, int $target_index, int $insert_mode)
static factory(string $a_package, int $a_timeout=0)
Creates an ilRpcClient instance to our ilServer.
Class ilTestMailNotification.
trait TestQuestionsImportTrait
getListOfQuestionsSettings()
Returns the settings for the list of questions options in the test properties This could contain one ...
createQuestionGUI($question_type, $question_id=-1)
Creates a question GUI instance of a given question type.
TestLogViewer $log_viewer
getMailNotificationType()
getJavaScriptOutput()
Returns if Javascript should be chosen for drag & drop actions for the active user.
const TIMINGS_DEACTIVATED
getShowSolutionAnswersOnly()
Returns if the full solution (including ILIAS content) should be presented to the solution or not...
static _lookupName(int $a_user_id)
lookup user name
& createTestSequence($active_id, $pass, $shuffle)
getQuestionTitle($title, $nr=null, $points=null)
Returns the title of a test question and checks if the title output is allowed.
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
$test_sequence
contains the test sequence data
getXMLZip()
Get zipped xml file for test.
inviteUser($user_id, $client_ip="")
Invites a user to a test.
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.
evalTotalPersonsArray(string $name_sort_order='asc')
TestScoringInteractionTypes
& getInvitedUsers(int $user_id=0, $order="login, lastname, firstname")
Returns a list of all invited users in a test.
ParticipantRepository $participant_repository
toXML()
Returns a QTI xml representation of the test.
getAlwaysSendMailNotification()
GlobalSettingsRepository $global_settings_repo
setTemplate(int $template_id)
setActivationLimited($a_value)
static isManScoringDone(int $active_id)
setActivationEndingTime(?int $ending_time=null)
setTestId($a_id)
Sets the test ID.
getUsrPassOverviewEnabled()
static _lookupRandomTest(int $obj_id)
isShowExamIdInTestResultsEnabled()
getProcessingTimeInSeconds(int $active_id=0)
static deliverData(string $a_data, string $a_filename, string $mime="application/octet-stream")
getCompleteWorkingTime($user_id)
Returns the complete working time in seconds a user worked on the test.
getQuestionsOfPass(int $active_id, int $pass)
getImagePathWeb()
Returns the web image path for web accessable images of a test The image path is under the web access...
startingTimeReached()
Returns true if the starting time of a test is reached A starting time is not available for self asse...
questionMoveDown($question_id)
Moves a question down in order.
getHighscoreWTime()
Gets if the column with the workingtime should be shown.
getResultDetailsSettings()
hasAnyTestResult(ilTestSession $test_session)
getActiveIdOfUser($user_id="", $anonymous_id="")
Gets the active id of a given user.
static _getObjectIDFromActiveID($active_id)
Returns the ILIAS test object id for a given active id.
$participantDataExist
holds the fact wether participant data exists or not DO NOT USE TIS PROPERTY DRIRECTLY ALWAYS USE ilO...
getActiveParticipantList()
static _isPassed($user_id, $a_obj_id)
Returns TRUE if the user with the user id $user_id passed the test with the object id $a_obj_id...
buildName(?int $user_id, ?string $firstname, ?string $lastname)
Builds a user name for the output depending on test type and existence of the user.
static _getBestPass($active_id)
Retrieves the best pass of a given user for a given test.
evalTotalStartedAverageTime(?array $active_ids_to_filter=null)
saveToDb(bool $properties_only=false)
static _lookupTestObjIdForQuestionId(int $q_id)
Get test Object ID for question ID.
withGeneralSettings(SettingsGeneral $settings)
static _lookupAnonymity($a_obj_id)
getTestResult(int $active_id, ?int $pass=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...
sort()
description: > Example for rendering a Sort Glyph.
getPotentialRandomTestQuestions()
getShowSolutionListComparison()
setQuestionSetSolved($value, $question_id, $user_id)
sets question solved state to value for given user_id
Base Exception for all Exceptions relating to Modules/Test.
getHighscoreTopTable()
Gets, if the top-rankings table should be shown.
lookupQuestionSetTypeByActiveId(int $active_id)
getQuestionsOfTest(int $active_id)
startWorkingTime($active_id, $pass)
Write the initial entry for the tests working time to the database.
static removeTrailingPathSeparators(string $path)
removeAllQuestionResults($question_id)
$evaluation_data
Contains the evaluation data settings the tutor defines for the user.
static _lookupObjId(int $ref_id)
static _instanciateQuestion($question_id)
Creates an instance of a question with a given question id.
setQuestionOrder(array $order)
& _getCompleteWorkingTimeOfParticipants($test_id)
Returns the complete working time in seconds for all test participants.
isRandomTest()
Returns the fact wether this test is a random questions test or not.
static getASCIIFilename(string $a_filename)
getHighscorePercentage()
Gets if the percentage column should be shown.
xmlEndTag(string $tag)
Writes an endtag.
isFixedTest()
Returns the fact wether this test is a fixed question set test or not.
while($session_entry=$r->fetchRow(ilDBConstants::FETCHMODE_ASSOC)) return null
static _getUserIdFromActiveId(int $active_id)
updateWorkingTime($times_id)
Update the working time of a test when a question is answered.
getFixedQuestionSetTotalPoints()
secondsToHoursMinutesSecondsString(int $seconds)
getHtmlQuestionContentPurifier()
ExportImportFactory $export_factory
ilTestParticipantList $access_filtered_participant_list
getSpecificAnswerFeedback()
getImportMapping()
get array of (two) new created questions for import id
static _getMaxPass($active_id)
Retrieves the maximum pass of a given user for a given test in which the user answered at least one q...
addDefaults($a_name)
Adds the defaults of this test to the test defaults.
cloneObject(int $target_id, int $copy_id=0, bool $omit_tree=false)
Clone object.
removeTestResultsByUserIds(array $user_ids)
static collectFileItems(ilPageObject $a_page, DOMDocument $a_domdoc)
Get all file items that are used within the page.
static instantiateQuestion(int $question_id)
$metadata
A reference to an IMS compatible matadata set.
checkQuestionParent(int $question_id)
Interface for html sanitizing functionality.
evalStatistical($active_id)
Returns the statistical evaluation of the test for a specified user.
removeQuestionWithResults(int $question_id, TestScoring $scoring)
static getSingleManualFeedback(int $active_id, int $question_id, int $pass)
getGamificationSettings()
getHighscoreHints()
Gets, if the column with the number of requested hints should be shown.
getTotalPointsPassedArray()
Returns an array with the total points of all users who passed the test This array could be used for ...
cloneMetaData(ilObject $target_obj)
Copy meta data.
getAccessFilteredParticipantList()
getVisitingTimeOfParticipant(int $active_id)
getQuestiontext($question_id)
Returns the question text for a given question.
replaceMobsInPageImports(string $text, array $mappings)
static _lookupTitle(int $obj_id)
getAllQuestions($pass=null)
Returns all questions of a test in test order.
getHighscoreAnon()
Gets if the highscores should be anonymized per setting.
sendAdvancedNotification(int $active_id)
getTestParticipantsForManualScoring($filter=null)
fromXML(ilQTIAssessment $assessment, array $mappings)
Receives parameters from a QTI parser and creates a valid ILIAS test object.
storeMarkSchema(MarkSchema $mark_schema)
static _prepareCloneSelection(array $ref_ids, string $new_type, bool $show_path=true)
Prepare copy wizard object selection.
setActivationVisibility($a_value)
hasQuestionsWithoutQuestionpool()
evalTotalPersons()
Returns the number of persons who started the test.
retrieveMobsFromLegacyImports(string $text, array $mobs, string $importdir)
getStartingTimeOfUser($active_id, $pass=null)
Returns the unix timestamp of the time a user started a test.
sendSimpleNotification($active_id)
getShowSolutionPrintview()
Returns if the solution printview should be presented to the user or not.
hasNrOfTriesRestriction()
returns if the numbers of tries have to be checked
getAuthor()
Gets the authors name of the ilObjTest object.
static _getResultPass($active_id)
Retrieves the pass number that should be counted for a given user.
getTestDefaults($test_defaults_id)
getShowPassDetails()
Returns if the pass details should be shown when a test is not finished.
ilTestPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI ilTestPageGUI: ilPublicUserProfile...
removeQuestion(int $question_id)
isTestFinishedToViewResults($active_id, $currentpass)
Returns true if an active user completed a test pass and did not start a new pass.
getUserData($ids)
Returns a data of all users specified by id list.
questionMoveUp($question_id)
Moves a question up in order.
static delDir(string $a_dir, bool $a_clean_only=false)
removes a dir and all its content (subdirs and files) recursively
MainSettings $main_settings
static getInstanceByRefId(int $ref_id, bool $stop_on_error=true)
get an instance of an Ilias object by reference id
static _getSolutionMaxPass(int $question_id, int $active_id)
Returns the maximum pass a users question solution.
getShowSolutionSuggested()
isSkillServiceToBeConsidered()
Returns whether this test must consider skills, usually by providing appropriate extensions in the us...
static _getCountSystem($active_id)
static _getSolvedQuestions($active_id, $question_fi=null)
get solved questions
getResultsForActiveId(int $active_id)
static createDirectory(string $a_dir, int $a_mod=0755)
create directory
ilTestEditPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI ilTestEditPageGUI: ilPublicUse...
isOfferingQuestionHintsEnabled()
static _refreshStatus(int $a_obj_id, ?array $a_users=null)
Filesystem $filesystem_web
exportXMLMediaObjects(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export media objects to xml (see ilias_co.dtd)
Class ilObjForumAdministration.
getAnsweredQuestionCount($active_id, $pass=null)
Retrieves the number of answered questions for a given user in a given test.
getAvailableDefaults()
Returns the available test defaults for the active user.
withIntroductionPageId(?int $introduction_page_id)
convertTimeToDateTimeImmutableIfNecessary(DateTimeImmutable|int|null $date_time)
static getInstanceByType(string $type)
static isSkillManagementGloballyActivated()
getAnswerFeedbackPoints()
canShowTestResults(ilTestSession $test_session)
createExportDirectory()
creates data directory for export files (data_dir/tst_data/tst_<id>/export, depending on data directo...
getAggregatedResultsData()
static _lookupAuthor($obj_id)
Gets the authors name of the ilObjTest object.
static _getObjectsByOperations( $a_obj_type, string $a_operation, int $a_usr_id=0, int $limit=0)
Get all objects of a specific type and check access This function is not recursive, instead it parses the serialized rbac_pa entries.
removeTestActives(array $active_ids)
copyQuestions(array $question_ids)
getStartingTimeOfParticipants()
Note, this function should only be used if absolutely necessary, since it perform joins on tables tha...
RequestDataCollector $testrequest
static getDataDir()
get data directory (outside webspace)
getLastFinishedPassTimestamp()
getResultSummarySettings()
getShowSolutionSignature()
Returns if the signature field should be shown in the test results.
static _lookupFinishedUserTests($a_user_id)
Gather all finished tests for user.
pcArrayShuffle($array)
Shuffles the values of a given array.
ilTestQuestionSetConfigFactory $question_set_config_factory
getMainSettingsRepository()
getCompleteEvaluationData($filterby='', $filtertext='')
static _lookupDescription(int $obj_id)
This file is part of ILIAS, a powerful learning management system published by ILIAS open source e-Le...
static _getTestIDFromObjectID($object_id)
Returns the ILIAS test id for a given object id.
getInstantFeedbackSolution()
getAllTestResults($participants)
returns all test results for all participants
removeQuestionsWithResults(array $question_ids)
isHighscoreAnon()
Gets if the highscores should be displayed anonymized.
isInstantFeedbackAnswerFixationEnabled()
prepareTextareaOutput($txt_output, $prepare_for_latex_output=false, $omitNl2BrWhenTextArea=false)
Prepares a string for a text area output in tests.
storeActivationSettings(?bool $is_activation_limited=false, ?int $activation_starting_time=null, ?int $activation_ending_time=null, bool $activation_visibility=false,)
static _createImportDirectory()
creates data directory for import files (data_dir/tst_data/tst_<id>/import, depending on data directo...
buildImportDirectoryFromImportFile(string $file_to_import)
getProcessingTimeForXML()
updatePassAndTestResults(array $active_ids)
duplicateQuestionForTest($question_id)
Takes a question and creates a copy of the question for use in the test.
addIntroductionToSettingsFromImport(SettingsIntroduction $settings, array $material, string $importdir, array $mappings)
evalTotalParticipantsArray(string $name_sort_order='asc')
isScoreReportingEnabled()
getAvailableQuestions($arr_filter, $completeonly=0)
Calculates the available questions for a test.
isForceInstantFeedbackEnabled()
getQuestionDataset($question_id)
Returns the dataset for a given question id.
static ilTempnam(?string $a_temp_path=null)
Returns a unique and non existing Path for e temporary file or directory.
updateTestResultCache(int $active_id, ?ilAssQuestionProcessLocker $process_locker=null)
withConcludingRemarksPageId(?int $concluding_remarks_page_id)
ilObjectProperties $object_properties
removeQuestions(array $question_ids)
getParticipantFunctionalitySettings()
removeTestResultsByActiveIds(array $active_ids)
A news item can be created by different sources.
getGenericAnswerFeedback()
static _getScoreCutting(int $active_id)
Determines if the score of a question should be cut at 0 points or the score of the whole test...
removeQuestionFromSequences(int $question_id, array $active_ids, ilTestReindexedSequencePositionMap $reindexed_sequence_position_map)
addToNewsOnOnline(bool $old_online_status, bool $new_online_status)
static getItem(int $ref_id)
buildIso8601PeriodForExportCompatibility(DateTimeImmutable $date_time)
isQuestionSetConfigured()
getActivationStartingTime()
int $activation_ending_time
getTextAnswer($active_id, $question_id, $pass=null)
Returns the text answer of a given user for a given question.
getScoreCutting()
Determines if the score of a question should be cut at 0 points or the score of the whole test...
getTitleFilenameCompliant()
returns the object title prepared to be used as a filename
bool $activation_visibility
getParticipantsForTestAndQuestion($test_id, $question_id)
Creates an associated array with all active id's for a given test and original question id...
setTmpCopyWizardCopyId(int $tmpCopyWizardCopyId)
static _getAvailableTests($use_object_id=false)
Returns the available tests for the active user.
$id
plugin.php for ilComponentBuildPluginInfoObjectiveTest::testAddPlugins
__construct(Container $dic, ilPlugin $plugin)
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.
getQuestionCountAndPointsForPassOfParticipant(int $active_id, int $pass)
exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog)
export pages of test to xml (see ilias_co.dtd)
recalculateScores($preserve_manscoring=false)
clonePage(int $source_page_id)
getMailNotificationContentType()
ScoreSettings $score_settings
ScoreSettingsRepository $score_settings_repo
deleteDefaults($test_default_id)
endingTimeReached()
Returns true if the ending time of a test is reached An ending time is not available for self assessm...
getGeneralQuestionPropertiesRepository()
getActivationEndingTime()
getCompleteManualFeedback(int $question_id)
Retrieves the manual feedback for a question in a test.
static formatDate(ilDateTime $date, bool $a_skip_day=false, bool $a_include_wd=false, bool $include_seconds=false, ?ilObjUser $user=null,)
getParticipants()
Returns all persons who started the test.
const QUESTION_SET_TYPE_FIXED
getConcludingRemarksPageId()
isActiveTestSubmitted($user_id=null)
returns if the active for user_id has been submitted
modifyExportIdentifier($a_tag, $a_param, $a_value)
Returns the installation id for a given identifier.
getQuestionTitlesAndIndexes()
Returns the titles of the test questions in question sequence.
getIntroductionSettings()
getQuestionType($question_id)
Returns the question type of a question with a given id.
static buildExamId($active_id, $pass, $test_obj_id=null)
xmlStartTag(string $tag, ?array $attrs=null, bool $empty=false, bool $encode=true, bool $escape=true)
Writes a starttag.
GeneralQuestionPropertiesRepository $questionrepository
isTestQuestion(int $question_id)
static _getPassScoring(int $active_id)
Gets the pass scoring type.
& getCompleteWorkingTimeOfParticipants()
Returns the complete working time in seconds for all test participants.
getNrOfResultsForPass($active_id, $pass)
Calculates the number of user results for a specific test pass.
getQuestionBehaviourSettings()
ilComponentFactory $component_factory
addQTIMaterial(ilXmlWriter &$xml_writer, ?int $page_id, string $material='')
xmlElement(string $tag, $attrs=null, $data=null, $encode=true, $escape=true)
Writes a basic element (no children, just textual content)
isShowGradingStatusEnabled()
canShowSolutionPrintview($user_id=null)
getQuestionCountWithoutReloading()
getHighscoreScore()
Gets if the score column should be shown.
static getTestObjIdsWithActiveForUserId($userId)
isPluginActive($a_pname)
Checks wheather or not a question plugin with a given name is active.
isFollowupQuestionAnswerFixationEnabled()
saveManualFeedback(int $active_id, int $question_id, int $pass, ?string $feedback, bool $finalized=false)
saveAuthorToMetadata($author="")
Saves an authors name into the lifecycle metadata if no lifecycle metadata exists This will only be c...
static getManualFeedback(int $active_id, int $question_id, ?int $pass)
Retrieves the feedback comment for a question in a test if it is finalized.
getScoreSettingsRepository()
static insertInstIntoID(string $a_value)
inserts installation id into ILIAS id
getWorkingTimeOfParticipantForPass(int $active_id, int $pass)
deliverPDFfromHTML($content, $title=null)
Delivers a PDF file from XHTML.
getDetailedTestResults($participants)
returns all test results for all participants
static getInstance(int $obj_id)
static clear(string $a_var)
isNrOfTriesReached($tries)
returns if number of tries are reached
Class ilObjectActivation.
_getLastAccess(int $active_id)
setAccessFilteredParticipantList(ilTestParticipantList $access_filtered_participant_list)
static deleteRequestsByActiveIds($activeIds)
Deletes all hint requests relating to a testactive included in given active ids.
insertManualFeedback(int $active_id, int $question_id, int $pass, ?string $feedback, bool $finalized, array $feedback_old)
insertQuestion(int $question_id, bool $link_only=false)
reindexFixedQuestionOrdering()
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.
ilTestParticipantAccessFilterFactory $participant_access_filter
withScoringSettings(SettingsScoring $settings)
userLookupFullName($user_id, $overwrite_anonymity=false, $sorted_order=false, $suffix="")
Returns the full name of a test user according to the anonymity status.
static _getActiveIdOfUser($user_id="", $test_id="")
static makeDir(string $a_dir)
creates a new directory and inherits all filesystem permissions of the parent directory You may pass ...
isMaxProcessingTimeReached(int $starting_time, int $active_id)
Returns whether the maximum processing time for a test is reached or not.
static _updateStatus(int $a_obj_id, int $a_usr_id, ?object $a_obj=null, bool $a_percentage=false, bool $a_force_raise=false)
isPreviousSolutionReuseEnabled($active_id)
getUserIdByActiveId($activeId)
getImagePath()
Returns the image path for web accessable images of a test The image path is under the CLIENT_WEB_DIR...
static lookupExamId($active_id, $pass)
removeTestResultsFromSoapLpAdministration(array $user_ids)
getPassScoring()
Gets the pass scoring type.