19 declare(strict_types=1);
159 public function __construct(
int $id = 0,
bool $a_call_by_reference =
true)
165 $this->
ctrl = $DIC[
'ilCtrl'];
167 $this->
settings = $DIC[
'ilSetting'];
168 $this->bench = $DIC[
'ilBench'];
169 $this->component_repository = $DIC[
'component.repository'];
170 $this->component_factory = $DIC[
'component.factory'];
171 $this->filesystem_web = $DIC->filesystem()->web();
172 $this->lo_metadata = $DIC->learningObjectMetadata();
175 $this->participant_access_filter = $local_dic[
'participant.access_filter.factory'];
176 $this->test_man_scoring_done_helper = $local_dic[
'scoring.manual.done_helper'];
177 $this->
logger = $local_dic[
'logging.logger'];
178 $this->log_viewer = $local_dic[
'logging.viewer'];
179 $this->global_settings_repo = $local_dic[
'settings.global.repository'];
180 $this->marks_repository = $local_dic[
'marks.repository'];
181 $this->questionrepository = $local_dic[
'question.general_properties.repository'];
182 $this->testrequest = $local_dic[
'request_data_collector'];
183 $this->participant_repository = $local_dic[
'participant.repository'];
184 $this->export_factory = $local_dic[
'exportimport.factory'];
185 $this->test_result_repository = $local_dic[
'results.data.repository'];
189 $this->
lng->loadLanguageModule(
"assessment");
190 $this->score_settings =
null;
197 $this->component_repository,
199 $this->questionrepository
205 return TestDIC::dic();
220 return $this->question_set_config_factory->getQuestionSetConfig();
243 $id = parent::create();
250 if (!parent::update()) {
262 $this->main_settings =
null;
263 $this->score_settings =
null;
264 $this->mark_schema =
null;
268 public function delete():
bool 271 if (!parent::delete()) {
282 $qsaImportFails->deleteRegisteredImportFails();
284 $sltImportFails->deleteRegisteredImportFails();
286 if ($this->
logger->isLoggingEnabled()) {
287 $this->
logger->logTestAdministrationInteraction(
288 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
290 $this->
user->getId(),
293 AdditionalInformationGenerator::KEY_TEST_TITLE => $test_title =
$this->title 305 $participantData->load($this->
getTestId());
308 $this->db->manipulateF(
309 "DELETE FROM tst_mark WHERE test_fi = %s",
314 $this->db->manipulateF(
315 "DELETE FROM tst_tests WHERE test_id = %s",
321 $directory = $tst_data_dir .
"/tst_" . $this->
getId();
322 if (is_dir($directory)) {
330 foreach ($mobs as $mob) {
348 if (!is_writable($tst_data_dir)) {
349 $this->
ilias->raiseError(
"Test Data Directory (" . $tst_data_dir
350 .
") not writeable.", $this->
ilias->error_obj->MESSAGE);
354 $tst_dir = $tst_data_dir .
"/tst_" . $this->
getId();
356 if (!@is_dir($tst_dir)) {
357 $this->
ilias->raiseError(
"Creation of Test Directory failed.", $this->
ilias->error_obj->MESSAGE);
360 $export_dir = $tst_dir .
"/export";
362 if (!@is_dir($export_dir)) {
363 $this->
ilias->raiseError(
"Creation of Export Directory failed.", $this->
ilias->error_obj->MESSAGE);
373 public function getExportFiles(
string $dir =
''): array
376 if (!@is_dir($dir) || !is_writable($dir)) {
385 if ($file->isDir()) {
389 $files[] = $file->getBasename();
409 if (!is_writable($tst_data_dir)) {
411 .
") not writeable.",
$ilias->error_obj->FATAL);
415 $tst_dir = $tst_data_dir .
"/tst_import";
417 if (!@is_dir($tst_dir)) {
444 if ($this->
isComplete($test_question_set_config)) {
448 $this->db->manipulateF(
449 'UPDATE tst_tests SET complete = %s WHERE test_id = %s',
451 [$complete, $this->test_id]
456 public function saveToDb(
bool $properties_only =
false): void
458 if ($this->test_id === -1) {
460 $next_id = $this->db->nextId(
'tst_tests');
465 'test_id' => [
'integer', $next_id],
466 'obj_fi' => [
'integer', $this->
getId()],
467 'created' => [
'integer', time()],
468 'tstamp' => [
'integer', time()],
473 $this->test_id = $next_id;
479 $aresult = $this->db->queryF(
480 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries >= %s AND submitted = %s",
481 [
'integer',
'integer',
'integer'],
484 while ($row = $this->db->fetchAssoc($aresult)) {
485 $this->db->manipulateF(
486 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
487 [
'integer',
'timestamp',
'integer'],
488 [1, date(
'Y-m-d H:i:s'), $row[
"active_id"]]
493 $aresult = $this->db->queryF(
494 "SELECT active_id FROM tst_active WHERE test_fi = %s AND tries < %s AND submitted = %s",
495 [
'integer',
'integer',
'integer'],
498 while ($row = $this->db->fetchAssoc($aresult)) {
499 $this->db->manipulateF(
500 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
501 [
'integer',
'timestamp',
'integer'],
502 [0,
null, $row[
"active_id"]]
507 $aresult = $this->db->queryF(
508 "SELECT active_id FROM tst_active WHERE test_fi = %s AND submitted = %s",
509 [
'integer',
'integer'],
512 while ($row = $this->db->fetchAssoc($aresult)) {
513 $this->db->manipulateF(
514 "UPDATE tst_active SET submitted = %s, submittimestamp = %s WHERE active_id = %s",
515 [
'integer',
'timestamp',
'integer'],
516 [0,
null, $row[
"active_id"]]
530 if ($properties_only) {
538 $this->marks_repository->storeMarkSchema($this->
getMarkSchema());
543 $this->db->manipulateF(
544 'DELETE FROM tst_test_question WHERE test_fi = %s',
548 foreach ($this->questions as $key => $value) {
549 $next_id = $this->db->nextId(
'tst_test_question');
550 $this->db->insert(
'tst_test_question', [
551 'test_question_id' => [
'integer', $next_id],
552 'test_fi' => [
'integer', $this->
getTestId()],
553 'question_fi' => [
'integer', $value],
554 'sequence' => [
'integer', $key],
555 'tstamp' => [
'integer', time()]
568 foreach ($question_ids as
$id) {
569 $question = assQuestion::instantiateQuestionGUI($id);
571 $title = $question->getObject()->getTitle();
573 while (in_array(
$title .
' (' . $i .
')', $question_titles)) {
577 $title .=
' (' . $i .
')';
579 $question_titles[] =
$title;
581 $new_id = $question->getObject()->duplicate(
false,
$title);
583 $clone = assQuestion::instantiateQuestionGUI($new_id);
584 $question = $clone->getObject();
585 $question->setObjId($this->
getId());
586 $clone->setObject($question);
587 $clone->getObject()->saveToDb();
601 $result = $this->db->queryF(
602 "SELECT test_result_id FROM tst_test_result WHERE active_fi = %s AND pass = %s",
603 [
'integer',
'integer'],
606 return $result->numRows();
611 $result = $this->db->queryF(
612 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
616 if ($result->numRows() === 1) {
617 $data = $this->db->fetchObject($result);
623 if (isset($this->ref_id)) {
625 switch ($activation[
"timing_type"]) {
646 $this->questions = [];
648 if ($active_id === 0) {
651 if (is_null($pass)) {
652 $pass = self::_getPass($active_id);
654 $result = $this->db->queryF(
655 'SELECT tst_test_rnd_qst.* ' 656 .
'FROM tst_test_rnd_qst, qpl_questions ' 657 .
'WHERE tst_test_rnd_qst.active_fi = %s ' 658 .
'AND qpl_questions.question_id = tst_test_rnd_qst.question_fi ' 659 .
'AND tst_test_rnd_qst.pass = %s ' 660 .
'ORDER BY sequence',
661 [
'integer',
'integer'],
665 $result = $this->db->queryF(
666 'SELECT tst_test_question.* ' 667 .
'FROM tst_test_question, qpl_questions ' 668 .
'WHERE tst_test_question.test_fi = %s ' 669 .
'AND qpl_questions.question_id = tst_test_question.question_fi ' 670 .
'ORDER BY sequence',
676 if ($this->test_id !== -1) {
678 while (
$data = $this->db->fetchAssoc($result)) {
679 $this->questions[$index++] =
$data[
"question_fi"];
686 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
687 if ($page_id !==
null) {
691 return $this->
getMainSettings()->getIntroductionSettings()->getIntroductionText();
696 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
697 if ($page_id ===
null) {
705 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
706 if ($page_id !==
null) {
709 return $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksText();
714 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
715 if ($page_id ===
null) {
724 $page_object->setParentId($this->
getId());
725 $new_page_id = $page_object->createPageWithNextId();
726 (
new ilTestPage($source_page_id))->copy($new_page_id);
740 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getPostponedQuestionsMoveToEnd();
745 return $this->
getScoreSettings()->getResultSummarySettings()->getScoreReporting()->isReportingEnabled();
750 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackPointsEnabled();
755 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackGenericEnabled();
760 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSolutionEnabled();
771 $ilDB = $DIC[
'ilDB'];
772 $result =
$ilDB->queryF(
773 "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",
777 if ($result->numRows()) {
778 $row =
$ilDB->fetchAssoc($result);
779 return $row[
"count_system"];
806 $ilDB = $DIC[
'ilDB'];
807 $result =
$ilDB->queryF(
808 "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",
812 if ($result->numRows()) {
813 $row =
$ilDB->fetchAssoc($result);
814 return (
int) $row[
"pass_scoring"];
825 $ilDB = $DIC[
'ilDB'];
826 $result =
$ilDB->queryF(
827 "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",
831 if ($result->numRows()) {
832 $row =
$ilDB->fetchAssoc($result);
833 return (
bool) $row[
"score_cutting"];
840 if ($this->mark_schema ===
null) {
841 $this->mark_schema = $this->marks_repository->getMarkSchemaFor($this->
getTestId());
849 $this->marks_repository->storeMarkSchema($mark_schema);
850 $this->mark_schema =
null;
855 return $this->
getMainSettings()->getTestBehaviourSettings()->getNumberOfTries();
860 return $this->
getMainSettings()->getTestBehaviourSettings()->getBlockAfterPassedEnabled();
865 return $this->
getMainSettings()->getTestBehaviourSettings()->getKioskModeEnabled();
870 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowTitleInKioskMode();
874 return $this->
getMainSettings()->getTestBehaviourSettings()->getShowParticipantNameInKioskMode();
879 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsePreviousAnswerAllowed();
884 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getQuestionTitleOutputMode();
889 $result = $this->db->queryF(
890 "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",
894 if ($result->numRows()) {
895 $row = $this->db->fetchAssoc($result);
896 $test_allows_reuse = $row[
"use_previous_answers"];
899 if ($test_allows_reuse ===
'1') {
900 $res = $this->
user->getPref(
"tst_use_previous_answers");
910 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
915 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime();
916 if ($processing_time ===
null 917 || $processing_time ===
'' 918 || !preg_match(
'/(\d{2}):(\d{2}):(\d{2})/is', $processing_time, $matches)
933 $processing_time = $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTime() ??
'';
934 if (preg_match(
"/(\d{2}):(\d{2}):(\d{2})/", (
string) $processing_time, $matches)) {
936 return ($matches[1] * 3600) + ($matches[2] * 60) + $matches[3] + $extratime;
944 return $this->
getMainSettings()->getTestBehaviourSettings()->getProcessingTimeEnabled();
949 return $this->
getMainSettings()->getTestBehaviourSettings()->getResetProcessingTime();
954 return $this->
getMainSettings()->getAccessSettings()->getStartTimeEnabled();
959 $start_time = $this->
getMainSettings()->getAccessSettings()->getStartTime();
960 return $start_time !==
null ? $start_time->getTimestamp() : 0;
965 return $this->
getMainSettings()->getAccessSettings()->getEndTimeEnabled();
970 $end_time = $this->
getMainSettings()->getAccessSettings()->getEndTime();
971 return $end_time !==
null ? $end_time->getTimestamp() : 0;
976 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode();
981 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode() === self::REDIRECT_KIOSK;
986 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionMode() === self::REDIRECT_NONE;
991 return $this->
getMainSettings()->getFinishingSettings()->getRedirectionUrl() ??
'';
996 return $this->
getMainSettings()->getAccessSettings()->getPasswordEnabled();
1010 $this->test_result_repository
1024 $participant_data->load($this->test_id);
1026 $question->removeAllExistingSolutions();
1033 $participant_data->getActiveIds(),
1040 $question->delete($question_id);
1049 if ($this->
logger->isLoggingEnabled()) {
1050 $this->
logger->logTestAdministrationInteraction(
1051 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1053 $this->
user->getId(),
1054 TestAdministrationInteractionTypes::QUESTION_REMOVED_IN_CORRECTIONS,
1056 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question->getTitleForHTMLOutput(),
1057 AdditionalInformationGenerator::KEY_QUESTION_TEXT => $question->getQuestion(),
1058 AdditionalInformationGenerator::KEY_QUESTION_ID => $question->getId(),
1059 AdditionalInformationGenerator::KEY_QUESTION_TYPE => $question->getQuestionType()
1077 $this->questionrepository
1080 foreach ($active_ids as $active_id) {
1082 $passSelector->setActiveId($active_id);
1084 foreach ($passSelector->getExistingPasses() as $pass) {
1085 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $pass);
1088 $test_sequence->removeQuestion($question_id, $reindexed_sequence_position_map);
1099 foreach ($question_ids as $question_id) {
1109 $question = self::_instanciateQuestion($question_id);
1110 $question_title = $question->getTitleForHTMLOutput();
1111 $question->delete($question_id);
1112 if ($this->
logger->isLoggingEnabled()) {
1113 $this->
logger->logTestAdministrationInteraction(
1114 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1116 $this->
user->getId(),
1117 TestAdministrationInteractionTypes::QUESTION_REMOVED,
1119 AdditionalInformationGenerator::KEY_QUESTION_TITLE => $question_title
1125 $this->
logger->error($e->getMessage());
1126 $this->
logger->error($e->getTraceAsString());
1143 $participantData->setUserIdsFilter($user_ids);
1144 $participantData->load($this->
getTestId());
1149 if ($this->
logger->isLoggingEnabled()) {
1150 $this->
logger->logTestAdministrationInteraction(
1151 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1153 $this->
user->getId(),
1154 TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
1156 AdditionalInformationGenerator::KEY_USERS => $participantData->getUserIds()
1172 $this->participant_repository->removeExtraTimeByUserId($this->
getTestId(), $user_ids);
1175 if ($participant_data->
getUserIds() !== []) {
1178 if ($test_lp instanceof
ilTestLP) {
1179 $test_lp->setTestObject($this);
1180 $test_lp->resetLPDataForUserIds($participant_data->
getUserIds(),
false);
1183 $this->participant_repository->removeExtraTimeByUserId($this->
getTestId(), $participant_data->
getUserIds());
1193 $this->participant_repository->removeExtraTimeByUserId($this->
getTestId(), $user_ids);
1196 if ($this->
logger->isLoggingEnabled()) {
1197 $this->
logger->logTestAdministrationInteraction(
1198 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1200 $this->
user->getId(),
1201 TestAdministrationInteractionTypes::PARTICIPANT_DATA_REMOVED,
1203 AdditionalInformationGenerator::KEY_USERS => $participant_data->
getUserIds(),
1214 $participantData->setUserIdsFilter($user_ids);
1215 $participantData->load($this->
getTestId());
1217 $in_user_ids = $this->db->in(
'usr_id', $participantData->getUserIds(),
false,
'integer');
1218 $this->db->manipulateF(
1219 "DELETE FROM usr_pref WHERE {$in_user_ids} AND keyword = %s",
1224 if ($participantData->getActiveIds() !== []) {
1231 $in_active_ids = $this->db->in(
'active_fi', $active_ids,
false,
'integer');
1233 $this->db->manipulate(
"DELETE FROM tst_solutions WHERE {$in_active_ids}");
1234 $this->db->manipulate(
"DELETE FROM tst_qst_solved WHERE {$in_active_ids}");
1235 $this->db->manipulate(
"DELETE FROM tst_test_result WHERE {$in_active_ids}");
1236 $this->db->manipulate(
"DELETE FROM tst_pass_result WHERE {$in_active_ids}");
1237 $this->db->manipulate(
"DELETE FROM tst_result_cache WHERE {$in_active_ids}");
1238 $this->db->manipulate(
"DELETE FROM tst_sequence WHERE {$in_active_ids}");
1239 $this->db->manipulate(
"DELETE FROM tst_times WHERE {$in_active_ids}");
1240 $this->db->manipulate(
1242 .
' WHERE ' . $this->db->in(
'active_id', $active_ids,
false,
'integer')
1246 $this->db->manipulate(
"DELETE FROM tst_test_rnd_qst WHERE {$in_active_ids}");
1249 $this->test_result_repository->removeTestResults($active_ids, $this->
getId());
1251 foreach ($active_ids as $active_id) {
1264 $IN_activeIds = $this->db->in(
'active_id', $active_ids,
false,
'integer');
1265 $this->db->manipulate(
"DELETE FROM tst_active WHERE $IN_activeIds");
1278 $result = $this->db->queryF(
1279 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1280 [
'integer',
'integer'],
1283 $data = $this->db->fetchObject($result);
1284 if (
$data->sequence > 1) {
1286 $result = $this->db->queryF(
1287 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1288 [
'integer',
'integer'],
1291 $data_previous = $this->db->fetchObject($result);
1293 $this->db->manipulateF(
1294 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1295 [
'integer',
'integer'],
1296 [
$data->sequence, $data_previous->test_question_id]
1299 $this->db->manipulateF(
1300 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1301 [
'integer',
'integer'],
1302 [
$data->sequence - 1,
$data->test_question_id]
1317 $current_question_result = $this->db->queryF(
1318 "SELECT * FROM tst_test_question WHERE test_fi=%s AND question_fi=%s",
1319 [
'integer',
'integer'],
1322 $current_question_data = $this->db->fetchObject($current_question_result);
1323 $next_question_result = $this->db->queryF(
1324 "SELECT * FROM tst_test_question WHERE test_fi=%s AND sequence=%s",
1325 [
'integer',
'integer'],
1326 [$this->
getTestId(), $current_question_data->sequence + 1]
1328 if ($this->db->numRows($next_question_result) === 1) {
1330 $next_question_data = $this->db->fetchObject($next_question_result);
1332 $this->db->manipulateF(
1333 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1334 [
'integer',
'integer'],
1335 [$current_question_data->sequence, $next_question_data->test_question_id]
1338 $this->db->manipulateF(
1339 "UPDATE tst_test_question SET sequence=%s WHERE test_question_id=%s",
1340 [
'integer',
'integer'],
1341 [$current_question_data->sequence + 1, $current_question_data->test_question_id]
1356 $duplicate_id = $question->duplicate(
true,
'',
'', -1, $this->
getId());
1357 return $duplicate_id;
1363 $duplicate_id = $question_id;
1369 $result = $this->db->queryF(
1370 "SELECT MAX(sequence) seq FROM tst_test_question WHERE test_fi=%s",
1376 if ($result->numRows() == 1) {
1377 $data = $this->db->fetchObject($result);
1378 $sequence =
$data->seq + 1;
1381 $next_id = $this->db->nextId(
'tst_test_question');
1382 $this->db->manipulateF(
1383 "INSERT INTO tst_test_question (test_question_id, test_fi, question_fi, sequence, tstamp) VALUES (%s, %s, %s, %s, %s)",
1384 [
'integer',
'integer',
'integer',
'integer',
'integer'],
1385 [$next_id, $this->
getTestId(), $duplicate_id, $sequence, time()]
1388 $this->db->manipulateF(
1389 "DELETE FROM tst_active WHERE test_fi = %s",
1394 $this->
saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
1396 if ($this->
logger->isLoggingEnabled()) {
1397 $this->
logger->logTestAdministrationInteraction(
1398 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
1400 $this->
user->getId(),
1401 TestAdministrationInteractionTypes::QUESTION_ADDED,
1403 AdditionalInformationGenerator::KEY_QUESTION_ID => $question_id
1405 ->toLog($this->
logger->getAdditionalInformationGenerator())
1410 return $duplicate_id;
1417 $result = $this->db->queryF(
1418 'SELECT qpl_questions.title FROM tst_test_question, qpl_questions ' 1419 .
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ' 1420 .
'ORDER BY tst_test_question.sequence',
1424 while ($row = $this->db->fetchAssoc($result)) {
1425 array_push($titles, $row[
'title']);
1442 $result = $this->db->queryF(
1443 'SELECT qpl_questions.title, qpl_questions.question_id ' 1444 .
'FROM tst_test_question, qpl_questions ' 1445 .
'WHERE tst_test_question.test_fi = %s AND tst_test_question.question_fi = qpl_questions.question_id ' 1446 .
'ORDER BY tst_test_question.sequence',
1450 while ($row = $this->db->fetchAssoc($result)) {
1451 $titles[$row[
'question_id']] = $row[
"title"];
1476 return $this->
lng->txt(
"ass_question") .
' ' . $nr;
1478 return $this->
lng->txt(
"ass_question");
1482 $txt = $this->
lng->txt(
"ass_question") .
' ' . $nr;
1484 $txt = $this->
lng->txt(
"ass_question");
1486 if ($points !=
'') {
1487 $lngv = $this->
lng->txt(
'points');
1489 $lngv = $this->
lng->txt(
'point');
1491 $txt .=
' - ' . $points .
' ' . $lngv;
1497 return $this->
lng->txt(
"ass_question");
1511 $result = $this->db->queryF(
1512 "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",
1516 $row = $this->db->fetchObject($result);
1528 $existing_questions = [];
1531 if (is_null($pass)) {
1534 $result = $this->db->queryF(
1535 "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",
1536 [
'integer',
'integer'],
1540 $result = $this->db->queryF(
1541 "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",
1546 while (
$data = $this->db->fetchObject($result)) {
1551 array_push($existing_questions,
$data->original_id);
1553 return $existing_questions;
1565 if ($question_id < 1) {
1568 $result = $this->db->queryF(
1569 "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",
1573 if ($result->numRows() == 1) {
1574 $data = $this->db->fetchObject($result);
1575 return $data->type_tag;
1589 $next_id = $this->db->nextId(
'tst_times');
1590 $affectedRows = $this->db->manipulateF(
1591 "INSERT INTO tst_times (times_id, active_fi, started, finished, pass, tstamp) VALUES (%s, %s, %s, %s, %s, %s)",
1592 [
'integer',
'integer',
'timestamp',
'timestamp',
'integer',
'integer'],
1593 [$next_id, $active_id, date(
"Y-m-d H:i:s"), date(
"Y-m-d H:i:s"), $pass, time()]
1606 $affectedRows = $this->db->manipulateF(
1607 "UPDATE tst_times SET finished = %s, tstamp = %s WHERE times_id = %s",
1608 [
'timestamp',
'integer',
'integer'],
1609 [date(
'Y-m-d H:i:s'), time(), $times_id]
1621 if (is_null($pass)) {
1622 $result = $this->db->queryF(
1623 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1624 [
'integer',
'integer'],
1628 $result = $this->db->queryF(
1629 "SELECT question_fi FROM tst_solutions WHERE active_fi = %s AND pass = %s GROUP BY question_fi",
1630 [
'integer',
'integer'],
1635 while ($row = $this->db->fetchAssoc($result)) {
1636 array_push($result_array, $row[
"question_fi"]);
1638 return $result_array;
1652 return ((($currentpass > 0) && ($num == 0)) || $this->
isTestFinished($active_id)) ? true :
false;
1665 if ($active_id ===
null) {
1669 if (count($this->questions) === 0) {
1672 if (is_null($pass)) {
1673 $pass = self::_getPass($active_id);
1675 $result = $this->db->queryF(
1676 "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'),
1677 [
'integer',
'integer'],
1681 if (count($this->questions) === 0) {
1684 $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'));
1687 while ($row = $this->db->fetchAssoc($result)) {
1688 $result_array[$row[
"question_id"]] = $row;
1690 return $result_array;
1708 if (is_array($tst_access_code) &&
1710 isset($tst_access_code[$this->
getTestId()]) &&
1711 $tst_access_code[$this->
getTestId()] !==
'') {
1712 $result = $this->db->queryF(
1713 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1714 [
'integer',
'integer',
'text'],
1717 } elseif ((
string) $anonymous_id !==
'') {
1718 $result = $this->db->queryF(
1719 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s AND anonymous_id = %s',
1720 [
'integer',
'integer',
'text'],
1721 [
$user_id, $this->test_id, $anonymous_id]
1727 $result = $this->db->queryF(
1728 'SELECT active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s',
1729 [
'integer',
'integer'],
1734 if ($result->numRows()) {
1735 $row = $this->db->fetchAssoc($result);
1736 return (
int) $row[
'active_id'];
1745 $ilDB = $DIC[
'ilDB'];
1746 $ilUser = $DIC[
'ilUser'];
1754 $result =
$ilDB->queryF(
1755 "SELECT tst_active.active_id FROM tst_active WHERE user_fi = %s AND test_fi = %s",
1756 [
'integer',
'integer'],
1759 if ($result->numRows()) {
1760 $row =
$ilDB->fetchAssoc($result);
1761 return $row[
"active_id"];
1775 $keys = array_keys($array);
1778 foreach ($keys as $key) {
1779 $result[$key] = $array[$key];
1792 ?
int $attempt =
null,
1793 bool $ordered_sequence =
false,
1794 bool $consider_hidden_questions =
true,
1795 bool $consider_optional_questions =
true 1797 $test_result = $this->test_result_repository->getTestResult($active_id);
1799 if ($test_result ===
null) {
1800 $test_result = $this->test_result_repository->updateTestResultCache($active_id);
1803 if ($attempt ===
null) {
1804 $attempt = $test_result->getAttempt();
1808 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $attempt);
1810 $test_sequence->setConsiderHiddenQuestionsEnabled($consider_hidden_questions);
1811 $test_sequence->setConsiderOptionalQuestionsEnabled($consider_optional_questions);
1816 if ($ordered_sequence) {
1826 tst_test_result.question_fi, 1827 tst_test_result.points reached, 1828 tst_test_result.answered answered, 1829 tst_manual_fb.finalized_evaluation finalized_evaluation 1831 FROM tst_test_result 1833 LEFT JOIN tst_solutions 1834 ON tst_solutions.active_fi = tst_test_result.active_fi 1835 AND tst_solutions.question_fi = tst_test_result.question_fi 1837 LEFT JOIN tst_manual_fb 1838 ON tst_test_result.active_fi = tst_manual_fb.active_fi 1839 AND tst_test_result.question_fi = tst_manual_fb.question_fi 1841 WHERE tst_test_result.active_fi = %s 1842 AND tst_test_result.pass = %s 1845 $solutionresult = $this->db->queryF(
1847 [
'integer',
'integer'],
1848 [$active_id, $attempt]
1851 while ($row = $this->db->fetchAssoc($solutionresult)) {
1852 $arr_results[ $row[
'question_fi'] ] = $row;
1855 $result = $this->db->query(
1856 'SELECT qpl_questions.*, qpl_qst_type.type_tag, qpl_sol_sug.question_fi has_sug_sol' . PHP_EOL
1857 .
'FROM qpl_qst_type, qpl_questions' . PHP_EOL
1858 .
'LEFT JOIN qpl_sol_sug' . PHP_EOL
1859 .
'ON qpl_sol_sug.question_fi = qpl_questions.question_id' . PHP_EOL
1860 .
'WHERE qpl_qst_type.question_type_id = qpl_questions.question_type_fi' . PHP_EOL
1861 .
'AND ' . $this->db->in(
'qpl_questions.question_id', $sequence,
false,
'integer')
1866 while ($row = $this->db->fetchAssoc($result)) {
1867 if (!isset($arr_results[ $row[
'question_id'] ])) {
1868 $percentvalue = 0.0;
1871 $row[
'points'] ? $arr_results[$row[
'question_id']][
'reached'] / $row[
'points'] : 0
1874 if ($percentvalue < 0) {
1875 $percentvalue = 0.0;
1881 'max' => round($row[
'points'], 2),
1882 'reached' => round($arr_results[$row[
'question_id']][
'reached'] ?? 0, 2),
1883 'percent' => sprintf(
'%2.2f ', ($percentvalue) * 100) .
'%',
1885 'type' => $row[
'type_tag'],
1886 'qid' => $row[
'question_id'],
1887 'original_id' => $row[
'original_id'],
1888 'workedthrough' => isset($arr_results[$row[
'question_id']]) ? 1 : 0,
1889 'answered' => $arr_results[$row[
'question_id']][
'answered'] ?? 0,
1890 'finalized_evaluation' => $arr_results[$row[
'question_id']][
'finalized_evaluation'] ?? 0,
1893 $unordered[ $row[
'question_id'] ] =
$data;
1901 foreach ($sequence as $qid) {
1904 $pass_max += round($unordered[$qid][
'max'], 2);
1905 $pass_reached += round($unordered[$qid][
'reached'], 2);
1906 $found[] = $unordered[$qid];
1910 if ($pass_reached < 0) {
1915 $found[
'pass'][
'total_max_points'] = $pass_max;
1916 $found[
'pass'][
'total_reached_points'] = $pass_reached;
1917 $found[
'pass'][
'percent'] = ($pass_max > 0) ? $pass_reached / $pass_max : 0;
1918 $found[
'pass'][
'num_workedthrough'] = count($arr_results);
1919 $found[
'pass'][
'num_questions_total'] = count($unordered);
1921 $found[
'test'][
'total_max_points'] = $test_result->getMaxPoints();
1922 $found[
'test'][
'total_reached_points'] = $test_result->getReachedPoints();
1923 $found[
'test'][
'result_pass'] = $attempt;
1924 $found[
'test'][
'result_tstamp'] = $test_result->getTimestamp();
1925 $found[
'test'][
'passed'] = $test_result->isPassed();
1938 $result = $this->db->queryF(
1939 'SELECT COUNT(active_id) total FROM tst_active WHERE test_fi = %s',
1943 $row = $this->db->fetchAssoc($result);
1944 return $row[
'total'];
1955 $result = $this->db->queryF(
1956 "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",
1957 [
'integer',
'integer'],
1961 while ($row = $this->db->fetchAssoc($result)) {
1962 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
1971 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
1980 $time += ($epoch_2 - $epoch_1);
2005 $result = $this->db->queryF(
2006 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi ORDER BY tst_times.active_fi, tst_times.started",
2012 while ($row = $this->db->fetchAssoc($result)) {
2013 if (!array_key_exists($row[
"active_fi"], $times)) {
2014 $times[$row[
"active_fi"]] = 0;
2016 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2025 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2034 $times[$row[
"active_fi"]] += ($epoch_2 - $epoch_1);
2047 $result = $this->db->queryF(
2048 "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",
2049 [
'integer',
'integer'],
2053 while ($row = $this->db->fetchAssoc($result)) {
2054 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches);
2063 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"finished"], $matches);
2072 $time += ($epoch_2 - $epoch_1);
2082 return $this->test_result_repository->fetchWorkingTime($active_id, $pass);
2092 $result = $this->db->queryF(
2093 "SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.active_id = %s AND tst_active.active_id = tst_times.active_fi",
2100 while ($row = $this->db->fetchObject($result)) {
2101 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2110 if (!$first_visit) {
2111 $first_visit = $epoch_1;
2113 if ($epoch_1 < $first_visit) {
2114 $first_visit = $epoch_1;
2116 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2126 $last_visit = $epoch_2;
2128 if ($epoch_2 > $last_visit) {
2129 $last_visit = $epoch_2;
2131 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2134 foreach ($times as $key => $value) {
2135 $max_time += $value;
2137 if ((!$test_result[
"test"][
"total_reached_points"]) or (!$test_result[
"test"][
"total_max_points"])) {
2140 $percentage = ($test_result[
"test"][
"total_reached_points"] / $test_result[
"test"][
"total_max_points"]) * 100.0;
2141 if ($percentage < 0) {
2145 $mark_obj = $this->
getMarkSchema()->getMatchingMark($percentage);
2146 $first_date = getdate($first_visit);
2147 $last_date = getdate($last_visit);
2148 $qworkedthrough = 0;
2149 foreach ($test_result as $key => $value) {
2150 if (preg_match(
"/\d+/", $key)) {
2151 $qworkedthrough += $value[
"workedthrough"];
2154 if (!$qworkedthrough) {
2157 $atimeofwork = $max_time / $qworkedthrough;
2163 if ($mark_obj !==
null) {
2164 $result_mark = $mark_obj->getShortName();
2166 if ($mark_obj->getPassed()) {
2172 $percent_worked_through = 0;
2173 if (count($this->questions)) {
2174 $percent_worked_through = $qworkedthrough / count($this->questions);
2177 "qworkedthrough" => $qworkedthrough,
2178 "qmax" => count($this->questions),
2179 "pworkedthrough" => $percent_worked_through,
2180 "timeofwork" => $max_time,
2181 "atimeofwork" => $atimeofwork,
2182 "firstvisit" => $first_date,
2183 "lastvisit" => $last_date,
2184 "resultspoints" => $test_result[
"test"][
"total_reached_points"],
2185 "maxpoints" => $test_result[
"test"][
"total_max_points"],
2186 "resultsmarks" => $result_mark,
2187 "passed" => $passed,
2188 "distancemedian" =>
"0" 2190 foreach ($test_result as $key => $value) {
2191 if (preg_match(
"/\d+/", $key)) {
2192 $result_array[$key] = $value;
2195 return $result_array;
2207 $totalpoints_array = [];
2209 foreach ($all_users as $active_id => $user_name) {
2211 $reached = $test_result[
"test"][
"total_reached_points"];
2212 $total = $test_result[
"test"][
"total_max_points"];
2213 $percentage = $total != 0 ? $reached / $total : 0;
2214 $mark = $this->
getMarkSchema()->getMatchingMark($percentage * 100.0);
2216 if ($mark !==
null && $mark->getPassed()) {
2217 array_push($totalpoints_array, $test_result[
"test"][
"total_reached_points"]);
2220 return $totalpoints_array;
2230 $result = $this->db->queryF(
2231 "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",
2235 $persons_array = [];
2236 while ($row = $this->db->fetchAssoc($result)) {
2237 $name = $this->
lng->txt(
"anonymous");
2238 $fullname = $this->
lng->txt(
"anonymous");
2241 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2242 $name = $this->
lng->txt(
"deleted_user");
2243 $fullname = $this->
lng->txt(
"deleted_user");
2244 $login = $this->
lng->txt(
"unknown");
2246 $login = $row[
"login"];
2248 $name = $this->
lng->txt(
"anonymous");
2249 $fullname = $this->
lng->txt(
"anonymous");
2251 $name = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2252 $fullname = trim($row[
"title"] .
" " . $row[
"firstname"] .
" " . $row[
"lastname"]);
2256 $persons_array[$row[
"active_id"]] = [
2258 "fullname" => $fullname,
2262 return $persons_array;
2267 $result = $this->db->queryF(
2268 "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),
2272 $persons_array = [];
2273 while ($row = $this->db->fetchAssoc($result)) {
2279 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"anonymous");
2281 if (strlen($row[
"firstname"] . $row[
"lastname"] . $row[
"title"]) == 0) {
2282 $persons_array[$row[
"active_id"]] = $this->
lng->txt(
"deleted_user");
2285 $persons_array[$row[
"active_id"]] = $row[
"lastname"];
2287 $persons_array[$row[
"active_id"]] = trim($row[
"lastname"] .
", " . $row[
"firstname"] .
" " . $row[
"title"]);
2292 return $persons_array;
2297 $result = $this->db->queryF(
2298 'SELECT tst_active.user_fi, tst_active.active_id, usr_data.login, ' 2299 .
'usr_data.firstname, usr_data.lastname, usr_data.title FROM tst_active ' 2300 .
'LEFT JOIN usr_data ON tst_active.user_fi = usr_data.usr_id ' 2301 .
'WHERE tst_active.test_fi = %s ' 2302 .
'ORDER BY usr_data.lastname ' . strtoupper($name_sort_order),
2306 $persons_array = [];
2307 while ($row = $this->db->fetchAssoc($result)) {
2309 $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
"anonymous")];
2311 if (strlen($row[
'firstname'] . $row[
'lastname'] . $row[
"title"]) == 0) {
2312 $persons_array[$row[
'active_id']] = [
'name' => $this->
lng->txt(
'deleted_user')];
2315 $persons_array[$row[
'active_id']] = [
'name' => $row[
'lastname']];
2317 $persons_array[$row[
'active_id']] = [
2318 'name' => trim($row[
'lastname'] .
', ' . $row[
'firstname']
2319 .
' ' . $row[
'title']),
2320 'login' => $row[
'login']
2326 return $persons_array;
2333 $result = $this->db->queryF(
2334 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, ' 2335 .
'tst_test_rnd_qst.pass, qpl_questions.points ' 2336 .
'FROM tst_test_rnd_qst, qpl_questions ' 2337 .
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id ' 2338 .
'AND tst_test_rnd_qst.active_fi = %s ORDER BY tst_test_rnd_qst.sequence',
2343 $result = $this->db->queryF(
2344 'SELECT tst_test_question.sequence, tst_test_question.question_fi, ' 2345 .
'qpl_questions.points ' 2346 .
'FROM tst_test_question, tst_active, qpl_questions ' 2347 .
'WHERE tst_test_question.question_fi = qpl_questions.question_id ' 2348 .
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
2354 if ($result->numRows()) {
2355 while ($row = $this->db->fetchAssoc($result)) {
2356 array_push($qtest, $row);
2366 $result = $this->db->queryF(
2367 'SELECT tst_test_rnd_qst.sequence, tst_test_rnd_qst.question_fi, ' 2368 .
'qpl_questions.points ' 2369 .
'FROM tst_test_rnd_qst, qpl_questions ' 2370 .
'WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id ' 2371 .
'AND tst_test_rnd_qst.active_fi = %s AND tst_test_rnd_qst.pass = %s ' 2372 .
'ORDER BY tst_test_rnd_qst.sequence',
2373 [
'integer',
'integer'],
2377 $result = $this->db->queryF(
2378 'SELECT tst_test_question.sequence, tst_test_question.question_fi, ' 2379 .
'qpl_questions.points ' 2380 .
'FROM tst_test_question, tst_active, qpl_questions ' 2381 .
'WHERE tst_test_question.question_fi = qpl_questions.question_id ' 2382 .
'AND tst_active.active_id = %s AND tst_active.test_fi = tst_test_question.test_fi',
2388 if ($result->numRows()) {
2389 while ($row = $this->db->fetchAssoc($result)) {
2390 array_push($qpass, $row);
2411 return $list->getAccessFilteredList(
2412 $this->participant_access_filter->getAccessStatisticsUserFilter($this->getRefId())
2424 return $list->getAllUserIds();
2426 return $list->getAccessFilteredList(
2427 $this->participant_access_filter->getAnonOnlyParticipantsUserFilter($this->getRefId())
2434 ->getEvaluationData();
2441 switch ($question_set_type) {
2443 $res = $this->db->queryF(
2445 SELECT tst_test_rnd_qst.pass, 2446 COUNT(tst_test_rnd_qst.question_fi) qcount, 2447 SUM(qpl_questions.points) qsum 2449 FROM tst_test_rnd_qst, 2452 WHERE tst_test_rnd_qst.question_fi = qpl_questions.question_id 2453 AND tst_test_rnd_qst.active_fi = %s 2456 GROUP BY tst_test_rnd_qst.active_fi, 2457 tst_test_rnd_qst.pass 2459 [
'integer',
'integer'],
2465 $res = $this->db->queryF(
2467 SELECT COUNT(tst_test_question.question_fi) qcount, 2468 SUM(qpl_questions.points) qsum 2470 FROM tst_test_question, 2474 WHERE tst_test_question.question_fi = qpl_questions.question_id 2475 AND tst_test_question.test_fi = tst_active.test_fi 2476 AND tst_active.active_id = %s 2478 GROUP BY tst_test_question.test_fi 2486 throw new ilTestException(
"not supported question set type: $question_set_type");
2489 $row = $this->db->fetchAssoc(
$res);
2491 if (is_array($row)) {
2492 return [
"count" => $row[
"qcount"],
"points" => $row[
"qsum"]];
2495 return [
"count" => 0,
"points" => 0];
2501 $data->setFilter($filterby, $filtertext);
2521 if ($user_id ===
null 2522 || $firstname . $lastname ===
'') {
2523 return $this->
lng->txt(
'deleted_user');
2527 return $this->
lng->txt(
'anonymous');
2534 return trim($lastname .
', ' . $firstname);
2539 $query =
"SELECT tst_times.* FROM tst_active, tst_times WHERE tst_active.test_fi = %s AND tst_active.active_id = tst_times.active_fi";
2541 if ($active_ids_to_filter !==
null && $active_ids_to_filter !== []) {
2542 $query .=
" AND " . $this->db->in(
'active_id', $active_ids_to_filter,
false,
'integer');
2545 $result = $this->db->queryF($query, [
'integer'], [$this->
getTestId()]);
2547 while ($row = $this->db->fetchObject($result)) {
2548 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->started, $matches);
2557 preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row->finished, $matches);
2566 if (isset($times[$row->active_fi])) {
2567 $times[$row->active_fi] += ($epoch_2 - $epoch_1);
2569 $times[$row->active_fi] = ($epoch_2 - $epoch_1);
2574 foreach ($times as $value) {
2575 $max_time += $value;
2578 if ($counter === 0) {
2581 return (
int) round($max_time / $counter);
2591 bool $use_object_id =
false,
2592 ?
bool $equal_points =
false,
2593 bool $could_be_offline =
false,
2594 bool $show_path =
false,
2595 bool $with_questioncount =
false,
2596 string $permission =
'read' 2600 $equal_points ??
false,
2603 $with_questioncount,
2645 if ((!$question_type) and ($question_id > 0)) {
2649 if (!strlen($question_type)) {
2653 if ($question_id > 0) {
2654 $question_gui = assQuestion::instantiateQuestionGUI($question_id);
2656 $question_type_gui = $question_type .
'GUI';
2657 $question_gui =
new $question_type_gui();
2660 return $question_gui;
2671 if (strcmp((
string) $question_id,
"") !== 0) {
2682 public function moveQuestions(array $move_questions,
int $target_index,
int $insert_mode): void
2684 $this->questions = array_values($this->questions);
2685 $array_pos = array_search($target_index, $this->questions);
2686 if ($insert_mode == 0) {
2687 $part1 = array_slice($this->questions, 0, $array_pos);
2688 $part2 = array_slice($this->questions, $array_pos);
2689 } elseif ($insert_mode == 1) {
2690 $part1 = array_slice($this->questions, 0, $array_pos + 1);
2691 $part2 = array_slice($this->questions, $array_pos + 1);
2693 foreach ($move_questions as $question_id) {
2694 if (!(array_search($question_id, $part1) ===
false)) {
2695 unset($part1[array_search($question_id, $part1)]);
2697 if (!(array_search($question_id, $part2) ===
false)) {
2698 unset($part2[array_search($question_id, $part2)]);
2701 $part1 = array_values($part1);
2702 $part2 = array_values($part2);
2703 $new_array = array_values(array_merge($part1, $move_questions, $part2));
2704 $this->questions = [];
2706 foreach ($new_array as $question_id) {
2707 $this->questions[$counter] = $question_id;
2712 if ($this->
logger->isLoggingEnabled()) {
2713 $this->
logger->logTestAdministrationInteraction(
2714 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
2716 $this->
user->getId(),
2717 TestAdministrationInteractionTypes::QUESTION_MOVED,
2772 if (count($available_pools)) {
2773 $available =
" AND " . $this->db->in(
'qpl_questions.obj_fi', $available_pools,
false,
'integer');
2777 if ($completeonly) {
2778 $available .=
" AND qpl_questions.complete = " . $this->db->quote(
"1",
'text');
2782 if (is_array($arr_filter)) {
2783 if (array_key_exists(
'title', $arr_filter) && strlen($arr_filter[
'title'])) {
2784 $where .=
" AND " . $this->db->like(
'qpl_questions.title',
'text',
"%%" . $arr_filter[
'title'] .
"%%");
2786 if (array_key_exists(
'description', $arr_filter) && strlen($arr_filter[
'description'])) {
2787 $where .=
" AND " . $this->db->like(
'qpl_questions.description',
'text',
"%%" . $arr_filter[
'description'] .
"%%");
2789 if (array_key_exists(
'author', $arr_filter) && strlen($arr_filter[
'author'])) {
2790 $where .=
" AND " . $this->db->like(
'qpl_questions.author',
'text',
"%%" . $arr_filter[
'author'] .
"%%");
2792 if (array_key_exists(
'type', $arr_filter) && strlen($arr_filter[
'type'])) {
2793 $where .=
" AND qpl_qst_type.type_tag = " . $this->db->quote($arr_filter[
'type'],
'text');
2795 if (array_key_exists(
'qpl', $arr_filter) && strlen($arr_filter[
'qpl'])) {
2796 $where .=
" AND " . $this->db->like(
'object_data.title',
'text',
"%%" . $arr_filter[
'qpl'] .
"%%");
2801 $original_clause =
" qpl_questions.original_id IS NULL";
2802 if (count($original_ids)) {
2803 $original_clause =
" qpl_questions.original_id IS NULL AND " . $this->db->in(
'qpl_questions.question_id', $original_ids,
true,
'integer');
2806 $query_result = $this->db->query(
" 2807 SELECT qpl_questions.*, qpl_questions.tstamp, 2808 qpl_qst_type.type_tag, qpl_qst_type.plugin, qpl_qst_type.plugin_name, 2809 object_data.title parent_title 2810 FROM qpl_questions, qpl_qst_type, object_data 2811 WHERE $original_clause $available 2812 AND object_data.obj_id = qpl_questions.obj_fi 2813 AND qpl_questions.tstamp > 0 2814 AND qpl_questions.question_type_fi = qpl_qst_type.question_type_id 2819 if ($query_result->numRows()) {
2820 while ($row = $this->db->fetchAssoc($query_result)) {
2823 if (!$row[
'plugin']) {
2824 $row[
'ttype' ] = $this->
lng->txt($row[
"type_tag" ]);
2830 $plugin = $this->component_repository->getPluginByName($row[
'plugin_name']);
2835 $pl = $this->component_factory->getPlugin(
$plugin->getId());
2836 $row[
'ttype' ] = $pl->getQuestionTypeTranslation();
2868 $introduction_settings = $introduction_settings->withIntroductionEnabled(
false);
2869 foreach ($assessment->objectives as
$objectives) {
2870 foreach ($objectives->materials as $material) {
2872 $introduction_settings,
2884 $finishing_settings,
2900 foreach ($assessment->qtimetadata as
$metadata) {
2901 switch ($metadata[
"label"]) {
2902 case "solution_details":
2903 $result_details_settings = $result_details_settings->withShowPassDetails((
bool) $metadata[
"entry"]);
2905 case "show_solution_list_comparison":
2906 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
2908 case "print_bs_with_res":
2909 $result_details_settings = $result_details_settings->withShowSolutionListComparison((
bool) $metadata[
"entry"]);
2915 $test_behaviour_settings = $test_behaviour_settings->withNumberOfTries((
int) $metadata[
"entry"]);
2917 case 'block_after_passed':
2918 $test_behaviour_settings = $test_behaviour_settings->withBlockAfterPassedEnabled((
bool) $metadata[
'entry']);
2920 case "pass_waiting":
2921 $test_behaviour_settings = $test_behaviour_settings->withPassWaiting($metadata[
"entry"]);
2924 $test_behaviour_settings = $test_behaviour_settings->withKioskMode((
int) $metadata[
"entry"]);
2926 case 'show_introduction':
2927 $introduction_settings = $introduction_settings->withIntroductionEnabled((
bool) $metadata[
'entry']);
2929 case "showfinalstatement":
2930 case 'show_concluding_remarks':
2931 $finishing_settings = $finishing_settings->withConcludingRemarksEnabled((
bool) $metadata[
"entry"]);
2933 case 'exam_conditions':
2934 $introduction_settings = $introduction_settings->withExamConditionsCheckboxEnabled($metadata[
'entry'] ===
'1');
2936 case "highscore_enabled":
2937 $gamification_settings = $gamification_settings->withHighscoreEnabled((
bool) $metadata[
"entry"]);
2939 case "highscore_anon":
2940 $gamification_settings = $gamification_settings->withHighscoreAnon((
bool) $metadata[
"entry"]);
2942 case "highscore_achieved_ts":
2943 $gamification_settings = $gamification_settings->withHighscoreAchievedTS((
bool) $metadata[
"entry"]);
2945 case "highscore_score":
2946 $gamification_settings = $gamification_settings->withHighscoreScore((
bool) $metadata[
"entry"]);
2948 case "highscore_percentage":
2949 $gamification_settings = $gamification_settings->withHighscorePercentage((
bool) $metadata[
"entry"]);
2951 case "highscore_wtime":
2952 $gamification_settings = $gamification_settings->withHighscoreWTime((
bool) $metadata[
"entry"]);
2954 case "highscore_own_table":
2955 $gamification_settings = $gamification_settings->withHighscoreOwnTable((
bool) $metadata[
"entry"]);
2957 case "highscore_top_table":
2958 $gamification_settings = $gamification_settings->withHighscoreTopTable((
bool) $metadata[
"entry"]);
2960 case "highscore_top_num":
2961 $gamification_settings = $gamification_settings->withHighscoreTopNum((
int) $metadata[
"entry"]);
2963 case "use_previous_answers":
2964 $participant_functionality_settings = $participant_functionality_settings->withUsePreviousAnswerAllowed((
bool) $metadata[
"entry"]);
2966 case 'question_list_enabled':
2967 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
'entry']);
2969 case "title_output":
2970 $question_behaviour_settings = $question_behaviour_settings->withQuestionTitleOutputMode((
int) $metadata[
"entry"]);
2972 case "question_set_type":
2973 if ($metadata[
'entry'] === self::QUESTION_SET_TYPE_RANDOM) {
2974 $this->questions = [];
2976 $general_settings = $general_settings->withQuestionSetType($metadata[
"entry"]);
2979 $general_settings = $general_settings->withAnonymity((
bool) $metadata[
"entry"]);
2981 case "results_presentation":
2982 $result_details_settings = $result_details_settings->withResultsPresentation((
int) $metadata[
"entry"]);
2984 case "reset_processing_time":
2985 $test_behaviour_settings = $test_behaviour_settings->withResetProcessingTime($metadata[
"entry"] ===
'1');
2987 case "answer_feedback_points":
2988 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackPointsEnabled((
bool) $metadata[
"entry"]);
2990 case "answer_feedback":
2991 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackGenericEnabled((
bool) $metadata[
"entry"]);
2993 case 'instant_feedback_specific':
2994 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSpecificEnabled((
bool) $metadata[
'entry']);
2996 case "instant_verification":
2997 $question_behaviour_settings = $question_behaviour_settings->withInstantFeedbackSolutionEnabled((
bool) $metadata[
"entry"]);
2999 case "force_instant_feedback":
3000 $question_behaviour_settings = $question_behaviour_settings->withForceInstantFeedbackOnNextQuestion((
bool) $metadata[
"entry"]);
3002 case "follow_qst_answer_fixation":
3003 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnNextQuestionEnabled((
bool) $metadata[
"entry"]);
3005 case "instant_feedback_answer_fixation":
3006 $question_behaviour_settings = $question_behaviour_settings->withLockAnswerOnInstantFeedbackEnabled((
bool) $metadata[
"entry"]);
3009 case "suspend_test_allowed":
3010 $participant_functionality_settings = $participant_functionality_settings->withSuspendTestAllowed((
bool) $metadata[
"entry"]);
3012 case "sequence_settings":
3013 $participant_functionality_settings = $participant_functionality_settings->withPostponedQuestionsMoveToEnd((
bool) $metadata[
"entry"]);
3016 $participant_functionality_settings = $participant_functionality_settings->withQuestionMarkingEnabled((
bool) $metadata[
"entry"]);
3018 case "fixed_participants":
3019 $access_settings = $access_settings->withFixedParticipants((
bool) $metadata[
"entry"]);
3021 case "score_reporting":
3022 if ($metadata[
'entry'] !==
null) {
3023 $result_summary_settings = $result_summary_settings->withScoreReporting(
3024 ScoreReportingTypes::tryFrom((
int) $metadata[
'entry']) ?? ScoreReportingTypes::SCORE_REPORTING_DISABLED
3028 case "shuffle_questions":
3029 $question_behaviour_settings = $question_behaviour_settings->withShuffleQuestions((
bool) $metadata[
"entry"]);
3031 case "count_system":
3032 $scoring_settings = $scoring_settings->withCountSystem((
int) $metadata[
"entry"]);
3034 case "mailnotification":
3035 $finishing_settings = $finishing_settings->withMailNotificationContentType((
int) $metadata[
"entry"]);
3038 $finishing_settings = $finishing_settings->withAlwaysSendMailNotification((
bool) $metadata[
"entry"]);
3040 case "exportsettings":
3041 $result_details_settings = $result_details_settings->withExportSettings((
int) $metadata[
"entry"]);
3043 case "score_cutting":
3044 $scoring_settings = $scoring_settings->withScoreCutting((
int) $metadata[
"entry"]);
3047 $access_settings = $access_settings->withPasswordEnabled(
3048 $metadata[
"entry"] !==
null && $metadata[
"entry"] !==
'' 3049 )->withPassword($metadata[
"entry"]);
3051 case 'ip_range_from':
3052 if ($metadata[
'entry'] !==
'') {
3053 $access_settings = $access_settings->withIpRangeFrom($metadata[
'entry']);
3057 if ($metadata[
'entry'] !==
'') {
3058 $access_settings = $access_settings->withIpRangeTo($metadata[
'entry']);
3061 case "pass_scoring":
3062 $scoring_settings = $scoring_settings->withPassScoring((
int) $metadata[
"entry"]);
3064 case 'pass_deletion_allowed':
3065 $result_summary_settings = $result_summary_settings->withPassDeletionAllowed((
bool) $metadata[
"entry"]);
3067 case "usr_pass_overview_mode":
3068 $participant_functionality_settings = $participant_functionality_settings->withUsrPassOverviewMode((
int) $metadata[
"entry"]);
3070 case "question_list":
3071 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled((
bool) $metadata[
"entry"]);
3074 case "reporting_date":
3076 if ($reporting_date !==
null) {
3077 $result_summary_settings = $result_summary_settings->withReportingDate($reporting_date);
3080 case 'enable_processing_time':
3081 $test_behaviour_settings = $test_behaviour_settings->withProcessingTimeEnabled((
bool) $metadata[
'entry']);
3083 case "processing_time":
3084 $test_behaviour_settings = $test_behaviour_settings->withProcessingTime($metadata[
'entry']);
3086 case "starting_time":
3088 if ($starting_time !==
null) {
3089 $access_settings = $access_settings->withStartTime($starting_time)
3090 ->withStartTimeEnabled(
true);
3095 if ($ending_time !==
null) {
3096 $access_settings = $access_settings->withEndTime($ending_time)
3097 ->withStartTimeEnabled(
true);
3100 case "enable_examview":
3101 $finishing_settings = $finishing_settings->withShowAnswerOverview((
bool) $metadata[
"entry"]);
3103 case 'redirection_mode':
3104 $finishing_settings = $finishing_settings->withRedirectionMode((
int) $metadata[
'entry']);
3106 case 'redirection_url':
3107 $finishing_settings = $finishing_settings->withRedirectionUrl($metadata[
'entry']);
3109 case 'examid_in_test_pass':
3110 $test_behaviour_settings = $test_behaviour_settings->withExamIdInTestAttemptEnabled((
bool) $metadata[
'entry']);
3112 case 'examid_in_test_res':
3113 $result_details_settings = $result_details_settings->withShowExamIdInTestResults((
bool) $metadata[
"entry"]);
3115 case 'skill_service':
3116 $additional_settings = $additional_settings->withSkillsServiceEnabled((
bool) $metadata[
'entry']);
3118 case 'show_grading_status':
3119 $result_summary_settings = $result_summary_settings->withShowGradingStatusEnabled((
bool) $metadata[
"entry"]);
3121 case 'show_grading_mark':
3122 $result_summary_settings = $result_summary_settings->withShowGradingMarkEnabled((
bool) $metadata[
"entry"]);
3124 case 'activation_limited':
3127 case 'activation_start_time':
3130 case 'activation_end_time':
3133 case 'activation_visibility':
3137 $question_behaviour_settings = $question_behaviour_settings->withAutosaveEnabled((
bool) $metadata[
'entry']);
3139 case 'autosave_ival':
3140 $question_behaviour_settings = $question_behaviour_settings->withAutosaveInterval((
int) $metadata[
'entry']);
3142 case 'show_summary':
3143 $participant_functionality_settings = $participant_functionality_settings->withQuestionListEnabled(($metadata[
'entry'] & 1) > 0)
3144 ->withUsrPassOverviewMode((
int) $metadata[
'entry']);
3147 case 'hide_info_tab':
3148 $additional_settings = $additional_settings->withHideInfoTab($metadata[
'entry'] ===
'1');
3150 if (preg_match(
"/mark_step_\d+/", $metadata[
"label"])) {
3151 $xmlmark = $metadata[
"entry"];
3152 preg_match(
"/<short>(.*?)<\/short>/", $xmlmark, $matches);
3153 $mark_short = $matches[1];
3154 preg_match(
"/<official>(.*?)<\/official>/", $xmlmark, $matches);
3155 $mark_official = $matches[1];
3156 preg_match(
"/<percentage>(.*?)<\/percentage>/", $xmlmark, $matches);
3157 $mark_percentage = (float) $matches[1];
3158 preg_match(
"/<passed>(.*?)<\/passed>/", $xmlmark, $matches);
3159 $mark_passed = (bool) $matches[1];
3160 $mark_steps[] =
new Mark($mark_short, $mark_official, $mark_percentage, $mark_passed);
3163 $this->mark_schema = $this->
getMarkSchema()->withMarkSteps($mark_steps);
3171 $main_settings = $main_settings
3173 ->withIntroductionSettings($introduction_settings)
3174 ->withAccessSettings($access_settings)
3175 ->withParticipantFunctionalitySettings($participant_functionality_settings)
3176 ->withTestBehaviourSettings($test_behaviour_settings)
3177 ->withQuestionBehaviourSettings($question_behaviour_settings)
3178 ->withFinishingSettings($finishing_settings)
3179 ->withAdditionalSettings($additional_settings);
3183 $score_settings = $score_settings
3185 ->withScoringSettings($scoring_settings)
3186 ->withResultDetailsSettings($result_details_settings)
3187 ->withResultSummarySettings($result_summary_settings);
3199 $text = $material[
'text'];
3200 $mobs = $material[
'mobs'];
3201 if (str_starts_with($text,
'<PageObject>')) {
3204 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
3208 $mappings[
'components/ILIAS/File'][
'file'] ?? []
3211 $page_object->setParentId($this->
getId());
3212 $page_object->setXMLContent($text);
3213 $new_page_id = $page_object->createPageWithNextId();
3233 $text = $material[
'text'];
3234 $mobs = $material[
'mobs'];
3235 if (str_starts_with($text,
'<PageObject>')) {
3238 $mappings[
'components/ILIAS/MediaObjects'][
'mob'] ?? []
3242 $mappings[
'components/ILIAS/File'][
'file'] ?? []
3245 $page_object->setParentId($this->
getId());
3246 $page_object->setXMLContent($text);
3247 $new_page_id = $page_object->createPageWithNextId();
3268 preg_match_all(
'/il_(\d+)_mob_(\d+)/', $text, $matches);
3269 foreach ($matches[0] as $index => $match) {
3270 if (empty($mappings[$matches[2][$index]])) {
3273 $text = str_replace($match,
"il__mob_{$mappings[$matches[2][$index]]}", $text);
3281 preg_match_all(
'/il_(\d+)_file_(\d+)/', $text, $matches);
3282 foreach ($matches[0] as $index => $match) {
3283 if (empty($mappings[$matches[2][$index]])) {
3286 $text = str_replace($match,
"il__file_{$mappings[$matches[2][$index]]}", $text);
3293 foreach ($mobs as $mob) {
3294 $importfile = $importdir . DIRECTORY_SEPARATOR . $mob[
'uri'];
3295 if (file_exists($importfile)) {
3300 'src="' . $mob[
'mob'] .
'"',
3301 'src="' .
'il_' .
IL_INST_ID .
'_mob_' . $media_object->getId() .
'"',
3321 $a_xml_writer->xmlHeader();
3322 $a_xml_writer->xmlSetDtdDef(
"<!DOCTYPE questestinterop SYSTEM \"ims_qtiasiv1p2p1.dtd\">");
3323 $a_xml_writer->xmlStartTag(
"questestinterop");
3329 $a_xml_writer->xmlStartTag(
"assessment", $attrs);
3333 $a_xml_writer->xmlElement(
3340 $a_xml_writer->xmlStartTag(
"qtimetadata");
3341 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3342 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ILIAS_VERSION");
3344 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3346 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3347 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"anonymity");
3348 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $main_settings->
getGeneralSettings()->getAnonymity()));
3349 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3351 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3352 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"question_set_type");
3353 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getGeneralSettings()->getQuestionSetType());
3354 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3356 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3357 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"sequence_settings");
3359 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3361 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3362 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"author");
3363 $a_xml_writer->xmlElement(
"fieldentry",
null, $this->
getAuthor());
3364 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3366 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3367 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"reset_processing_time");
3369 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3371 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3372 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"count_system");
3374 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3376 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3377 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"score_cutting");
3379 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3381 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3382 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"password");
3383 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getPassword() ??
'');
3384 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3386 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3387 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ip_range_from");
3388 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getAccessSettings()->getIpRangeFrom());
3389 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3391 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3392 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ip_range_to");
3394 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3396 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3397 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"pass_scoring");
3399 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3401 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3402 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'pass_deletion_allowed');
3404 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3407 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3408 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"reporting_date");
3409 $a_xml_writer->xmlElement(
3416 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3419 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3420 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"nr_of_tries");
3422 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3424 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3425 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'block_after_passed');
3427 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3429 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3430 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"pass_waiting");
3432 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3434 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3435 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"kiosk");
3437 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3439 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3440 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"redirection_mode");
3442 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3444 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3445 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"redirection_url");
3447 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3449 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3450 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"use_previous_answers");
3452 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3454 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3455 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'question_list_enabled');
3457 $a_xml_writer->xmlEndTag(
'qtimetadatafield');
3459 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3460 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"title_output");
3462 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3464 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3465 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"results_presentation");
3466 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $this->
getScoreSettings()->getResultDetailsSettings()->getResultsPresentation()));
3467 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3469 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3470 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"examid_in_test_pass");
3471 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $main_settings->
getTestBehaviourSettings()->getExamIdInTestAttemptEnabled()));
3472 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3474 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3475 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"examid_in_test_res");
3476 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $this->
getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults()));
3477 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3479 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3480 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"usr_pass_overview_mode");
3482 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3484 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3485 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"score_reporting");
3486 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", $this->
getScoreSettings()->getResultSummarySettings()->getScoreReporting()->value));
3487 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3489 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3490 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_solution_list_comparison");
3491 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $this->score_settings->getResultDetailsSettings()->getShowSolutionListComparison());
3492 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3494 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3495 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_verification");
3497 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3499 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3500 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"answer_feedback");
3502 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3504 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3505 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_specific");
3507 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3509 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3510 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"answer_feedback_points");
3512 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3514 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3515 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"follow_qst_answer_fixation");
3517 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3519 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3520 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_answer_fixation");
3522 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3524 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3525 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"force_instant_feedback");
3527 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3529 $highscore_metadata = [
3540 foreach ($highscore_metadata as $label =>
$data) {
3541 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3542 $a_xml_writer->xmlElement(
"fieldlabel",
null, $label);
3543 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d",
$data[
'value']));
3544 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3547 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3548 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"suspend_test_allowed");
3550 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3552 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3553 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_marker");
3555 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3557 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3558 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"fixed_participants");
3559 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getAccessSettings()->getFixedParticipants()));
3560 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3562 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3563 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_introduction");
3564 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getIntroductionSettings()->getIntroductionEnabled()));
3565 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3567 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3568 $a_xml_writer->xmlElement(
"fieldlabel",
null,
'exam_conditions');
3569 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getIntroductionSettings()->getExamConditionsCheckboxEnabled()));
3570 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3572 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3573 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_concluding_remarks");
3574 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
"%d", (
int) $main_settings->
getFinishingSettings()->getConcludingRemarksEnabled()));
3575 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3577 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3578 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mailnotification");
3579 $a_xml_writer->xmlElement(
"fieldentry",
null, $main_settings->
getFinishingSettings()->getMailNotificationContentType());
3580 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3582 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3583 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mailnottype");
3584 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getFinishingSettings()->getAlwaysSendMailNotification());
3585 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3587 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3588 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"exportsettings");
3590 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3592 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3593 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"shuffle_questions");
3595 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3597 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3598 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"processing_time");
3600 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3602 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3603 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"enable_examview");
3604 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getFinishingSettings()->getShowAnswerOverview());
3605 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3607 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3608 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"skill_service");
3609 $a_xml_writer->xmlElement(
"fieldentry",
null, (
int) $main_settings->
getAdditionalSettings()->getSkillsServiceEnabled());
3610 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3614 "solutionswitch" =>
"Yes" 3619 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs,
null);
3621 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3622 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_grading_status");
3624 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3626 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3627 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"show_grading_mark");
3629 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3631 $a_xml_writer->xmlStartTag(
'qtimetadatafield');
3632 $a_xml_writer->xmlElement(
'fieldlabel',
null,
'hide_info_tab');
3633 $a_xml_writer->xmlElement(
'fieldentry',
null, (
int) $this->
getMainSettings()->getAdditionalSettings()->getHideInfoTab());
3634 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3637 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3638 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"starting_time");
3639 $a_xml_writer->xmlElement(
3646 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3650 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3651 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"ending_time");
3652 $a_xml_writer->xmlElement(
3659 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3662 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3663 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"activation_limited");
3665 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3667 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3668 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"activation_start_time");
3670 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3672 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3673 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"activation_end_time");
3675 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3677 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3678 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"activation_visibility");
3680 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3682 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3683 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"autosave");
3685 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3687 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3688 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"autosave_ival");
3690 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3692 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3693 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_specific");
3695 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3697 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3698 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"instant_feedback_answer_fixation");
3700 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3702 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3703 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"enable_processing_time");
3705 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3707 foreach ($this->
getMarkSchema()->getMarkSteps() as $index => $mark) {
3708 $a_xml_writer->xmlStartTag(
"qtimetadatafield");
3709 $a_xml_writer->xmlElement(
"fieldlabel",
null,
"mark_step_$index");
3710 $a_xml_writer->xmlElement(
"fieldentry",
null, sprintf(
3711 "<short>%s</short><official>%s</official><percentage>%.2f</percentage><passed>%d</passed>",
3712 $mark->getShortName(),
3713 $mark->getOfficialName(),
3714 $mark->getMinimumLevel(),
3717 $a_xml_writer->xmlEndTag(
"qtimetadatafield");
3719 $a_xml_writer->xmlEndTag(
"qtimetadata");
3722 $introduction = $page_id !==
null 3723 ? (
new ilTestPage($page_id))->getXMLContent()
3726 $a_xml_writer->xmlStartTag(
"objectives");
3728 $a_xml_writer->xmlEndTag(
"objectives");
3732 "solutionswitch" =>
"Yes" 3737 $a_xml_writer->xmlElement(
"assessmentcontrol", $attrs,
null);
3741 $concluding_remarks = $page_id !==
null 3742 ? (
new ilTestPage($page_id))->getXMLContent()
3745 $a_xml_writer->xmlStartTag(
"presentation_material");
3746 $a_xml_writer->xmlStartTag(
"flow_mat");
3747 $this->
addQTIMaterial($a_xml_writer, $page_id, $concluding_remarks);
3748 $a_xml_writer->xmlEndTag(
"flow_mat");
3749 $a_xml_writer->xmlEndTag(
"presentation_material");
3755 $a_xml_writer->xmlElement(
"section", $attrs,
null);
3756 $a_xml_writer->xmlEndTag(
"assessment");
3757 $a_xml_writer->xmlEndTag(
"questestinterop");
3759 $xml = $a_xml_writer->xmlDumpMem(
false);
3765 return $date_time->setTimezone(
new DateTimeZone(
'UTC'))->format(
'\PY\Yn\Mj\D\TG\Hi\Ms\S');
3770 if ($period ===
null) {
3773 if (preg_match(
"/P(\d+)Y(\d+)M(\d+)DT(\d+)H(\d+)M(\d+)S/", $period, $matches)) {
3776 "%02d-%02d-%02d %02d:%02d:%02d",
3796 public function exportPagesXML(&$a_xml_writer, $a_inst, $a_target_dir, &$expLog): void
3798 $this->mob_ids = [];
3801 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Page Objects");
3802 $this->bench->start(
"ContentObjectExport",
"exportPageObjects");
3804 $this->bench->stop(
"ContentObjectExport",
"exportPageObjects");
3805 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Page Objects");
3808 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export Media Objects");
3809 $this->bench->start(
"ContentObjectExport",
"exportMediaObjects");
3811 $this->bench->stop(
"ContentObjectExport",
"exportMediaObjects");
3812 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export Media Objects");
3815 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Start Export File Items");
3816 $this->bench->start(
"ContentObjectExport",
"exportFileItems");
3818 $this->bench->stop(
"ContentObjectExport",
"exportFileItems");
3819 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Finished Export File Items");
3829 if ($a_tag ==
"Identifier" && $a_param ==
"Entry") {
3845 foreach ($this->questions as $question_id) {
3846 $this->bench->start(
"ContentObjectExport",
"exportPageObject");
3847 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Page Object " . $question_id);
3850 $a_xml_writer->xmlStartTag(
"PageObject", $attrs);
3854 $this->bench->start(
"ContentObjectExport",
"exportPageObject_XML");
3856 $page_object->buildDom();
3857 $page_object->insertInstIntoIDs((
string) $inst);
3858 $mob_ids = $page_object->collectMediaObjects(
false);
3860 $xml = $page_object->getXMLFromDom(
false,
false,
false,
"",
true);
3861 $xml = str_replace(
"&",
"&", $xml);
3862 $a_xml_writer->appendXML($xml);
3863 $page_object->freeDom();
3864 unset($page_object);
3866 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_XML");
3869 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectMedia");
3871 foreach ($mob_ids as $mob_id) {
3872 $this->mob_ids[$mob_id] = $mob_id;
3874 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectMedia");
3877 $this->bench->start(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
3879 foreach ($file_ids as $file_id) {
3880 $this->file_ids[$file_id] = $file_id;
3882 $this->bench->stop(
"ContentObjectExport",
"exportPageObject_CollectFileItems");
3884 $a_xml_writer->xmlEndTag(
"PageObject");
3887 $this->bench->stop(
"ContentObjectExport",
"exportPageObject");
3896 foreach ($this->mob_ids as $mob_id) {
3897 $expLog->write(date(
"[y-m-d H:i:s] ") .
"Media Object " . $mob_id);
3899 $target_dir = $a_target_dir . DIRECTORY_SEPARATOR .
'objects' 3900 . DIRECTORY_SEPARATOR .
'il_' .
IL_INST_ID .
'_mob_' . $mob_id;
3903 $media_obj->exportXML($a_xml_writer, (
int) $a_inst);
3904 foreach ($media_obj->getMediaItems() as $item) {
3905 $stream = $item->getLocationStream();
3906 file_put_contents($target_dir . DIRECTORY_SEPARATOR . $item->getLocation(), $stream);
3920 foreach ($this->file_ids as $file_id) {
3921 $expLog->write(date(
"[y-m-d H:i:s] ") .
"File Item " . $file_id);
3922 $file_dir = $target_dir .
'/objects/il_' .
IL_INST_ID .
'_file_' . $file_id;
3924 $file_obj =
new ilObjFile((
int) $file_id,
false);
3925 $source_file = $file_obj->getFile($file_obj->getVersion());
3926 if (!is_file($source_file)) {
3927 $source_file = $file_obj->getFile();
3929 if (is_file($source_file)) {
3930 copy($source_file, $file_dir .
'/' . $file_obj->getFileName());
3949 $this->
saveCompleteStatus($this->question_set_config_factory->getQuestionSetConfig());
3962 $results_summary_settings = $this->
getScoreSettings()->getResultSummarySettings();
3964 || $results_summary_settings->getScoreReporting()->isReportingEnabled() ===
false) {
3968 if ($results_summary_settings->getScoreReporting() === ScoreReportingTypes::SCORE_REPORTING_DATE) {
3969 return $results_summary_settings->getReportingDate()
3987 $path_to_lifecycle = $this->lo_metadata->paths()->custom()->withNextStep(
'lifeCycle')->get();
3988 $path_to_authors = $this->lo_metadata->paths()->authors();
3990 $reader = $this->lo_metadata->read($this->
getId(), 0, $this->
getType(), $path_to_lifecycle);
3991 if (!is_null($reader->allData($path_to_lifecycle)->current())) {
3995 if ($author ===
'') {
3996 $author = $this->
user->getFullname();
3998 $this->lo_metadata->manipulate($this->
getId(), 0, $this->
getType())
3999 ->prepareCreateOrUpdate($path_to_authors, $author)
4020 $path_to_authors = $this->lo_metadata->paths()->authors();
4021 $author_data = $this->lo_metadata->read($this->
getId(), 0, $this->
getType(), $path_to_authors)
4022 ->allData($path_to_authors);
4024 return $this->lo_metadata->dataHelper()->makePresentableAsList(
', ', ...$author_data);
4038 $lo_metadata = $DIC->learningObjectMetadata();
4040 $path_to_authors = $lo_metadata->paths()->authors();
4041 $author_data = $lo_metadata->read($obj_id, 0,
"tst", $path_to_authors)
4042 ->allData($path_to_authors);
4044 return $lo_metadata->dataHelper()->makePresentableAsList(
',', ...$author_data);
4056 $ilUser = $DIC[
'ilUser'];
4059 $tests = array_slice(
4067 if (count($tests)) {
4070 if ($use_object_id) {
4072 $result_array[$obj_id] = $titles[
$ref_id];
4078 return $result_array;
4093 $new_obj = parent::cloneObject($target_id, $copy_id, $omit_tree);
4094 $new_obj->setTmpCopyWizardCopyId($copy_id);
4097 $new_obj->saveToDb();
4098 $new_obj->addToNewsOnOnline(
false, $new_obj->getObjectProperties()->getPropertyIsOnline()->getIsOnline());
4101 ->withIntroductionSettings(
4102 $this->
getMainSettings()->getIntroductionSettings()->withIntroductionPageId(
4104 )->withTestId($new_obj->getTestId())
4105 )->withFinishingSettings(
4106 $this->
getMainSettings()->getFinishingSettings()->withConcludingRemarksPageId(
4108 )->withTestId($new_obj->getTestId())
4114 $this->marks_repository->storeMarkSchema(
4127 $templateRepository,
4131 $cloneAction->cloneCertificate($this, $new_obj);
4133 $this->question_set_config_factory->getQuestionSetConfig()->cloneQuestionSetRelatedData($new_obj);
4134 $new_obj->saveQuestionsToDb();
4137 $skillLevelThresholdList->setTestId($this->
getTestId());
4138 $skillLevelThresholdList->loadFromDb();
4139 $skillLevelThresholdList->cloneListForTest($new_obj->getTestId());
4142 $obj_settings->cloneSettings($new_obj->getId());
4144 if ($new_obj->getTestLogger()->isLoggingEnabled()) {
4145 $new_obj->getTestLogger()->logTestAdministrationInteraction(
4146 $new_obj->getTestLogger()->getInteractionFactory()->buildTestAdministrationInteraction(
4147 $new_obj->getRefId(),
4148 $this->
user->getId(),
4149 TestAdministrationInteractionTypes::NEW_TEST_CREATED,
4168 $this->component_repository,
4170 $this->questionrepository
4173 $questionSetConfig->loadFromDb();
4175 if ($questionSetConfig->isQuestionAmountConfigurationModePerPool()) {
4182 $sourcePoolDefinitionList->loadDefinitions();
4184 if (is_int($sourcePoolDefinitionList->getQuestionAmount())) {
4185 $num = $sourcePoolDefinitionList->getQuestionAmount();
4187 } elseif (is_int($questionSetConfig->getQuestionAmountPerTest())) {
4188 $num = $questionSetConfig->getQuestionAmountPerTest();
4192 $num = count($this->questions);
4203 return count($this->questions);
4216 $ilDB = $DIC[
'ilDB'];
4218 $result =
$ilDB->queryF(
4219 "SELECT obj_fi FROM tst_tests WHERE test_id = %s",
4223 if ($result->numRows()) {
4224 $row =
$ilDB->fetchAssoc($result);
4225 $object_id = $row[
"obj_fi"];
4240 $ilDB = $DIC[
'ilDB'];
4242 $result =
$ilDB->queryF(
4243 "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",
4247 if ($result->numRows()) {
4248 $row =
$ilDB->fetchAssoc($result);
4249 $object_id = $row[
"obj_fi"];
4264 $ilDB = $DIC[
'ilDB'];
4266 $result =
$ilDB->queryF(
4267 "SELECT test_id FROM tst_tests WHERE obj_fi = %s",
4271 if ($result->numRows()) {
4272 $row =
$ilDB->fetchAssoc($result);
4273 $test_id = $row[
"test_id"];
4288 if (($active_id) && ($question_id)) {
4289 if ($pass ===
null) {
4292 if ($pass ===
null) {
4295 $query = $this->db->queryF(
4296 "SELECT value1 FROM tst_solutions WHERE active_fi = %s AND question_fi = %s AND pass = %s",
4297 [
'integer',
'integer',
'integer'],
4298 [$active_id, $question_id, $pass]
4300 $result = $this->db->fetchAll($query);
4301 if (count($result) == 1) {
4302 return $result[0][
"value1"];
4319 $result = $this->db->queryF(
4320 "SELECT question_text FROM qpl_questions WHERE question_id = %s",
4324 if ($result->numRows() == 1) {
4325 $row = $this->db->fetchAssoc($result);
4326 $res = $row[
"question_text"];
4337 return $participant_list;
4352 $result = $this->db->queryF(
4353 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
4354 "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 " .
4355 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4356 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4358 [
'text',
'text',
'text',
'integer',
'integer'],
4362 $result = $this->db->queryF(
4363 "SELECT tst_active.active_id, tst_active.tries, usr_id, %s login, %s lastname, %s firstname, " .
4364 "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 " .
4365 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4366 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4368 [
'text',
'text',
'text',
'integer'],
4369 [
'', $this->
lng->txt(
'anonymous'),
'', $this->
getTestId()]
4374 $result = $this->db->queryF(
4375 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
4376 "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 " .
4377 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4378 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id AND usr_data.usr_id=%s " .
4380 [
'integer',
'integer'],
4384 $result = $this->db->queryF(
4385 "SELECT tst_active.active_id, tst_active.tries, usr_id, login, lastname, firstname, " .
4386 "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 " .
4387 "LEFT JOIN tst_active ON tst_active.user_fi = tst_invited_user.user_fi AND tst_active.test_fi = tst_invited_user.test_fi " .
4388 "WHERE tst_invited_user.test_fi = %s and tst_invited_user.user_fi=usr_data.usr_id " .
4396 while ($row = $this->db->fetchAssoc($result)) {
4397 $result_array[$row[
'usr_id']] = $row;
4399 return $result_array;
4406 SELECT tst_active.active_id, 4408 tst_active.user_fi usr_id, 4412 tst_active.submitted test_finished, 4413 usr_data.matriculation, 4415 tst_active.lastindex, 4416 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes 4419 ON tst_active.user_fi = usr_data.usr_id 4420 WHERE tst_active.test_fi = %s 4421 ORDER BY usr_data.lastname 4423 $result = $this->db->queryF(
4425 [
'text',
'text',
'text',
'integer'],
4426 [
'', $this->
lng->txt(
"anonymous"),
"", $this->
getTestId()]
4430 SELECT tst_active.active_id, 4432 tst_active.user_fi usr_id, 4436 tst_active.submitted test_finished, 4437 usr_data.matriculation, 4439 tst_active.lastindex, 4440 COALESCE(tst_active.last_finished_pass, -1) <> tst_active.last_started_pass unfinished_passes 4443 ON tst_active.user_fi = usr_data.usr_id 4444 WHERE tst_active.test_fi = %s 4445 ORDER BY usr_data.lastname 4447 $result = $this->db->queryF(
4454 while ($row = $this->db->fetchAssoc($result)) {
4455 $data[$row[
'active_id']] = $row;
4457 foreach (
$data as $index => $participant) {
4458 if (strlen(trim($participant[
"firstname"] . $participant[
"lastname"])) == 0) {
4459 $data[$index][
"lastname"] = $this->
lng->txt(
"deleted_user");
4471 $filtered_participants = [];
4473 if ($participant[
'tries'] > 0) {
4476 if ($this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
4477 $filtered_participants[$active_id] = $participant;
4481 if (!$this->test_man_scoring_done_helper->isDone((
int) $active_id)) {
4482 $filtered_participants[$active_id] = $participant;
4486 $filtered_participants[$active_id] = $participant;
4490 return $filtered_participants;
4501 if (!is_array($ids) || count($ids) == 0) {
4506 $result = $this->db->queryF(
4507 "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",
4508 [
'text',
'text',
'text'],
4509 [
"", $this->
lng->txt(
"anonymous"),
""]
4512 $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");
4516 while ($row = $this->db->fetchAssoc($result)) {
4517 $result_array[$row[
"usr_id"]] = $row;
4519 return $result_array;
4524 if (!is_array($ids) || count($ids) == 0) {
4537 if (!is_array($ids) || count($ids) == 0) {
4541 foreach ($ids as $obj_id) {
4555 $this->db->manipulateF(
4556 "DELETE FROM tst_invited_user WHERE test_fi = %s AND user_fi = %s",
4557 [
'integer',
'integer'],
4560 $this->db->manipulateF(
4561 "INSERT INTO tst_invited_user (test_fi, user_fi, ip_range_from, ip_range_to, tstamp) VALUES (%s, %s, %s, %s, %s)",
4562 [
'integer',
'integer',
'text',
'text',
'integer'],
4563 [$this->
getTestId(),
$user_id, (strlen($client_ip)) ? $client_ip :
null, (strlen($client_ip)) ? $client_ip : null,time()]
4575 $ilDB = $DIC[
'ilDB'];
4576 if (is_numeric($question_fi)) {
4577 $result =
$ilDB->queryF(
4578 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s AND question_fi=%s",
4579 [
'integer',
'integer'],
4580 [$active_id, $question_fi]
4583 $result =
$ilDB->queryF(
4584 "SELECT question_fi, solved FROM tst_qst_solved WHERE active_fi = %s",
4590 while ($row =
$ilDB->fetchAssoc($result)) {
4591 $result_array[$row[
"question_fi"]] = $row;
4593 return $result_array;
4603 $this->db->manipulateF(
4604 "DELETE FROM tst_qst_solved WHERE active_fi = %s AND question_fi = %s",
4605 [
'integer',
'integer'],
4606 [$active_id, $question_id]
4608 $this->db->manipulateF(
4609 "INSERT INTO tst_qst_solved (solved, question_fi, active_fi) VALUES (%s, %s, %s)",
4610 [
'integer',
'integer',
'integer'],
4611 [$value, $question_id, $active_id]
4620 $result = $this->db->queryF(
4621 "SELECT submitted FROM tst_active WHERE active_id=%s AND submitted=%s",
4622 [
'integer',
'integer'],
4625 return $result->numRows() == 1;
4637 $result = $this->db->queryF(
4638 "SELECT submitted FROM tst_active WHERE test_fi=%s AND user_fi=%s AND submitted=%s",
4639 [
'integer',
'integer',
'integer'],
4642 return $result->numRows() == 1;
4676 "user_id" => $this->
lng->txt(
"user_id"),
4677 "matriculation" => $this->
lng->txt(
"matriculation"),
4678 "lastname" => $this->
lng->txt(
"lastname"),
4679 "firstname" => $this->
lng->txt(
"firstname"),
4680 "login" => $this->
lng->txt(
"login"),
4681 "reached_points" => $this->
lng->txt(
"tst_reached_points"),
4682 "max_points" => $this->
lng->txt(
"tst_maximum_points"),
4683 "percent_value" => $this->
lng->txt(
"tst_percent_solved"),
4684 "mark" => $this->
lng->txt(
"tst_mark"),
4685 "passed" => $this->
lng->txt(
"tst_mark_passed"),
4688 if (count($participants)) {
4689 foreach ($participants as $active_id => $user_rec) {
4692 $reached_points = 0;
4696 if (!is_int($pass)) {
4699 foreach ($this->questions as $value) {
4701 if (is_object($question)) {
4702 $max_points += $question->getMaximumPoints();
4703 $reached_points += $question->getReachedPoints($active_id, $pass);
4706 if ($max_points > 0) {
4707 $percentvalue = $reached_points / $max_points;
4708 if ($percentvalue < 0) {
4709 $percentvalue = 0.0;
4714 $mark_obj = $this->
getMarkSchema()->getMatchingMark($percentvalue * 100);
4716 if ($mark_obj !==
null) {
4717 $mark = $mark_obj->getOfficialName();
4720 $user_rec[
'firstname'] =
"";
4721 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
4724 "user_id" => $user_rec[
'usr_id'],
4725 "matriculation" => $user_rec[
'matriculation'],
4726 "lastname" => $user_rec[
'lastname'],
4727 "firstname" => $user_rec[
'firstname'],
4728 "login" => $user_rec[
'login'],
4729 "reached_points" => $reached_points,
4730 "max_points" => $max_points,
4731 "percent_value" => $percentvalue,
4733 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
4751 $ilDB = $DIC[
'ilDB'];
4752 $result =
$ilDB->queryF(
4753 "SELECT tries FROM tst_active WHERE active_id = %s",
4757 if ($result->numRows()) {
4758 $row =
$ilDB->fetchAssoc($result);
4759 return $row[
"tries"];
4777 $ilDB = $DIC[
'ilDB'];
4778 $result =
$ilDB->queryF(
4779 "SELECT MAX(pass) maxpass FROM tst_pass_result WHERE active_fi = %s",
4784 if ($result->numRows()) {
4785 $row =
$ilDB->fetchAssoc($result);
4786 return $row[
"maxpass"];
4800 $ilDB = $DIC[
'ilDB'];
4802 $result =
$ilDB->queryF(
4803 "SELECT * FROM tst_pass_result WHERE active_fi = %s",
4808 if (!$result->numRows()) {
4814 while ($row =
$ilDB->fetchAssoc($result)) {
4815 if ($row[
"maxpoints"] > 0.0) {
4816 $factor = (float) ($row[
"points"] / $row[
"maxpoints"]);
4820 if ($factor === 0.0 && $bestfactor === 0.0
4821 || $factor > $bestfactor) {
4823 $bestfactor = $factor;
4827 if (is_array($bestrow)) {
4828 return $bestrow[
"pass"];
4844 $counted_pass =
null;
4850 return $counted_pass;
4868 foreach ($this->questions as $value) {
4869 if ($this->questionrepository->lookupResultRecordExist($active_id, $value, $pass)) {
4870 $workedthrough += 1;
4873 return $workedthrough;
4885 $ilDB = $DIC[
'ilDB'];
4887 if (is_null($pass)) {
4892 SELECT tst_pass_result.tstamp pass_res_tstamp, 4893 tst_test_result.tstamp quest_res_tstamp 4895 FROM tst_pass_result 4897 LEFT JOIN tst_test_result 4898 ON tst_test_result.active_fi = tst_pass_result.active_fi 4899 AND tst_test_result.pass = tst_pass_result.pass 4901 WHERE tst_pass_result.active_fi = %s 4902 AND tst_pass_result.pass = %s 4904 ORDER BY tst_test_result.tstamp DESC 4907 $result =
$ilDB->queryF(
4909 [
'integer',
'integer'],
4913 while ($row =
$ilDB->fetchAssoc($result)) {
4914 if ($row[
'quest_res_tstamp']) {
4915 return $row[
'quest_res_tstamp'];
4918 return $row[
'pass_res_tstamp'];
4935 "executable" =>
true,
4936 "errormessage" =>
"" 4940 $result[
"executable"] =
false;
4941 $result[
"errormessage"] = $this->
lng->txt(
'autosave_failed') .
': ' . $this->
lng->txt(
'offline');
4946 $result[
"executable"] =
false;
4951 $result[
"executable"] =
false;
4962 $result[
"executable"] =
false;
4963 $result[
"errormessage"] = $this->
lng->txt(
"detail_max_processing_time_reached");
4968 $testPassesSelector->setActiveId($active_id);
4969 $testPassesSelector->setLastFinishedPass($test_session->getLastFinishedPass());
4972 $closedPasses = $testPassesSelector->getClosedPasses();
4975 $result[
"executable"] =
false;
4976 $result[
"errormessage"] = $this->
lng->txt(
"maximum_nr_of_tries_reached");
4981 if ($this->test_result_repository->isPassed(
$user_id, $this->getId())) {
4982 $result[
'executable'] =
false;
4983 $result[
'errormessage'] = $this->
lng->txt(
"tst_addit_passes_blocked_after_passed_msg");
4989 $next_pass_allowed_timestamp = 0;
4990 if (!$this->
isNextPassAllowed($testPassesSelector, $next_pass_allowed_timestamp)) {
4993 $result[
'executable'] =
false;
4994 $result[
'errormessage'] = sprintf($this->
lng->txt(
'wait_for_next_pass_hint_msg'), $date);
5002 $waiting_between_passes = $this->
getMainSettings()->getTestBehaviourSettings()->getPassWaiting();
5006 $this->
getMainSettings()->getTestBehaviourSettings()->getPassWaitingEnabled()
5007 && ($waiting_between_passes !==
'')
5009 && ($last_finished_pass_timestamp !==
null)
5011 $time_values = explode(
':', $waiting_between_passes);
5012 $next_pass_allowed_timestamp = strtotime(
'+ ' . $time_values[0] .
' Days + ' . $time_values[1] .
' Hours' . $time_values[2] .
' Minutes', $last_finished_pass_timestamp);
5013 return (time() > $next_pass_allowed_timestamp);
5023 $pass_selector->setActiveId($test_session->
getActiveId());
5026 return $pass_selector->hasReportablePasses();
5033 $pass_selector->setActiveId($test_session->
getActiveId());
5036 return $pass_selector->hasExistingPasses();
5048 if ($active_id < 1) {
5051 if ($pass ===
null) {
5054 $result = $this->db->queryF(
5055 "SELECT tst_times.started FROM tst_times WHERE tst_times.active_fi = %s AND tst_times.pass = %s ORDER BY tst_times.started",
5056 [
'integer',
'integer'],
5059 if ($result->numRows()) {
5060 $row = $this->db->fetchAssoc($result);
5061 if (preg_match(
"/(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})/", $row[
"started"], $matches)) {
5092 if ($now > ($starting_time + $processing_time)) {
5101 $tags_trafo = $this->
refinery->string()->stripTags();
5105 questtypes.type_tag, 5107 origquest.obj_fi orig_obj_fi 5109 FROM qpl_questions questions 5111 INNER JOIN qpl_qst_type questtypes 5112 ON questtypes.question_type_id = questions.question_type_fi 5114 INNER JOIN tst_test_question tstquest 5115 ON tstquest.question_fi = questions.question_id 5117 LEFT JOIN qpl_questions origquest 5118 ON origquest.question_id = questions.original_id 5120 WHERE tstquest.test_fi = %s 5122 ORDER BY tstquest.sequence 5125 $query_result = $this->db->queryF(
5133 while ($row = $this->db->fetchAssoc($query_result)) {
5134 $row[
'title'] = $tags_trafo->transform($row[
'title']);
5135 $row[
'description'] = $tags_trafo->transform($row[
'description'] !==
'' && $row[
'description'] !==
null ? $row[
'description'] :
' ');
5136 $row[
'author'] = $tags_trafo->transform($row[
'author']);
5138 $questions[] = $row;
5147 if ($questionData[
'question_id'] != $question_id) {
5159 $row = $this->db->fetchAssoc($this->db->queryF(
5160 "SELECT COUNT(question_id) cnt FROM qpl_questions WHERE question_id = %s AND obj_fi = %s",
5161 [
'integer',
'integer'],
5162 [$question_id, $this->getId()]
5165 return (
bool) $row[
'cnt'];
5173 $points += $question_data[
'points'];
5186 questtypes.type_tag, 5187 origquest.obj_fi orig_obj_fi 5189 FROM qpl_questions questions 5191 INNER JOIN qpl_qst_type questtypes 5192 ON questtypes.question_type_id = questions.question_type_fi 5194 INNER JOIN tst_rnd_cpy tstquest 5195 ON tstquest.qst_fi = questions.question_id 5197 LEFT JOIN qpl_questions origquest 5198 ON origquest.question_id = questions.original_id 5200 WHERE tstquest.tst_fi = %s 5203 $query_result = $this->db->queryF(
5209 return $this->db->fetchAll($query_result);
5214 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getShuffleQuestions();
5230 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewMode();
5235 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getQuestionListEnabled();
5240 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getUsrPassOverviewEnabled();
5245 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtBeginning();
5250 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShownQuestionListAtEnd();
5255 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getShowDescriptionInQuestionList();
5263 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowPassDetails();
5271 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionPrintview();
5286 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionFeedback();
5294 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionAnswersOnly();
5302 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionSignature();
5310 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionSuggested();
5319 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionListComparison();
5324 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowSolutionListOwnAnswers();
5333 $ilDB = $DIC[
'ilDB'];
5334 $result =
$ilDB->queryF(
5335 "SELECT user_fi FROM tst_active WHERE active_id = %s",
5339 if ($result->numRows()) {
5340 $row =
$ilDB->fetchAssoc($result);
5341 return $row[
"user_fi"];
5349 $result = $this->db->queryF(
5350 "SELECT finished FROM tst_times WHERE active_fi = %s ORDER BY finished DESC",
5354 if ($result->numRows()) {
5355 $row = $this->db->fetchAssoc($result);
5356 return $row[
"finished"];
5361 public static function lookupLastTestPassAccess(
int $active_id,
int $pass_index): ?
int 5365 $ilDB = $DIC[
'ilDB'];
5368 SELECT MAX(tst_times.tstamp) as last_pass_access 5370 WHERE active_fi = %s 5376 [
'integer',
'integer'],
5377 [$active_id, $pass_index]
5380 while ($row =
$ilDB->fetchAssoc(
$res)) {
5381 return $row[
'last_pass_access'];
5396 if (preg_match(
"/<[^>]*?>/", $a_text)) {
5413 for ($i = 0; $i < $a_material->getMaterialCount(); $i++) {
5414 $material = $a_material->getMaterial($i);
5415 if ($material[
'type'] ===
'mattext') {
5416 $result .= $material[
'material']->getContent();
5418 if ($material[
'type'] ===
'matimage') {
5419 $matimage = $material[
'material'];
5420 if (preg_match(
'/(il_([0-9]+)_mob_([0-9]+))/', $matimage->getLabel(), $matches)) {
5422 'mob' => $matimage->getLabel(),
5423 'uri' => $matimage->getUri()
5429 $decoded_result = base64_decode($result);
5430 if (str_starts_with($decoded_result,
'<PageObject>')) {
5431 $result = $decoded_result;
5445 'texttype' =>
'text/plain' 5449 if ($page_id !==
null) {
5450 $attrs[
'texttype'] =
'text/xml';
5453 $page_object->buildDom();
5454 $page_object->insertInstIntoIDs((
string)
IL_INST_ID);
5455 $material = base64_encode($page_object->getXMLFromDom());
5457 foreach ($file_ids as $file_id) {
5458 $this->file_ids[] = (
int) $file_id;
5460 $mob_string =
'il_' . IL_INST_ID .
'_mob_';
5461 } elseif ($this->
isHTML($material)) {
5462 $attrs[
'texttype'] =
'text/xhtml';
5464 $mob_string =
'mm_';
5467 $xml_writer->
xmlElement(
'mattext', $attrs, $material);
5468 foreach ($mobs as $mob) {
5469 $mob_id_string = (string) $mob;
5470 $moblabel =
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string;
5471 if (strpos($material, $mob_string . $mob_id_string) !==
false) {
5475 'label' => $moblabel,
5476 'uri' =>
'objects/' .
'il_' .
IL_INST_ID .
'_mob_' . $mob_id_string .
'/' . $mob_obj->getTitle()
5493 if ($txt_output ==
null) {
5498 $prepare_for_latex_output,
5499 $omitNl2BrWhenTextArea
5505 return $this->
getMainSettings()->getGeneralSettings()->getAnonymity();
5512 $ilDB = $DIC[
'ilDB'];
5514 $result =
$ilDB->queryF(
5515 "SELECT anonymity FROM tst_tests WHERE obj_fi = %s",
5519 while ($row =
$ilDB->fetchAssoc($result)) {
5520 return (
int) $row[
'anonymity'];
5527 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getSuspendTestAllowed();
5532 return $this->
getMainSettings()->getParticipantFunctionalitySettings()->getQuestionMarkingEnabled();
5537 return $this->
getMainSettings()->getAccessSettings()->getFixedParticipants();
5543 SELECT tst_tests.question_set_type 5545 INNER JOIN tst_tests 5546 ON tst_active.test_fi = tst_tests.test_id 5547 WHERE tst_active.active_id = %s 5550 $res = $this->db->queryF($query, [
'integer'], [$active_id]);
5552 while ($row = $this->db->fetchAssoc(
$res)) {
5553 return $row[
'question_set_type'];
5572 return $this->
lng->txt(
"anonymous") . $suffix;
5575 if (strlen($uname[
"firstname"] . $uname[
"lastname"]) == 0) {
5576 $uname[
"firstname"] = $this->
lng->txt(
"deleted_user");
5578 if ($sorted_order) {
5579 return trim($uname[
"lastname"] .
", " . $uname[
"firstname"]) . $suffix;
5581 return trim($uname[
"firstname"] .
" " . $uname[
"lastname"]) . $suffix;
5593 $result = $this->db->queryF(
5594 "SELECT * FROM tst_test_defaults WHERE user_fi = %s ORDER BY name ASC",
5596 [$this->
user->getId()]
5599 while ($row = $this->db->fetchAssoc($result)) {
5600 $defaults[$row[
"test_defaults_id"]] = $row;
5607 $result = $this->db->queryF(
5608 "SELECT * FROM tst_test_defaults WHERE test_defaults_id = %s",
5612 if ($result->numRows() == 1) {
5613 $row = $this->db->fetchAssoc($result);
5622 $this->db->manipulateF(
5623 "DELETE FROM tst_test_defaults WHERE test_defaults_id = %s",
5690 'mailnotification' => $main_settings->
getFinishingSettings()->getMailNotificationContentType(),
5723 fn(
Mark $v): array => [
5732 $next_id = $this->db->nextId(
'tst_test_defaults');
5734 'tst_test_defaults',
5736 'test_defaults_id' => [
'integer', $next_id],
5737 'name' => [
'text', $a_name],
5738 'user_fi' => [
'integer', $this->
user->getId()],
5739 'defaults' => [
'clob', serialize($testsettings)],
5740 'marks' => [
'clob', json_encode($marks)],
5741 'tstamp' => [
'integer', time()]
5748 $testsettings = unserialize($test_defaults[
'defaults'], [
'allowed_classes' => [DateTimeImmutable::class]]);
5749 $activation_starting_time = is_numeric($testsettings[
'activation_starting_time'] ??
false)
5750 ? (
int) $testsettings[
'activation_starting_time']
5752 $activation_ending_time = is_numeric($testsettings[
'activation_ending_time'] ??
false)
5753 ? (
int) $testsettings[
'activation_ending_time']
5755 $unserialized_marks = json_decode($test_defaults[
'marks'],
true);
5758 if (is_array($unserialized_marks)
5759 && is_array($unserialized_marks[0])) {
5764 $v[
'official_name'],
5765 $v[
'minimum_level'],
5772 $info =
'old_mark_default_not_applied';
5777 (
bool) ($testsettings[
'is_activation_limited'] ??
false),
5778 $activation_starting_time,
5779 $activation_ending_time,
5780 (
bool) ($testsettings[
'activation_visibility'] ??
false),
5794 $main_settings = $main_settings
5797 ->withQuestionSetType(
5798 $testsettings[
'questionSetType'] ?? $general_settings->getQuestionSetType()
5800 $testsettings[
'Anonymity'] ?? $general_settings->getAnonymity()
5802 )->withIntroductionSettings(
5803 $introduction_settings
5804 ->withIntroductionEnabled(
5805 $testsettings[
'IntroEnabled'] ?? $introduction_settings->getIntroductionEnabled()
5806 )->withExamConditionsCheckboxEnabled(
5807 $testsettings[
'ExamConditionsCheckboxEnabled'] ?? $introduction_settings->getExamConditionsCheckboxEnabled()
5809 )->withAccessSettings(
5811 ->withStartTimeEnabled(
5812 $testsettings[
'StartingTimeEnabled'] ?? $access_settings->getStartTimeEnabled()
5815 $testsettings[
'StartingTime'] ?? $access_settings->getStartTime()
5817 )->withEndTimeEnabled(
5818 $testsettings[
'EndingTimeEnabled'] ?? $access_settings->getEndTimeEnabled()
5821 $testsettings[
'EndingTime'] ?? $access_settings->getEndTime()
5823 )->withPasswordEnabled(
5824 $testsettings[
'password_enabled'] ?? $access_settings->getPasswordEnabled()
5826 $testsettings[
'password'] ?? $access_settings->getPassword()
5827 )->withFixedParticipants(
5828 $testsettings[
'fixed_participants'] ?? $access_settings->getFixedParticipants()
5830 )->withTestBehaviourSettings(
5831 $test_behavior_settings
5832 ->withNumberOfTries(
5833 $testsettings[
'NrOfTries'] ?? $test_behavior_settings->getNumberOfTries()
5834 )->withBlockAfterPassedEnabled(
5835 $testsettings[
'BlockAfterPassed'] ?? $test_behavior_settings->getBlockAfterPassedEnabled()
5837 $testsettings[
'pass_waiting'] ?? $test_behavior_settings->getPassWaiting()
5839 $testsettings[
'Kiosk'] ?? $test_behavior_settings->getKioskMode()
5840 )->withProcessingTimeEnabled(
5841 $testsettings[
'EnableProcessingTime'] ?? $test_behavior_settings->getProcessingTimeEnabled()
5842 )->withProcessingTime(
5843 $testsettings[
'ProcessingTime'] ?? $test_behavior_settings->getProcessingTime()
5844 )->withResetProcessingTime(
5845 $testsettings[
'ResetProcessingTime'] ?? $test_behavior_settings->getResetProcessingTime()
5846 )->withExamIdInTestAttemptEnabled(
5847 $testsettings[
'examid_in_test_pass'] ?? $test_behavior_settings->getExamIdInTestAttemptEnabled()
5849 )->withQuestionBehaviourSettings(
5850 $question_behavior_settings
5851 ->withQuestionTitleOutputMode(
5852 $testsettings[
'TitleOutput'] ?? $question_behavior_settings->getQuestionTitleOutputMode()
5853 )->withAutosaveEnabled(
5854 $testsettings[
'autosave'] ?? $question_behavior_settings->getAutosaveEnabled()
5855 )->withAutosaveInterval(
5856 $testsettings[
'autosave_ival'] ?? $question_behavior_settings->getAutosaveInterval()
5857 )->withShuffleQuestions(
5858 $testsettings[
'Shuffle'] ?? $question_behavior_settings->getShuffleQuestions()
5859 )->withInstantFeedbackPointsEnabled(
5860 $testsettings[
'AnswerFeedbackPoints'] ?? $question_behavior_settings->getInstantFeedbackPointsEnabled()
5861 )->withInstantFeedbackGenericEnabled(
5862 $testsettings[
'AnswerFeedback'] ?? $question_behavior_settings->getInstantFeedbackGenericEnabled()
5863 )->withInstantFeedbackSpecificEnabled(
5864 $testsettings[
'SpecificAnswerFeedback'] ?? $question_behavior_settings->getInstantFeedbackSpecificEnabled()
5865 )->withInstantFeedbackSolutionEnabled(
5866 $testsettings[
'InstantFeedbackSolution'] ?? $question_behavior_settings->getInstantFeedbackSolutionEnabled()
5867 )->withForceInstantFeedbackOnNextQuestion(
5868 $testsettings[
'force_inst_fb'] ?? $question_behavior_settings->getForceInstantFeedbackOnNextQuestion()
5869 )->withLockAnswerOnInstantFeedbackEnabled(
5870 $testsettings[
'inst_fb_answer_fixation'] ?? $question_behavior_settings->getLockAnswerOnInstantFeedbackEnabled()
5871 )->withLockAnswerOnNextQuestionEnabled(
5872 $testsettings[
'follow_qst_answer_fixation'] ?? $question_behavior_settings->getLockAnswerOnNextQuestionEnabled()
5874 )->withParticipantFunctionalitySettings(
5875 $participant_functionality_settings
5876 ->withUsePreviousAnswerAllowed(
5877 $testsettings[
'use_previous_answers'] ?? $participant_functionality_settings->getUsePreviousAnswerAllowed()
5878 )->withSuspendTestAllowed(
5879 $testsettings[
'ShowCancel'] ?? $participant_functionality_settings->getSuspendTestAllowed()
5880 )->withPostponedQuestionsMoveToEnd(
5881 $testsettings[
'SequenceSettings'] ?? $participant_functionality_settings->getPostponedQuestionsMoveToEnd()
5882 )->withUsrPassOverviewMode(
5883 $testsettings[
'ListOfQuestionsSettings'] ?? $participant_functionality_settings->getUsrPassOverviewMode()
5884 )->withQuestionMarkingEnabled(
5885 $testsettings[
'ShowMarker'] ?? $participant_functionality_settings->getQuestionMarkingEnabled()
5887 )->withFinishingSettings(
5889 ->withShowAnswerOverview(
5890 $testsettings[
'enable_examview'] ?? $finishing_settings->getShowAnswerOverview()
5891 )->withConcludingRemarksEnabled(
5892 $testsettings[
'ShowFinalStatement'] ?? $finishing_settings->getConcludingRemarksEnabled()
5893 )->withRedirectionMode(
5894 $testsettings[
'redirection_mode'] ?? $finishing_settings->getRedirectionMode()
5895 )->withRedirectionUrl(
5896 $testsettings[
'redirection_url'] ?? $finishing_settings->getRedirectionUrl()
5897 )->withMailNotificationContentType(
5898 $testsettings[
'mailnotification'] ?? $finishing_settings->getMailNotificationContentType()
5899 )->withAlwaysSendMailNotification(
5900 $testsettings[
'mailnottype'] ?? $finishing_settings->getAlwaysSendMailNotification()
5902 )->withAdditionalSettings(
5903 $additional_settings
5904 ->withSkillsServiceEnabled(
5905 $testsettings[
'skill_service'] ?? $additional_settings->getSkillsServiceEnabled()
5907 $testsettings[
'HideInfoTab'] ?? $additional_settings->getHideInfoTab()
5913 $score_reporting = ScoreReportingTypes::SCORE_REPORTING_DISABLED;
5914 if ($testsettings[
'ScoreReporting'] !==
null) {
5915 $score_reporting = ScoreReportingTypes::tryFrom($testsettings[
'ScoreReporting'])
5916 ?? ScoreReportingTypes::SCORE_REPORTING_DISABLED;
5919 $reporting_date = $testsettings[
'ReportingDate'];
5920 if (is_string($reporting_date)) {
5931 $score_settings = $score_settings
5935 $testsettings[
'PassScoring'] ?? $scoring_settings->getPassScoring()
5936 )->withScoreCutting(
5937 $testsettings[
'ScoreCutting'] ?? $scoring_settings->getScoreCutting()
5939 $testsettings[
'CountSystem'] ?? $scoring_settings->getCountSystem()
5941 )->withResultSummarySettings(
5942 $result_summary_settings
5943 ->withPassDeletionAllowed(
5944 $testsettings[
'pass_deletion_allowed'] ?? $result_summary_settings->getPassDeletionAllowed()
5945 )->withShowGradingStatusEnabled(
5946 $testsettings[
'show_grading_status'] ?? $result_summary_settings->getShowGradingStatusEnabled()
5947 )->withShowGradingMarkEnabled(
5948 $testsettings[
'show_grading_mark'] ?? $result_summary_settings->getShowGradingMarkEnabled()
5949 )->withScoreReporting(
5951 )->withReportingDate(
5954 )->withResultDetailsSettings(
5955 $result_details_settings
5956 ->withResultsPresentation(
5957 $testsettings[
'ResultsPresentation'] ?? $result_details_settings->getResultsPresentation()
5958 )->withShowSolutionListComparison(
5959 $testsettings[
'show_solution_list_comparison'] ?? $result_details_settings->getShowSolutionListComparison()
5960 )->withShowExamIdInTestResults(
5961 $testsettings[
'examid_in_test_res'] ?? $result_details_settings->getShowExamIdInTestResults()
5963 )->withGamificationSettings(
5964 $gamification_settings
5965 ->withHighscoreEnabled(
5966 $testsettings[
'highscore_enabled'] ?? $gamification_settings->getHighscoreEnabled()
5967 )->withHighscoreAnon(
5968 $testsettings[
'highscore_anon'] ?? $gamification_settings->getHighscoreAnon()
5969 )->withHighscoreAchievedTS(
5970 $testsettings[
'highscore_achieved_ts'] ?? $gamification_settings->getHighscoreAchievedTS()
5971 )->withHighscoreScore(
5972 $testsettings[
'highscore_score'] ?? $gamification_settings->getHighscoreScore()
5973 )->withHighscorePercentage(
5974 $testsettings[
'highscore_percentage'] ?? $gamification_settings->getHighscorePercentage()
5975 )->withHighscoreWTime(
5976 $testsettings[
'highscore_wtime'] ?? $gamification_settings->getHighscoreWTime()
5977 )->withHighscoreOwnTable(
5978 $testsettings[
'highscore_own_table'] ?? $gamification_settings->getHighscoreOwnTable()
5979 )->withHighscoreTopTable(
5980 $testsettings[
'highscore_top_table'] ?? $gamification_settings->getHighscoreTopTable()
5981 )->withHighscoreTopNum(
5982 $testsettings[
'highscore_top_num'] ?? $gamification_settings->getHighscoreTopNum()
5999 return DateTimeImmutable::createFromFormat(
'U', (
string) $date_time);
6011 if (extension_loaded(
"tidy")) {
6014 "output-xml" =>
true,
6015 "numeric-entities" => true
6018 $tidy->parseString($print_output, $config,
'utf8');
6019 $tidy->cleanRepair();
6020 $print_output = tidy_get_output($tidy);
6021 $print_output = preg_replace(
"/^.*?(<html)/",
"\\1", $print_output);
6023 $print_output = str_replace(
" ",
" ", $print_output);
6024 $print_output = str_replace(
"⊗",
"X", $print_output);
6026 $xsl = file_get_contents(
"./components/ILIAS/Test/xml/question2fo.xsl");
6031 'font-family="Helvetica, unifont"',
6032 'font-family="' . $this->
settings->get(
'rpc_pdf_font',
'Helvetica, unifont') .
'"',
6036 $args = [
'/_xml' => $print_output,
'/_xsl' => $xsl ];
6037 $xh = xslt_create();
6039 $output = xslt_process($xh,
"arg:/_xml",
"arg:/_xsl",
null, $args,
$params);
6053 $content = preg_replace(
"/href=\".*?\"/",
"", $content);
6054 $printbody =
new ilTemplate(
"tpl.il_as_tst_print_body.html",
true,
true,
"components/ILIAS/Test");
6056 $printbody->setVariable(
"ADM_CONTENT", $content);
6057 $printbody->setCurrentBlock(
"css_file");
6059 $printbody->parseCurrentBlock();
6060 $printoutput = $printbody->get();
6061 $html = str_replace(
"href=\"./",
"href=\"" . ILIAS_HTTP_PATH .
"/", $printoutput);
6062 $html = preg_replace(
"/<div id=\"dontprint\">.*?<\\/div>/ims",
"", $html);
6063 if (extension_loaded(
"tidy")) {
6066 "output-xml" =>
true,
6067 "numeric-entities" => true
6070 $tidy->parseString($html, $config,
'utf8');
6071 $tidy->cleanRepair();
6072 $html = tidy_get_output($tidy);
6073 $html = preg_replace(
"/^.*?(<html)/",
"\\1", $html);
6075 $html = str_replace(
" ",
" ", $html);
6076 $html = str_replace(
"⊗",
"X", $html);
6078 $html = preg_replace(
"/src=\".\\//ims",
"src=\"" . ILIAS_HTTP_PATH .
"/", $html);
6090 $fp = fopen($fo_file,
"w");
6099 $pdf_base64->scalar,
6105 $this->
logger->info(__METHOD__ .
': ' . $e->getMessage());
6121 if ($pass ===
null) {
6125 $row = self::getSingleManualFeedback((
int) $active_id, (
int) $question_id, (
int) $pass);
6128 $feedback = $row[
'feedback'] ??
'';
6137 $ilDB = $DIC[
'ilDB'];
6139 $result =
$ilDB->queryF(
6140 "SELECT * FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s",
6141 [
'integer',
'integer',
'integer'],
6142 [$active_id, $question_id, $pass]
6145 if (
$ilDB->numRows($result) === 1) {
6146 $row =
$ilDB->fetchAssoc($result);
6148 } elseif (
$ilDB->numRows($result) > 1) {
6149 $DIC->logger()->root()->warning(
6150 "WARNING: Multiple feedback entries on tst_manual_fb for " .
6151 "active_fi = $active_id , question_fi = $question_id and pass = $pass" 6168 $ilDB = $DIC[
'ilDB'];
6171 $result =
$ilDB->queryF(
6172 "SELECT * FROM tst_manual_fb WHERE question_fi = %s",
6177 while ($row =
$ilDB->fetchAssoc($result)) {
6178 $active = $row[
'active_fi'];
6179 $pass = $row[
'pass'];
6180 $question = $row[
'question_fi'];
6184 $feedback[$active][$pass][$question] = $row;
6195 bool $finalized =
false 6197 $feedback_old = self::getSingleManualFeedback($active_id, $question_id, $pass);
6198 $this->db->manipulateF(
6199 'DELETE FROM tst_manual_fb WHERE active_fi = %s AND question_fi = %s AND pass = %s',
6200 [
'integer',
'integer',
'integer'],
6201 [$active_id, $question_id, $pass]
6204 $this->
insertManualFeedback($active_id, $question_id, $pass, $feedback, $finalized, $feedback_old);
6216 $next_id = $this->db->nextId(
'tst_manual_fb');
6218 $finalized_time = time();
6221 'manual_feedback_id' => [
'integer', $next_id],
6222 'active_fi' => [
'integer', $active_id],
6223 'question_fi' => [
'integer', $question_id],
6224 'pass' => [
'integer', $pass],
6226 'tstamp' => [
'integer', time()]
6229 if ($feedback_old !== [] && (
int) $feedback_old[
'finalized_evaluation'] === 1) {
6230 $user = $feedback_old[
'finalized_by_usr_id'];
6231 $finalized_time = $feedback_old[
'finalized_tstamp'];
6234 if ($finalized ===
false) {
6235 $update_default[
'finalized_evaluation'] = [
'integer', 0];
6236 $update_default[
'finalized_by_usr_id'] = [
'integer', 0];
6237 $update_default[
'finalized_tstamp'] = [
'integer', 0];
6238 } elseif ($finalized ===
true) {
6239 $update_default[
'finalized_evaluation'] = [
'integer', 1];
6240 $update_default[
'finalized_by_usr_id'] = [
'integer',
$user];
6241 $update_default[
'finalized_tstamp'] = [
'integer', $finalized_time];
6244 $this->db->insert(
'tst_manual_fb', $update_default);
6246 if ($this->
logger->isLoggingEnabled()) {
6247 $this->
logger->logScoringInteraction(
6248 $this->
logger->getInteractionFactory()->buildScoringInteraction(
6251 $this->
user->getId(),
6252 self::_getUserIdFromActiveId($active_id),
6253 TestScoringInteractionTypes::QUESTION_GRADED,
6255 AdditionalInformationGenerator::KEY_EVAL_FINALIZED => $this->
logger 6256 ->getAdditionalInformationGenerator()->getTrueFalseTagForBool($finalized),
6288 $this->test_id = $a_id;
6301 if (count($participants)) {
6302 foreach ($participants as $active_id => $user_rec) {
6304 $reached_points = 0;
6307 foreach ($this->questions as $value) {
6309 if (is_object($question)) {
6310 $max_points += $question->getMaximumPoints();
6311 $reached_points += $question->getReachedPoints($active_id, $pass);
6312 if ($max_points > 0) {
6313 $percentvalue = $reached_points / $max_points;
6314 if ($percentvalue < 0) {
6315 $percentvalue = 0.0;
6321 $user_rec[
'firstname'] =
"";
6322 $user_rec[
'lastname'] = $this->
lng->txt(
"anonymous");
6325 "user_id" => $user_rec[
'usr_id'],
6326 "matriculation" => $user_rec[
'matriculation'],
6327 "lastname" => $user_rec[
'lastname'],
6328 "firstname" => $user_rec[
'firstname'],
6329 "login" => $user_rec[
'login'],
6330 "question_id" => $question->getId(),
6331 "question_title" => $question->getTitle(),
6332 "reached_points" => $reached_points,
6333 "max_points" => $max_points,
6334 "passed" => $user_rec[
'passed'] ?
'1' :
'0',
6349 $ilDB = $DIC[
'ilDB'];
6351 $result =
$ilDB->queryF(
6352 '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',
6356 $rec =
$ilDB->fetchAssoc($result);
6357 return $rec[
'obj_id'] ??
null;
6368 if (!$this->component_repository->getComponentByTypeAndName(
6371 )->getPluginSlotById(
'qst')->hasPluginName($a_pname)) {
6375 return $this->component_repository
6376 ->getComponentByTypeAndName(
6380 ->getPluginSlotById(
6394 SELECT tst_test_result.active_fi, tst_test_result.question_fi, tst_test_result.pass 6395 FROM tst_test_result 6396 INNER JOIN tst_active ON tst_active.active_id = tst_test_result.active_fi AND tst_active.test_fi = %s 6397 INNER JOIN qpl_questions ON qpl_questions.question_id = tst_test_result.question_fi 6398 LEFT JOIN usr_data ON usr_data.usr_id = tst_active.user_fi 6399 WHERE tst_test_result.question_fi = %s 6400 ORDER BY usr_data.lastname ASC, usr_data.firstname ASC 6403 $result = $this->db->queryF(
6405 [
'integer',
'integer'],
6406 [$test_id, $question_id]
6410 while ($row = $this->db->fetchAssoc($result)) {
6415 if (!array_key_exists($row[
"active_fi"], $foundusers)) {
6416 $foundusers[$row[
"active_fi"]] = [];
6418 array_push($foundusers[$row[
"active_fi"]], [
"pass" => $row[
"pass"],
"qid" => $row[
"question_fi"]]);
6426 $found_participants =
$data->getParticipants();
6427 $results = [
'overview' => [],
'questions' => []];
6428 if ($found_participants !== []) {
6429 $results[
'overview'][
'tst_stat_result_mark_median'] =
$data->getStatistics()->getEvaluationDataOfMedianUser()?->getMark()?->getShortName() ??
'';
6430 $results[
'overview'][
'tst_stat_result_rank_median'] =
$data->getStatistics()->rankMedian();
6431 $results[
'overview'][
'tst_stat_result_total_participants'] =
$data->getStatistics()->count();
6432 $results[
'overview'][
'tst_stat_result_median'] =
$data->getStatistics()->median();
6433 $results[
'overview'][
'tst_eval_total_persons'] = count($found_participants);
6434 $total_finished =
$data->getTotalFinishedParticipants();
6435 $results[
'overview'][
'tst_eval_total_finished'] = $total_finished;
6436 $results[
'overview'][
'tst_eval_total_finished_average_time'] =
6441 $total_passed_reached = 0;
6442 $total_passed_max = 0;
6443 $total_passed_time = 0;
6444 foreach ($found_participants as $userdata) {
6445 if ($userdata->getMark()?->getPassed()) {
6447 $total_passed_reached += $userdata->getReached();
6448 $total_passed_max += $userdata->getMaxpoints();
6449 $total_passed_time += $userdata->getTimeOnTask();
6452 $average_passed_reached = $total_passed ? $total_passed_reached / $total_passed : 0;
6453 $average_passed_max = $total_passed ? $total_passed_max / $total_passed : 0;
6454 $average_passed_time = $total_passed ? $total_passed_time / $total_passed : 0;
6455 $results[
'overview'][
'tst_eval_total_passed'] = $total_passed;
6456 $results[
'overview'][
'tst_eval_total_passed_average_points'] = sprintf(
'%2.2f', $average_passed_reached)
6457 .
' ' . strtolower(
'of') .
' ' . sprintf(
'%2.2f', $average_passed_max);
6458 $results[
'overview'][
'tst_eval_total_passed_average_time'] =
6462 foreach (
$data->getQuestionTitles() as $question_id => $question_title) {
6466 foreach ($found_participants as $userdata) {
6467 for ($i = 0; $i <= $userdata->getLastPass(); $i++) {
6468 if (is_object($userdata->getPass($i))) {
6469 $question = $userdata->getPass($i)->getAnsweredQuestionByQuestionId($question_id);
6470 if (is_array($question)) {
6472 $reached += $question[
'reached'];
6473 $max += $question[
'points'];
6478 $percent = $max ? $reached / $max * 100.0 : 0;
6479 $results[
'questions'][$question_id] = [
6481 sprintf(
'%.2f', $answered ? $reached / $answered : 0) .
' ' . strtolower($this->
lng->txt(
'of')) .
' ' . sprintf(
'%.2f', $answered ? $max / $answered : 0),
6482 sprintf(
'%.2f', $percent) .
'%',
6484 sprintf(
'%.2f', $answered ? $reached / $answered : 0),
6485 sprintf(
'%.2f', $answered ? $max / $answered : 0),
6494 $diff_hours = floor($seconds / 3600);
6495 $seconds -= $diff_hours * 3600;
6496 $diff_minutes = floor($seconds / 60);
6497 $seconds -= $diff_minutes * 60;
6498 return sprintf(
'%02d:%02d:%02d', $diff_hours, $diff_minutes, $seconds);
6506 return $this->export_factory->getExporter($this,
'xml')
6512 return $this->
getMainSettings()->getFinishingSettings()->getMailNotificationContentType();
6520 $mail->sendSimpleNotification($owner_id, $this->
getTitle(), $usr_data);
6529 $path = $this->export_factory->getExporter(
6531 ExportImportTypes::SCORED_ATTEMPT
6532 )->withFilterByActiveId($active_id)
6535 $delivered_file_name =
'result_' . $active_id .
'.xlsx';
6537 $fd->copyAttachmentFile(
$path, $delivered_file_name);
6538 $file_names[] = $delivered_file_name;
6540 $mail->sendAdvancedNotification($owner_id, $this->
getTitle(), $usr_data, $file_names);
6542 if (count($file_names)) {
6543 $fd->unlinkFiles($file_names);
6551 return $this->
getMainSettings()->getFinishingSettings()->getAlwaysSendMailNotification();
6556 return $this->
getScoreSettings()->getResultDetailsSettings()->getExportSettings();
6571 $question_set_config = $this->question_set_config_factory->getQuestionSetConfig();
6572 $reindexed_sequence_position_map = $question_set_config->reindexQuestionOrdering();
6576 return $reindexed_sequence_position_map;
6585 foreach (array_keys($order) as
$id) {
6589 UPDATE tst_test_question 6591 WHERE question_fi = %s 6594 $this->db->manipulateF(
6596 [
'integer',
'integer'],
6601 if ($this->
logger->isLoggingEnabled()) {
6602 $this->
logger->logTestAdministrationInteraction(
6603 $this->
logger->getInteractionFactory()->buildTestAdministrationInteraction(
6605 $this->
user->getId(),
6606 TestAdministrationInteractionTypes::QUESTION_MOVED,
6608 AdditionalInformationGenerator::KEY_QUESTION_ORDER => $order
6621 $IN_questions = $this->db->in(
'q1.question_id', array_keys($questions),
false,
'integer');
6624 SELECT count(q1.question_id) cnt 6626 FROM qpl_questions q1 6628 INNER JOIN qpl_questions q2 6629 ON q2.question_id = q1.original_id 6632 AND q1.obj_fi = q2.obj_fi 6634 $rset = $this->db->query($query);
6635 $row = $this->db->fetchAssoc($rset);
6637 return $row[
'cnt'] > 0;
6649 $ilDB = $DIC[
'ilDB'];
6651 $result =
$ilDB->queryF(
6652 "SELECT test_fi,MAX(pass) AS pass FROM tst_active" .
6653 " JOIN tst_pass_result ON (tst_pass_result.active_fi = tst_active.active_id)" .
6654 " WHERE user_fi=%s" .
6655 " GROUP BY test_fi",
6656 [
'integer',
'integer'],
6660 while ($row =
$ilDB->fetchAssoc($result)) {
6661 $obj_id = self::_getObjectIDFromTestID($row[
"test_fi"]);
6662 $all[$obj_id] = (bool) $row[
"pass"];
6679 $this->activation_visibility = (bool) $a_value;
6694 $this->activation_limited = (bool) $a_value;
6698 ?
bool $is_activation_limited =
false,
6699 ?
int $activation_starting_time =
null,
6700 ?
int $activation_ending_time =
null,
6701 bool $activation_visibility =
false,
6703 if (!$this->ref_id) {
6708 $is_activation_limited ??=
false;
6710 if (!$is_activation_limited) {
6714 $item->setTimingStart($activation_starting_time);
6715 $item->setTimingEnd($activation_ending_time);
6716 $item->toggleVisible($activation_visibility);
6719 $item->update($this->ref_id);
6729 $page_id = $this->
getMainSettings()->getIntroductionSettings()->getIntroductionPageId();
6730 if ($page_id !==
null) {
6735 $page_object->setParentId($this->
getId());
6736 $new_page_id = $page_object->createPageWithNextId();
6738 ->withIntroductionPageId($new_page_id);
6742 return $new_page_id;
6747 $page_id = $this->
getMainSettings()->getFinishingSettings()->getConcludingRemarksPageId();
6748 if ($page_id !==
null) {
6753 $page_object->setParentId($this->
getId());
6754 $new_page_id = $page_object->createPageWithNextId();
6756 ->withConcludingRemarksPageId($new_page_id);
6760 return $new_page_id;
6765 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreEnabled();
6779 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreAnon();
6800 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreAchievedTS();
6808 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreScore();
6816 return $this->
getScoreSettings()->getGamificationSettings()->getHighscorePercentage();
6824 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreWTime();
6832 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreOwnTable();
6840 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreTopTable();
6849 return $this->
getScoreSettings()->getGamificationSettings()->getHighscoreTopNum();
6854 return $this->
getScoreSettings()->getGamificationSettings()->getHighScoreMode();
6859 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getInstantFeedbackSpecificEnabled();
6864 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getAutosaveEnabled();
6869 return $this->
getScoreSettings()->getResultSummarySettings()->getPassDeletionAllowed();
6874 return $this->
getMainSettings()->getFinishingSettings()->getShowAnswerOverview();
6879 $this->activation_starting_time = $starting_time;
6884 $this->activation_ending_time = $ending_time;
6906 $result = $this->db->queryF(
6907 "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",
6911 while ($row = $this->db->fetchAssoc($result)) {
6912 $times[$row[
'active_fi']] = $row[
'started'];
6920 $result = $this->db->queryF(
6921 "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",
6925 while ($row = $this->db->fetchAssoc($result)) {
6926 $times[$row[
'active_fi']] = $row[
'additionaltime'];
6933 if ($active_id === 0) {
6936 return $this->participant_repository
6937 ->getParticipantByActiveId($this->
getTestId(), $active_id)
6938 ?->getExtraTime() ?? 0;
6944 SELECT MAX(tst_pass_result.pass) + 1 max_res 6945 FROM tst_pass_result 6946 INNER JOIN tst_active ON tst_active.active_id = tst_pass_result.active_fi 6947 WHERE test_fi = ' . $this->db->quote($this->
getTestId(),
'integer') .
' 6949 $res = $this->db->query($query);
6951 return (
int)
$data[
'max_res'];
6957 $ilDB = $DIC[
'ilDB'];
6959 $exam_id_query =
'SELECT exam_id FROM tst_pass_result WHERE active_fi = %s AND pass = %s';
6960 $exam_id_result =
$ilDB->queryF($exam_id_query, [
'integer',
'integer' ], [ $active_id, $pass ]);
6961 if (
$ilDB->numRows($exam_id_result) == 1) {
6962 $exam_id_row =
$ilDB->fetchAssoc($exam_id_result);
6964 if ($exam_id_row[
'exam_id'] !=
null) {
6965 return $exam_id_row[
'exam_id'];
6979 if ($test_obj_id ===
null) {
6980 $obj_id = self::_getObjectIDFromActiveID($active_id);
6982 $obj_id = $test_obj_id;
6985 $examId =
'I' . $inst_id .
'_T' . $obj_id .
'_A' . $active_id .
'_P' . $pass;
6992 return $this->
getMainSettings()->getTestBehaviourSettings()->getExamIdInTestAttemptEnabled();
6997 return $this->
getScoreSettings()->getResultDetailsSettings()->getShowExamIdInTestResults();
7005 ->withQuestionSetType($question_set_type)
7011 return $this->
getMainSettings()->getGeneralSettings()->getQuestionSetType();
7036 switch ($questionSetType) {
7038 return $lng->
txt(
'tst_question_set_type_fixed');
7041 return $lng->
txt(
'tst_question_set_type_random');
7044 throw new ilTestException(
'invalid question set type value given: ' . $questionSetType);
7059 $scoring->setPreserveManualScores($preserve_manscoring);
7060 $scoring->recalculateSolutions();
7066 $ilDB = $DIC[
'ilDB'];
7071 INNER JOIN tst_tests 7072 ON test_id = test_fi 7076 $res =
$ilDB->queryF($query, [
'integer'], [$userId]);
7080 while ($row =
$ilDB->fetchAssoc(
$res)) {
7081 $objIds[] = (
int) $row[
'obj_fi'];
7089 return $this->
getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled();
7105 if (!$this->
getMainSettings()->getAdditionalSettings()->getSkillsServiceEnabled()) {
7109 if (!self::isSkillManagementGloballyActivated()) {
7120 if (self::$isSkillManagementGloballyActivated ===
null) {
7123 self::$isSkillManagementGloballyActivated = $skmgSet->isActivated();
7126 return self::$isSkillManagementGloballyActivated;
7131 return $this->
getScoreSettings()->getResultSummarySettings()->getShowGradingStatusEnabled();
7136 return $this->
getScoreSettings()->getResultSummarySettings()->getShowGradingMarkEnabled();
7141 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnNextQuestionEnabled();
7146 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getLockAnswerOnInstantFeedbackEnabled();
7151 return $this->
getMainSettings()->getQuestionBehaviourSettings()->getForceInstantFeedbackOnNextQuestion();
7158 $ilDB = $DIC[
'ilDB'];
7159 $ilUser = $DIC[
'ilUser'];
7163 $active_id = $test_obj->getActiveIdOfUser($user_id);
7168 $test_session_factory->reset();
7170 $test_sequence_factory =
new ilTestSequenceFactory($test_obj,
$ilDB, TestDIC::dic()[
'question.general_properties.repository']);
7172 $test_session = $test_session_factory->getSession($active_id);
7173 $test_sequence = $test_sequence_factory->getSequenceByActiveIdAndPass($active_id, $test_session->getPass());
7182 SELECT COUNT(test_question_id) cnt 7183 FROM tst_test_question 7188 $questRes = $this->db->queryF($query, [
'integer'], [$this->
getTestId()]);
7190 $row = $this->db->fetchAssoc($questRes);
7191 $questCount = $row[
'cnt'];
7197 INNER JOIN tst_sequence tseq 7198 ON tseq.active_fi = tac.active_id 7199 WHERE tac.test_fi = %s 7202 $partRes = $this->db->queryF(
7208 while ($row = $this->db->fetchAssoc($partRes)) {
7209 $sequence = @unserialize($row[
'sequence']);
7215 $sequence = array_filter($sequence,
function ($value) use ($questCount) {
7216 return $value <= $questCount;
7219 $num_seq = count($sequence);
7220 if ($questCount > $num_seq) {
7221 $diff = $questCount - $num_seq;
7222 for ($i = 1; $i <= $diff; $i++) {
7223 $sequence[$num_seq + $i - 1] = $num_seq + $i;
7227 $new_sequence = serialize($sequence);
7229 $this->db->update(
'tst_sequence', [
7230 'sequence' => [
'clob', $new_sequence]
7232 'active_fi' => [
'integer', $row[
'active_fi']],
7233 'pass' => [
'integer', $row[
'pass']]
7237 $new_sequence = serialize($questCount > 0 ? range(1, $questCount) : []);
7242 INNER JOIN tst_sequence tseq 7243 ON tseq.active_fi = tac.active_id 7244 WHERE tac.test_fi = %s 7247 $part_rest = $this->db->queryF(
7253 while ($row = $this->db->fetchAssoc($part_rest)) {
7254 $this->db->update(
'tst_sequence', [
7255 'sequence' => [
'clob', $new_sequence]
7257 'active_fi' => [
'integer', $row[
'active_fi']],
7258 'pass' => [
'integer', $row[
'pass']]
7279 return $this->global_settings_repo->getGlobalSettings();
7284 if (!$this->main_settings) {
7293 if (!$this->main_settings_repo) {
7301 if (!$this->score_settings) {
7310 if (!$this->score_settings_repo) {
7317 bool $old_online_status,
7318 bool $new_online_status
7320 if (!$old_online_status && $new_online_status) {
7322 $newsItem->setContext($this->
getId(),
'tst');
7324 $newsItem->setTitle(
'new_test_online');
7325 $newsItem->setContentIsLangVar(
true);
7326 $newsItem->setContent(
'');
7327 $newsItem->setUserId($this->
user->getId());
7329 $newsItem->create();
7333 if ($old_online_status && !$new_online_status) {
7339 if (!$new_online_status && $newsId > 0) {
7341 $newsItem->setTitle(
'new_test_online');
7342 $newsItem->setContentIsLangVar(
true);
7343 $newsItem->setContent(
'');
7344 $newsItem->update();
7355 $query =
'SELECT question_set_type FROM tst_tests WHERE obj_fi = %s';
7357 $res = $DIC[
'ilDB']->queryF($query, [
'integer'], [$obj_id]);
7359 $question_set_type =
null;
7361 while ($row = $DIC[
'ilDB']->fetchAssoc(
$res)) {
7362 $question_set_type = $row[
'question_set_type'];
7365 return $question_set_type === self::QUESTION_SET_TYPE_RANDOM;
7370 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)
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...
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.
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()
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)
Properties $object_properties
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()
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
static createDirectory(string $a_dir, int $a_mod=0755)
create directory
ilTestEditPageGUI: ilPageEditorGUI, ilEditClipboardGUI, ilMDEditorGUI ilTestEditPageGUI: ilPublicUse...
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.
withConcludingRemarksPageId(?int $concluding_remarks_page_id)
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...
getAnonOnlyParticipantIds()
return int[]
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...
getTestResult(int $active_id, ?int $attempt=null, bool $ordered_sequence=false, bool $consider_hidden_questions=true, bool $consider_optional_questions=true)
Calculates the results of a test for a given user and returns an array with all test results...
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()
Repository $test_result_repository
static insertInstIntoID(string $a_value)
inserts installation id into ILIAS id
getWorkingTimeOfParticipantForPass(int $active_id, int $pass)
11, will be removed in 12, use TestResultManager::fetchWorkingTime instead
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)
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.
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.